mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge fx-team to m-c a=merge
This commit is contained in:
commit
2e408ff3b5
@ -451,7 +451,7 @@ TestRunner.prototype = {
|
||||
function tiredOfWaiting() {
|
||||
self._logTestFailed("timed out");
|
||||
if ("testMessage" in self.console) {
|
||||
self.console.testMessage(false, false, self.test.name, "Timed out");
|
||||
self.console.testMessage(false, false, self.test.name, "Test timed out");
|
||||
}
|
||||
else {
|
||||
self.console.error("fail:", "Timed out")
|
||||
|
@ -73,7 +73,8 @@ let panelContract = contract(merge({
|
||||
}),
|
||||
contentStyleFile: merge(Object.create(loaderContract.rules.contentScriptFile), {
|
||||
msg: 'The `contentStyleFile` option must be a local URL or an array of URLs'
|
||||
})
|
||||
}),
|
||||
contextMenu: boolean
|
||||
}, displayContract.rules, loaderContract.rules));
|
||||
|
||||
|
||||
@ -134,6 +135,7 @@ const Panel = Class({
|
||||
defaultHeight: 240,
|
||||
focus: true,
|
||||
position: Object.freeze({}),
|
||||
contextMenu: false
|
||||
}, panelContract(options));
|
||||
models.set(this, model);
|
||||
|
||||
@ -151,6 +153,9 @@ const Panel = Class({
|
||||
|
||||
// Load panel content.
|
||||
domPanel.setURL(view, model.contentURL);
|
||||
|
||||
// Allow context menu
|
||||
domPanel.allowContextMenu(view, model.contextMenu);
|
||||
|
||||
setupAutoHide(this);
|
||||
|
||||
@ -188,7 +193,15 @@ const Panel = Class({
|
||||
|
||||
/* Public API: Panel.position */
|
||||
get position() modelFor(this).position,
|
||||
|
||||
|
||||
/* Public API: Panel.contextMenu */
|
||||
get contextMenu() modelFor(this).contextMenu,
|
||||
set contextMenu(allow) {
|
||||
let model = modelFor(this);
|
||||
model.contextMenu = panelContract({ contextMenu: allow }).contextMenu;
|
||||
domPanel.allowContextMenu(viewFor(this), model.contextMenu);
|
||||
},
|
||||
|
||||
get contentURL() modelFor(this).contentURL,
|
||||
set contentURL(value) {
|
||||
let model = modelFor(this);
|
||||
@ -226,7 +239,8 @@ const Panel = Class({
|
||||
height: model.height,
|
||||
defaultWidth: model.defaultWidth,
|
||||
defaultHeight: model.defaultHeight,
|
||||
focus: model.focus
|
||||
focus: model.focus,
|
||||
contextMenu: model.contextMenu
|
||||
}, displayContract(options));
|
||||
|
||||
if (!isDisposed(this))
|
||||
|
@ -211,7 +211,7 @@ function show(panel, options, anchor) {
|
||||
// Prevent the panel from getting focus when showing up
|
||||
// if focus is set to false
|
||||
panel.setAttribute("noautofocus", !options.focus);
|
||||
|
||||
|
||||
let window = anchor && getOwnerBrowserWindow(anchor);
|
||||
let { document } = window ? window : getMostRecentBrowserWindow();
|
||||
attach(panel, document);
|
||||
@ -404,3 +404,13 @@ exports.getContentDocument = getContentDocument;
|
||||
|
||||
function setURL(panel, url) getContentFrame(panel).setAttribute("src", url)
|
||||
exports.setURL = setURL;
|
||||
|
||||
function allowContextMenu(panel, allow) {
|
||||
if(allow) {
|
||||
panel.setAttribute("context", "contentAreaContextMenu");
|
||||
}
|
||||
else {
|
||||
panel.removeAttribute("context");
|
||||
}
|
||||
}
|
||||
exports.allowContextMenu = allowContextMenu;
|
||||
|
@ -18,6 +18,7 @@ const system = require("../system");
|
||||
const memory = require('../deprecated/memory');
|
||||
const { gc: gcPromise } = require('./memory');
|
||||
const { defer } = require('../core/promise');
|
||||
const { extend } = require('../core/heritage');
|
||||
|
||||
// Trick manifest builder to make it think we need these modules ?
|
||||
const unit = require("../deprecated/unit-test");
|
||||
@ -453,7 +454,7 @@ var consoleListener = {
|
||||
};
|
||||
|
||||
function TestRunnerConsole(base, options) {
|
||||
this.__proto__ = {
|
||||
let proto = extend(base, {
|
||||
errorsLogged: 0,
|
||||
warn: function warn() {
|
||||
this.errorsLogged++;
|
||||
@ -470,8 +471,8 @@ function TestRunnerConsole(base, options) {
|
||||
if (first == "pass:")
|
||||
print(".");
|
||||
},
|
||||
__proto__: base
|
||||
};
|
||||
});
|
||||
return Object.create(proto);
|
||||
}
|
||||
|
||||
function stringify(arg) {
|
||||
|
@ -19,7 +19,7 @@ function CustomLoader(module, globals, packaging, overrides={}) {
|
||||
options = override(options, {
|
||||
id: overrides.id || options.id,
|
||||
globals: override(defaultGlobals, globals || {}),
|
||||
modules: override(options.modules || {}, {
|
||||
modules: override(override(options.modules || {}, overrides.modules || {}), {
|
||||
'sdk/addon/window': addonWindow
|
||||
})
|
||||
});
|
||||
@ -31,6 +31,8 @@ function CustomLoader(module, globals, packaging, overrides={}) {
|
||||
require: Require(loader, module),
|
||||
sandbox: function(id) {
|
||||
let requirement = loader.resolve(id, module.id);
|
||||
if (!requirement)
|
||||
requirement = id;
|
||||
let uri = resolveURI(requirement, loader.mapping);
|
||||
return loader.sandboxes[uri];
|
||||
},
|
||||
@ -73,13 +75,13 @@ exports.LoaderWithHookedConsole = function (module, callback) {
|
||||
return {
|
||||
loader: CustomLoader(module, {
|
||||
console: new HookedPlainTextConsole(hook, null, null)
|
||||
}, override(require("@loader/options"), {
|
||||
}, null, {
|
||||
modules: {
|
||||
'sdk/console/plain-text': {
|
||||
PlainTextConsole: HookedPlainTextConsole.bind(null, hook)
|
||||
}
|
||||
}
|
||||
})),
|
||||
}),
|
||||
messages: messages
|
||||
};
|
||||
}
|
||||
@ -112,11 +114,11 @@ exports.LoaderWithFilteredConsole = function (module, callback) {
|
||||
|
||||
return CustomLoader(module, {
|
||||
console: new HookedPlainTextConsole(hook, null, null)
|
||||
}, override(require("@loader/options"), {
|
||||
}, null, {
|
||||
modules: {
|
||||
'sdk/console/plain-text': {
|
||||
PlainTextConsole: HookedPlainTextConsole.bind(null, hook)
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
@ -714,7 +714,8 @@ const Loader = iced(function Loader(options) {
|
||||
console: console
|
||||
},
|
||||
resolve: options.isNative ?
|
||||
exports.nodeResolve :
|
||||
// Make the returned resolve function have the same signature
|
||||
(id, requirer) => exports.nodeResolve(id, requirer, { rootURI: rootURI }) :
|
||||
exports.resolve,
|
||||
sharedGlobalBlacklist: ["sdk/indexed-db"]
|
||||
}, options);
|
||||
|
@ -234,6 +234,11 @@ parser_groups = (
|
||||
help="JSON file to overload package.json properties",
|
||||
default=None,
|
||||
cmds=['xpi'])),
|
||||
(("", "--abort-on-missing-module",), dict(dest="abort_on_missing",
|
||||
help="Abort if required module is missing",
|
||||
action="store_true",
|
||||
default=False,
|
||||
cmds=['test', 'run', 'xpi', 'testpkgs'])),
|
||||
]
|
||||
),
|
||||
|
||||
@ -651,7 +656,8 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
# a Mozilla application (which includes running tests).
|
||||
|
||||
use_main = False
|
||||
inherited_options = ['verbose', 'enable_e10s', 'parseable', 'check_memory']
|
||||
inherited_options = ['verbose', 'enable_e10s', 'parseable', 'check_memory',
|
||||
'abort_on_missing']
|
||||
enforce_timeouts = False
|
||||
|
||||
if command == "xpi":
|
||||
@ -746,9 +752,9 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
if ":" in options.filter:
|
||||
test_filter_re = options.filter.split(":")[0]
|
||||
try:
|
||||
manifest = build_manifest(target_cfg, pkg_cfg, deps,
|
||||
scan_tests, test_filter_re,
|
||||
loader_modules)
|
||||
manifest = build_manifest(target_cfg, pkg_cfg, deps, scan_tests,
|
||||
test_filter_re, loader_modules,
|
||||
abort_on_missing=options.abort_on_missing)
|
||||
except ModuleNotFoundError, e:
|
||||
print str(e)
|
||||
sys.exit(1)
|
||||
@ -788,6 +794,10 @@ def run(arguments=sys.argv[1:], target_cfg=None, pkg_cfg=None,
|
||||
options.force_use_bundled_sdk = False
|
||||
options.overload_modules = True
|
||||
|
||||
if options.pkgdir == env_root:
|
||||
options.bundle_sdk = True
|
||||
options.overload_modules = True
|
||||
|
||||
extra_environment = {}
|
||||
if command == "test":
|
||||
# This should be contained in the test runner package.
|
||||
|
@ -181,7 +181,7 @@ class ModuleInfo:
|
||||
|
||||
class ManifestBuilder:
|
||||
def __init__(self, target_cfg, pkg_cfg, deps, extra_modules,
|
||||
stderr=sys.stderr):
|
||||
stderr=sys.stderr, abort_on_missing=False):
|
||||
self.manifest = {} # maps (package,section,module) to ManifestEntry
|
||||
self.target_cfg = target_cfg # the entry point
|
||||
self.pkg_cfg = pkg_cfg # all known packages
|
||||
@ -193,6 +193,7 @@ class ManifestBuilder:
|
||||
self.datamaps = {} # maps package name to DataMap instance
|
||||
self.files = [] # maps manifest index to (absfn,absfn) js/docs pair
|
||||
self.test_modules = [] # for runtime
|
||||
self.abort_on_missing = abort_on_missing # cfx eol
|
||||
|
||||
def build(self, scan_tests, test_filter_re):
|
||||
"""
|
||||
@ -416,6 +417,12 @@ class ManifestBuilder:
|
||||
# test-securable-module.js, and the modules/red.js
|
||||
# that it imports, both do that intentionally
|
||||
continue
|
||||
if not self.abort_on_missing:
|
||||
# print a warning, but tolerate missing modules
|
||||
# unless cfx --abort-on-missing-module flag was set
|
||||
print >>self.stderr, "Warning: missing module: %s" % reqname
|
||||
me.add_requirement(reqname, reqname)
|
||||
continue
|
||||
lineno = locations.get(reqname) # None means define()
|
||||
if lineno is None:
|
||||
reqtype = "define"
|
||||
@ -633,7 +640,7 @@ class ManifestBuilder:
|
||||
return None
|
||||
|
||||
def build_manifest(target_cfg, pkg_cfg, deps, scan_tests,
|
||||
test_filter_re=None, extra_modules=[]):
|
||||
test_filter_re=None, extra_modules=[], abort_on_missing=False):
|
||||
"""
|
||||
Perform recursive dependency analysis starting from entry_point,
|
||||
building up a manifest of modules that need to be included in the XPI.
|
||||
@ -659,7 +666,8 @@ def build_manifest(target_cfg, pkg_cfg, deps, scan_tests,
|
||||
code which does, so it knows what to copy into the XPI.
|
||||
"""
|
||||
|
||||
mxt = ManifestBuilder(target_cfg, pkg_cfg, deps, extra_modules)
|
||||
mxt = ManifestBuilder(target_cfg, pkg_cfg, deps, extra_modules,
|
||||
abort_on_missing=abort_on_missing)
|
||||
mxt.build(scan_tests, test_filter_re)
|
||||
return mxt
|
||||
|
||||
|
@ -48,6 +48,7 @@ class Basic(unittest.TestCase):
|
||||
def assertReqIs(modname, reqname, path):
|
||||
reqs = m["one/%s" % modname]["requirements"]
|
||||
self.failUnlessEqual(reqs[reqname], path)
|
||||
|
||||
assertReqIs("main", "sdk/panel", "sdk/panel")
|
||||
assertReqIs("main", "two.js", "one/two")
|
||||
assertReqIs("main", "./two", "one/two")
|
||||
@ -57,11 +58,26 @@ class Basic(unittest.TestCase):
|
||||
assertReqIs("subdir/three", "../main", "one/main")
|
||||
|
||||
target_cfg.dependencies = []
|
||||
|
||||
try:
|
||||
# this should now work, as we ignore missing modules by default
|
||||
m = manifest.build_manifest(target_cfg, pkg_cfg, deps, scan_tests=False)
|
||||
m = m.get_harness_options_manifest(False)
|
||||
|
||||
assertReqIs("main", "sdk/panel", "sdk/panel")
|
||||
# note that with "addon-sdk" dependency present,
|
||||
# "sdk/tabs.js" mapped to "sdk/tabs", but without,
|
||||
# we just get the default (identity) mapping
|
||||
assertReqIs("main", "sdk/tabs.js", "sdk/tabs.js")
|
||||
except Exception, e:
|
||||
self.fail("Must not throw from build_manifest() if modules are missing")
|
||||
|
||||
# now, because .dependencies *is* provided, we won't search 'deps',
|
||||
# so we'll get a link error
|
||||
# and stop_on_missing is True, we'll get a link error
|
||||
self.assertRaises(manifest.ModuleNotFoundError,
|
||||
manifest.build_manifest,
|
||||
target_cfg, pkg_cfg, deps, scan_tests=False)
|
||||
target_cfg, pkg_cfg, deps, scan_tests=False,
|
||||
abort_on_missing=True)
|
||||
|
||||
def test_main_in_deps(self):
|
||||
target_cfg = self.get_pkg("three")
|
||||
|
@ -4,10 +4,16 @@
|
||||
'use strict';
|
||||
|
||||
const { merge } = require('sdk/util/object');
|
||||
const { get } = require('sdk/preferences/service');
|
||||
|
||||
merge(module.exports, require('./test-tab'));
|
||||
merge(module.exports, require('./test-tab-events'));
|
||||
merge(module.exports, require('./test-tab-observer'));
|
||||
merge(module.exports, require('./test-tab-utils'));
|
||||
|
||||
// e10s tests should not ride the train to aurora
|
||||
if (get('app.update.channel') !== 'nightly') {
|
||||
module.exports = {};
|
||||
}
|
||||
|
||||
require('sdk/test/runner').runTestsFromModule(module);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
var options = require("@loader/options");
|
||||
|
||||
@ -43,4 +43,4 @@ exports.testPackaging = function(assert) {
|
||||
"private browsing metadata should be be frozen");
|
||||
};
|
||||
|
||||
require('sdk/test').run(exports);
|
||||
require("sdk/test/runner").runTestsFromModule(module);
|
4
addon-sdk/source/test/addons/packaging/package.json
Normal file
4
addon-sdk/source/test/addons/packaging/package.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"id": "test-packaging",
|
||||
"description": "Add-on development made easy."
|
||||
}
|
@ -17,4 +17,8 @@ exports["test self.data.load"] = assert => {
|
||||
"relative paths work");
|
||||
};
|
||||
|
||||
exports["test self.id"] = assert => {
|
||||
assert.equal(self.id, "test-self@jetpack", "self.id should be correct.");
|
||||
};
|
||||
|
||||
require("sdk/test/runner").runTestsFromModule(module);
|
||||
|
@ -6,6 +6,55 @@
|
||||
|
||||
const { on, once, off, emit, count } = require("sdk/event/core");
|
||||
|
||||
const { setImmediate, setTimeout } = require("sdk/timers");
|
||||
const { defer } = require("sdk/core/promise");
|
||||
|
||||
/**
|
||||
* Utility function that returns a promise once the specified event's `type`
|
||||
* is emitted on the given `target`, or the delay specified is passed.
|
||||
*
|
||||
* @param {Object|Number} [target]
|
||||
* The delay to wait, or the object that receives the event.
|
||||
* If not given, the function returns a promise that will be resolved
|
||||
* as soon as possible.
|
||||
* @param {String} [type]
|
||||
* A string representing the event type to waiting for.
|
||||
* @param {Boolean} [capture]
|
||||
* If `true`, `capture` indicates that the user wishes to initiate capture.
|
||||
*
|
||||
* @returns {Promise}
|
||||
* A promise resolved once the delay given is passed, or the object
|
||||
* receives the event specified
|
||||
*/
|
||||
const wait = (target, type, capture) => {
|
||||
let { promise, resolve, reject } = defer();
|
||||
|
||||
if (!arguments.length) {
|
||||
setImmediate(resolve);
|
||||
}
|
||||
else if (typeof(target) === "number") {
|
||||
setTimeout(resolve, target);
|
||||
}
|
||||
else if (typeof(target.once) === "function") {
|
||||
target.once(type, resolve);
|
||||
}
|
||||
else if (typeof(target.addEventListener) === "function") {
|
||||
target.addEventListener(type, function listener(...args) {
|
||||
this.removeEventListener(type, listener, capture);
|
||||
resolve(...args);
|
||||
}, capture);
|
||||
}
|
||||
else if (typeof(target) === "object" && target !== null) {
|
||||
once(target, type, resolve);
|
||||
}
|
||||
else {
|
||||
reject('Invalid target given.');
|
||||
}
|
||||
|
||||
return promise;
|
||||
};
|
||||
exports.wait = wait;
|
||||
|
||||
function scenario(setup) {
|
||||
return function(unit) {
|
||||
return function(assert) {
|
||||
@ -56,4 +105,4 @@ exports.FIFO = scenario(function(target, expected, actual) {
|
||||
return expected.reduce(function(result, value) {
|
||||
return result.concat(value + "#1", value + "#2", value + "#3");
|
||||
}, []);
|
||||
});
|
||||
});
|
@ -136,6 +136,7 @@ exports["test Create Proxy Test With Events"] = createProxyTest("", function (he
|
||||
|
||||
});
|
||||
|
||||
/* Disabled due to bug 1038432
|
||||
// Bug 714778: There was some issue around `toString` functions
|
||||
// that ended up being shared between content scripts
|
||||
exports["test Shared To String Proxies"] = createProxyTest("", function(helper) {
|
||||
@ -165,7 +166,7 @@ exports["test Shared To String Proxies"] = createProxyTest("", function(helper)
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
// Ensure that postMessage is working correctly across documents with an iframe
|
||||
let html = '<iframe id="iframe" name="test" src="data:text/html;charset=utf-8," />';
|
||||
|
@ -12,7 +12,7 @@ module.metadata = {
|
||||
const { Cc, Ci } = require("chrome");
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const { LoaderWithHookedConsole } = require("sdk/test/loader");
|
||||
const timer = require("sdk/timers");
|
||||
const { setTimeout } = require("sdk/timers");
|
||||
const self = require('sdk/self');
|
||||
const { open, close, focus, ready } = require('sdk/window/helpers');
|
||||
const { isPrivate } = require('sdk/private-browsing');
|
||||
@ -22,6 +22,8 @@ const { getMostRecentBrowserWindow } = require('sdk/window/utils');
|
||||
const { getWindow } = require('sdk/panel/window');
|
||||
const { pb } = require('./private-browsing/helper');
|
||||
const { URL } = require('sdk/url');
|
||||
const { wait } = require('./event/helpers');
|
||||
|
||||
const fixtures = require('./fixtures')
|
||||
|
||||
const SVG_URL = fixtures.url('mofo_logo.SVG');
|
||||
@ -544,7 +546,7 @@ function makeEventOrderTest(options) {
|
||||
panel.on(event, function() {
|
||||
assert.equal(event, expectedEvents.shift());
|
||||
if (cb)
|
||||
timer.setTimeout(cb, 1);
|
||||
setTimeout(cb, 1);
|
||||
});
|
||||
return {then: expect};
|
||||
}
|
||||
@ -1056,6 +1058,136 @@ exports['test panel CSS list'] = function(assert, done) {
|
||||
panel.show();
|
||||
};
|
||||
|
||||
exports['test panel contextmenu validation'] = function(assert) {
|
||||
const loader = Loader(module);
|
||||
const { Panel } = loader.require('sdk/panel');
|
||||
|
||||
let panel = Panel({});
|
||||
|
||||
assert.equal(panel.contextMenu, false,
|
||||
'contextMenu option is `false` by default');
|
||||
|
||||
panel.destroy();
|
||||
|
||||
panel = Panel({
|
||||
contextMenu: false
|
||||
});
|
||||
|
||||
assert.equal(panel.contextMenu, false,
|
||||
'contextMenu option is `false`');
|
||||
|
||||
panel.contextMenu = true;
|
||||
|
||||
assert.equal(panel.contextMenu, true,
|
||||
'contextMenu option accepts boolean values');
|
||||
|
||||
panel.destroy();
|
||||
|
||||
panel = Panel({
|
||||
contextMenu: true
|
||||
});
|
||||
|
||||
assert.equal(panel.contextMenu, true,
|
||||
'contextMenu option is `true`');
|
||||
|
||||
panel.contextMenu = false;
|
||||
|
||||
assert.equal(panel.contextMenu, false,
|
||||
'contextMenu option accepts boolean values');
|
||||
|
||||
assert.throws(() =>
|
||||
Panel({contextMenu: 1}),
|
||||
/The option "contextMenu" must be one of the following types: boolean, undefined, null/,
|
||||
'contextMenu only accepts boolean or nil values');
|
||||
|
||||
panel = Panel();
|
||||
|
||||
assert.throws(() =>
|
||||
panel.contextMenu = 1,
|
||||
/The option "contextMenu" must be one of the following types: boolean, undefined, null/,
|
||||
'contextMenu only accepts boolean or nil values');
|
||||
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test panel contextmenu enabled'] = function*(assert) {
|
||||
const loader = Loader(module);
|
||||
const { Panel } = loader.require('sdk/panel');
|
||||
const { getActiveView } = loader.require('sdk/view/core');
|
||||
const { getContentDocument } = loader.require('sdk/panel/utils');
|
||||
|
||||
let contextmenu = getMostRecentBrowserWindow().
|
||||
document.getElementById("contentAreaContextMenu");
|
||||
|
||||
let panel = Panel({contextMenu: true});
|
||||
|
||||
panel.show();
|
||||
|
||||
yield wait(panel, 'show');
|
||||
|
||||
let view = getActiveView(panel);
|
||||
let window = getContentDocument(view).defaultView;
|
||||
|
||||
let { sendMouseEvent } = window.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
yield ready(window);
|
||||
|
||||
assert.equal(contextmenu.state, 'closed',
|
||||
'contextmenu must be closed');
|
||||
|
||||
sendMouseEvent('contextmenu', 20, 20, 2, 1, 0);
|
||||
|
||||
yield wait(contextmenu, 'popupshown');
|
||||
|
||||
assert.equal(contextmenu.state, 'open',
|
||||
'contextmenu is opened');
|
||||
|
||||
contextmenu.hidePopup();
|
||||
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
exports['test panel contextmenu disabled'] = function*(assert) {
|
||||
const loader = Loader(module);
|
||||
const { Panel } = loader.require('sdk/panel');
|
||||
const { getActiveView } = loader.require('sdk/view/core');
|
||||
const { getContentDocument } = loader.require('sdk/panel/utils');
|
||||
|
||||
let contextmenu = getMostRecentBrowserWindow().
|
||||
document.getElementById("contentAreaContextMenu");
|
||||
let listener = () => assert.fail('popupshown should never be called');
|
||||
|
||||
let panel = Panel();
|
||||
|
||||
panel.show();
|
||||
|
||||
yield wait(panel, 'show');
|
||||
|
||||
let view = getActiveView(panel);
|
||||
let window = getContentDocument(view).defaultView;
|
||||
|
||||
let { sendMouseEvent } = window.QueryInterface(Ci.nsIInterfaceRequestor).
|
||||
getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
yield ready(window);
|
||||
|
||||
assert.equal(contextmenu.state, 'closed',
|
||||
'contextmenu must be closed');
|
||||
|
||||
sendMouseEvent('contextmenu', 20, 20, 2, 1, 0);
|
||||
|
||||
contextmenu.addEventListener('popupshown', listener);
|
||||
|
||||
yield wait(1000);
|
||||
|
||||
contextmenu.removeEventListener('popupshown', listener);
|
||||
|
||||
assert.equal(contextmenu.state, 'closed',
|
||||
'contextmenu was never open');
|
||||
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
if (isWindowPBSupported) {
|
||||
exports.testGetWindow = function(assert, done) {
|
||||
|
@ -234,6 +234,8 @@ exports.testConsoleInnerID = function(assert) {
|
||||
let Console = require("sdk/console/plain-text").PlainTextConsole;
|
||||
let { log, info, warn, error, debug, exception, trace } = new Console(function() {}, "test ID");
|
||||
|
||||
prefs.set(SDK_LOG_LEVEL_PREF, "all");
|
||||
|
||||
let messages = [];
|
||||
function onMessage({ subject }) {
|
||||
let message = subject.wrappedJSObject;
|
||||
@ -253,6 +255,8 @@ exports.testConsoleInnerID = function(assert) {
|
||||
assert.deepEqual(messages[2], { msg: "Test error", type: "error", innerID: "test ID" }, "Should see the right event");
|
||||
|
||||
system.off("console-api-log-event", onMessage);
|
||||
|
||||
restorePrefs();
|
||||
};
|
||||
|
||||
function restorePrefs() {
|
||||
|
@ -51,9 +51,13 @@ function checkError (assert, name, e) {
|
||||
// we'd also like to assert that the right filename
|
||||
// and linenumber is in the stacktrace
|
||||
let tb = traceback.fromException(e);
|
||||
// Get the second to last frame, as the last frame is inside
|
||||
// toolkit/loader
|
||||
let lastFrame = tb[tb.length-2];
|
||||
|
||||
// The last frame may be inside a loader
|
||||
let lastFrame = tb[tb.length - 1];
|
||||
if (lastFrame.fileName.indexOf("toolkit/loader.js") !== -1 ||
|
||||
lastFrame.fileName.indexOf("sdk/loader/cuddlefish.js") !== -1)
|
||||
lastFrame = tb[tb.length - 2];
|
||||
|
||||
assert.ok(lastFrame.fileName.indexOf("test-require.js") !== -1,
|
||||
'Filename found in stacktrace');
|
||||
assert.equal(lastFrame.lineNumber, REQUIRE_LINE_NO,
|
||||
|
@ -40,27 +40,6 @@ exports.testSelf = function(assert) {
|
||||
'usePrivateBrowsing property is false by default');
|
||||
};
|
||||
|
||||
exports.testSelfID = function(assert, done) {
|
||||
var self = require("sdk/self");
|
||||
// We can't assert anything about the ID inside the unit test right now,
|
||||
// because the ID we get depends upon how the test was invoked. The idea
|
||||
// is that it is supposed to come from the main top-level package's
|
||||
// package.json file, from the "id" key.
|
||||
assert.equal(typeof(self.id), "string", "self.id is a string");
|
||||
assert.ok(self.id.length > 0);
|
||||
|
||||
AddonManager.getAddonByID(self.id, function(addon) {
|
||||
if (!addon) {
|
||||
assert.fail("did not find addon with self.id");
|
||||
}
|
||||
else {
|
||||
assert.pass("found addon with self.id");
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
exports.testSelfHandlesLackingLoaderOptions = function (assert) {
|
||||
let root = module.uri.substr(0, module.uri.lastIndexOf('/'));
|
||||
let uri = root + '/fixtures/loader/self/';
|
||||
|
@ -22,10 +22,12 @@
|
||||
#include "VideoUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsIPrefService.h"
|
||||
#include "MediaTrackConstraints.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
using dom::ConstrainLongRange;
|
||||
|
||||
NS_IMPL_ISUPPORTS(MediaEngineTabVideoSource, nsIDOMEventListener, nsITimerCallback)
|
||||
|
||||
@ -38,13 +40,8 @@ nsresult
|
||||
MediaEngineTabVideoSource::StartRunnable::Run()
|
||||
{
|
||||
mVideoSource->Draw();
|
||||
nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(mVideoSource->mWindow);
|
||||
if (privateDOMWindow) {
|
||||
privateDOMWindow->GetChromeEventHandler()->AddEventListener(NS_LITERAL_STRING("MozAfterPaint"), mVideoSource, false);
|
||||
} else {
|
||||
mVideoSource->mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
mVideoSource->mTimer->InitWithCallback(mVideoSource, mVideoSource->mTimePerFrame, nsITimer:: TYPE_REPEATING_SLACK);
|
||||
}
|
||||
mVideoSource->mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
mVideoSource->mTimer->InitWithCallback(mVideoSource, mVideoSource->mTimePerFrame, nsITimer:: TYPE_REPEATING_SLACK);
|
||||
mVideoSource->mTabSource->NotifyStreamStart(mVideoSource->mWindow);
|
||||
return NS_OK;
|
||||
}
|
||||
@ -53,9 +50,6 @@ nsresult
|
||||
MediaEngineTabVideoSource::StopRunnable::Run()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> privateDOMWindow = do_QueryInterface(mVideoSource->mWindow);
|
||||
if (privateDOMWindow && privateDOMWindow->GetChromeEventHandler()) {
|
||||
privateDOMWindow->GetChromeEventHandler()->RemoveEventListener(NS_LITERAL_STRING("MozAfterPaint"), mVideoSource, false);
|
||||
}
|
||||
|
||||
if (mVideoSource->mTimer) {
|
||||
mVideoSource->mTimer->Cancel();
|
||||
@ -76,21 +70,14 @@ MediaEngineTabVideoSource::Notify(nsITimer*) {
|
||||
Draw();
|
||||
return NS_OK;
|
||||
}
|
||||
#define LOGTAG "TabVideo"
|
||||
|
||||
nsresult
|
||||
MediaEngineTabVideoSource::InitRunnable::Run()
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIPrefService> prefs = do_GetService("@mozilla.org/preferences-service;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
|
||||
if (!branch)
|
||||
return NS_OK;
|
||||
branch->GetIntPref("media.tabstreaming.width", &mVideoSource->mBufW);
|
||||
branch->GetIntPref("media.tabstreaming.height", &mVideoSource->mBufH);
|
||||
branch->GetIntPref("media.tabstreaming.time_per_frame", &mVideoSource->mTimePerFrame);
|
||||
mVideoSource->mData = (unsigned char*)malloc(mVideoSource->mBufW * mVideoSource->mBufH * 4);
|
||||
|
||||
nsresult rv;
|
||||
mVideoSource->mTabSource = do_GetService(NS_TABSOURCESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
@ -119,9 +106,41 @@ MediaEngineTabVideoSource::GetUUID(nsAString_internal& aUuid)
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaEngineTabVideoSource::Allocate(const VideoTrackConstraintsN&,
|
||||
const MediaEnginePrefs&)
|
||||
MediaEngineTabVideoSource::Allocate(const VideoTrackConstraintsN& aConstraints,
|
||||
const MediaEnginePrefs& aPrefs)
|
||||
{
|
||||
|
||||
ConstrainLongRange cWidth(aConstraints.mRequired.mWidth);
|
||||
ConstrainLongRange cHeight(aConstraints.mRequired.mHeight);
|
||||
|
||||
if (aConstraints.mAdvanced.WasPassed()) {
|
||||
const auto& advanced = aConstraints.mAdvanced.Value();
|
||||
for (uint32_t i = 0; i < advanced.Length(); i++) {
|
||||
if (cWidth.mMax >= advanced[i].mWidth.mMin && cWidth.mMin <= advanced[i].mWidth.mMax &&
|
||||
cHeight.mMax >= advanced[i].mHeight.mMin && cHeight.mMin <= advanced[i].mHeight.mMax) {
|
||||
cWidth.mMin = std::max(cWidth.mMin, advanced[i].mWidth.mMin);
|
||||
cHeight.mMin = std::max(cHeight.mMin, advanced[i].mHeight.mMin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mBufW = aPrefs.GetWidth(false);
|
||||
mBufH = aPrefs.GetHeight(false);
|
||||
|
||||
if (cWidth.mMin > mBufW) {
|
||||
mBufW = cWidth.mMin;
|
||||
} else if (cWidth.mMax < mBufW) {
|
||||
mBufW = cWidth.mMax;
|
||||
}
|
||||
|
||||
if (cHeight.mMin > mBufH) {
|
||||
mBufH = cHeight.mMin;
|
||||
} else if (cHeight.mMax < mBufH) {
|
||||
mBufH = cHeight.mMax;
|
||||
}
|
||||
|
||||
mTimePerFrame = aPrefs.mFPS ? 1000 / aPrefs.mFPS : aPrefs.mFPS;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -390,6 +390,10 @@
|
||||
android:authorities="@ANDROID_PACKAGE_NAME@.db.readinglist"
|
||||
android:permission="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER"/>
|
||||
|
||||
<provider android:name="org.mozilla.gecko.db.SearchHistoryProvider"
|
||||
android:authorities="@ANDROID_PACKAGE_NAME@.db.searchhistory"
|
||||
android:permission="@ANDROID_PACKAGE_NAME@.permissions.BROWSER_PROVIDER"/>
|
||||
|
||||
<service
|
||||
android:exported="false"
|
||||
android:name="org.mozilla.gecko.updater.UpdateService"
|
||||
|
@ -25,6 +25,7 @@ import org.mozilla.gecko.animation.PropertyAnimator;
|
||||
import org.mozilla.gecko.animation.ViewHelper;
|
||||
import org.mozilla.gecko.db.BrowserContract.Combined;
|
||||
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
|
||||
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
|
||||
import org.mozilla.gecko.db.BrowserDB;
|
||||
import org.mozilla.gecko.db.SuggestedSites;
|
||||
import org.mozilla.gecko.distribution.Distribution;
|
||||
@ -529,6 +530,7 @@ public class BrowserApp extends GeckoApp
|
||||
"Menu:Update",
|
||||
"Reader:Added",
|
||||
"Reader:FaviconRequest",
|
||||
"Search:Keyword",
|
||||
"Prompt:ShowTop",
|
||||
"Accounts:Exist");
|
||||
|
||||
@ -936,6 +938,7 @@ public class BrowserApp extends GeckoApp
|
||||
"Menu:Update",
|
||||
"Reader:Added",
|
||||
"Reader:FaviconRequest",
|
||||
"Search:Keyword",
|
||||
"Prompt:ShowTop",
|
||||
"Accounts:Exist");
|
||||
|
||||
@ -1383,6 +1386,8 @@ public class BrowserApp extends GeckoApp
|
||||
} else if (event.equals("Reader:FaviconRequest")) {
|
||||
final String url = message.getString("url");
|
||||
handleReaderFaviconRequest(url);
|
||||
} else if (event.equals("Search:Keyword")) {
|
||||
storeSearchQuery(message.getString("query"));
|
||||
} else if (event.equals("Prompt:ShowTop")) {
|
||||
// Bring this activity to front so the prompt is visible..
|
||||
Intent bringToFrontIntent = new Intent();
|
||||
@ -1806,6 +1811,27 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store search query in SearchHistoryProvider.
|
||||
*
|
||||
* @param query
|
||||
* a search query to store. We won't store empty queries.
|
||||
*/
|
||||
private void storeSearchQuery(String query) {
|
||||
if (TextUtils.isEmpty(query)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(SearchHistory.QUERY, query);
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
getContentResolver().insert(SearchHistory.CONTENT_URI, values);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void filterEditingMode(String searchTerm, AutocompleteHandler handler) {
|
||||
if (TextUtils.isEmpty(searchTerm)) {
|
||||
hideBrowserSearch();
|
||||
@ -2849,6 +2875,7 @@ public class BrowserApp extends GeckoApp
|
||||
@Override
|
||||
public void onSearch(SearchEngine engine, String text) {
|
||||
recordSearch(engine, "barsuggest");
|
||||
storeSearchQuery(text);
|
||||
openUrlAndStopEditing(text, engine.name);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout android:id="@+id/remote_tabs_setup_containing_layout"
|
||||
style="@style/TabsPanelFrame"
|
||||
style="@style/TabsPanelFrame.RemoteTabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<LinearLayout android:id="@+id/remote_tabs_verification_containing_layout"
|
||||
style="@style/TabsPanelFrame"
|
||||
style="@style/TabsPanelFrame.RemoteTabs"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
|
@ -64,8 +64,14 @@
|
||||
<!-- We set values in tablet portrait. -->
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelFrame.RemoteTabs">
|
||||
<item name="android:paddingLeft">0dp</item>
|
||||
<item name="android:paddingRight">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection" parent="TabsPanelSectionBase">
|
||||
<!-- To override the values-land style. -->
|
||||
<item name="android:layout_marginLeft">20dp</item>
|
||||
<item name="android:layout_marginRight">20dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelSection.PrivateTabs">
|
||||
@ -86,8 +92,6 @@
|
||||
<item name="android:paddingBottom">12dp</item>
|
||||
<item name="android:paddingLeft">6dp</item>
|
||||
<item name="android:paddingRight">6dp</item>
|
||||
<item name="android:layout_marginLeft">12dp</item>
|
||||
<item name="android:layout_marginRight">12dp</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
</style>
|
||||
|
||||
|
@ -95,6 +95,11 @@
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelFrame.RemoteTabs" parent="TabsPanelFrameBase">
|
||||
<item name="android:paddingLeft">112dp</item>
|
||||
<item name="android:paddingRight">112dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelFrame.PrivateTabs">
|
||||
<item name="android:orientation">horizontal</item>
|
||||
<item name="android:paddingTop">0dp</item>
|
||||
@ -118,19 +123,4 @@
|
||||
<item name="android:layout_gravity">center</item>
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelFrame" parent="TabsPanelFrameBase">
|
||||
<item name="android:paddingLeft">84dp</item>
|
||||
<item name="android:paddingRight">84dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">18dp</item>
|
||||
<item name="android:paddingBottom">18dp</item>
|
||||
<item name="android:paddingLeft">9dp</item>
|
||||
<item name="android:paddingRight">9dp</item>
|
||||
<item name="android:layout_marginLeft">90dp</item>
|
||||
<item name="android:layout_marginRight">90dp</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -29,13 +29,16 @@
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelFrame.RemoteTabs" parent="TabsPanelFrameBase">
|
||||
<item name="android:paddingLeft">0dp</item>
|
||||
<item name="android:paddingRight">0dp</item>
|
||||
</style>
|
||||
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">12dp</item>
|
||||
<item name="android:paddingBottom">12dp</item>
|
||||
<item name="android:paddingLeft">6dp</item>
|
||||
<item name="android:paddingRight">6dp</item>
|
||||
<item name="android:layout_marginLeft">12dp</item>
|
||||
<item name="android:layout_marginRight">12dp</item>
|
||||
<item name="android:textSize">16dp</item>
|
||||
</style>
|
||||
|
||||
|
@ -31,13 +31,9 @@
|
||||
</style>
|
||||
|
||||
<!-- Tabs panel -->
|
||||
<style name="TabsPanelItem.Button" parent="TabsPanelItem.ButtonBase">
|
||||
<item name="android:paddingTop">18dp</item>
|
||||
<item name="android:paddingBottom">18dp</item>
|
||||
<item name="android:paddingLeft">9dp</item>
|
||||
<item name="android:paddingRight">9dp</item>
|
||||
<item name="android:layout_marginLeft">180dp</item>
|
||||
<item name="android:layout_marginRight">180dp</item>
|
||||
<style name="TabsPanelFrame.RemoteTabs" parent="TabsPanelFrameBase">
|
||||
<item name="android:paddingLeft">212dp</item>
|
||||
<item name="android:paddingRight">212dp</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -15,9 +15,11 @@ import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.widget.GeckoPopupMenu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
@ -26,6 +28,8 @@ import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.ArrayList;
|
||||
|
||||
@ -35,10 +39,11 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
private static final String MENU_BUTTON_KEY = "MENU_BUTTON_KEY";
|
||||
private static final int DEFAULT_PAGE_ACTIONS_SHOWN = 2;
|
||||
|
||||
private ArrayList<PageAction> mPageActionList;
|
||||
private final Context mContext;
|
||||
private final LinearLayout mLayout;
|
||||
private final List<PageAction> mPageActionList;
|
||||
|
||||
private GeckoPopupMenu mPageActionsMenu;
|
||||
private Context mContext;
|
||||
private LinearLayout mLayout;
|
||||
|
||||
// By default it's two, can be changed by calling setNumberShown(int)
|
||||
private int mMaxVisiblePageActions;
|
||||
@ -58,10 +63,12 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
}
|
||||
|
||||
private void setNumberShown(int count) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
mMaxVisiblePageActions = count;
|
||||
|
||||
for(int index = 0; index < count; index++) {
|
||||
if ((this.getChildCount() - 1) < index) {
|
||||
for (int index = 0; index < count; index++) {
|
||||
if ((getChildCount() - 1) < index) {
|
||||
mLayout.addView(createImageButton());
|
||||
}
|
||||
}
|
||||
@ -74,12 +81,26 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(String event, NativeJSObject message, EventCallback callback) {
|
||||
public void handleMessage(final String event, final NativeJSObject message, final EventCallback callback) {
|
||||
// NativeJSObject cannot be used off of the Gecko thread, so convert it to a Bundle.
|
||||
final Bundle bundle = message.toBundle();
|
||||
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
handleUiMessage(event, bundle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleUiMessage(final String event, final Bundle message) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
if (event.equals("PageActions:Add")) {
|
||||
final String id = message.getString("id");
|
||||
final String title = message.getString("title");
|
||||
final String imageURL = message.optString("icon", null);
|
||||
final boolean mImportant = message.getBoolean("important");
|
||||
final String imageURL = message.getString("icon");
|
||||
final boolean important = message.getBoolean("important");
|
||||
|
||||
addPageAction(id, title, imageURL, new OnPageActionClickListeners() {
|
||||
@Override
|
||||
@ -92,7 +113,7 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("PageActions:LongClicked", id));
|
||||
return true;
|
||||
}
|
||||
}, mImportant);
|
||||
}, important);
|
||||
} else if (event.equals("PageActions:Remove")) {
|
||||
final String id = message.getString("id");
|
||||
|
||||
@ -100,12 +121,15 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
}
|
||||
}
|
||||
|
||||
private void addPageAction(final String id, final String title, final String imageData, final OnPageActionClickListeners mOnPageActionClickListeners, boolean mImportant) {
|
||||
final PageAction pageAction = new PageAction(id, title, null, mOnPageActionClickListeners, mImportant);
|
||||
private void addPageAction(final String id, final String title, final String imageData,
|
||||
final OnPageActionClickListeners onPageActionClickListeners, boolean important) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
final PageAction pageAction = new PageAction(id, title, null, onPageActionClickListeners, important);
|
||||
|
||||
int insertAt = mPageActionList.size();
|
||||
while(insertAt > 0 && mPageActionList.get(insertAt-1).isImportant()) {
|
||||
insertAt--;
|
||||
while (insertAt > 0 && mPageActionList.get(insertAt - 1).isImportant()) {
|
||||
insertAt--;
|
||||
}
|
||||
mPageActionList.add(insertAt, pageAction);
|
||||
|
||||
@ -121,9 +145,13 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
}
|
||||
|
||||
private void removePageAction(String id) {
|
||||
for(int i = 0; i < mPageActionList.size(); i++) {
|
||||
if (mPageActionList.get(i).getID().equals(id)) {
|
||||
mPageActionList.remove(i);
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
final Iterator<PageAction> iter = mPageActionList.iterator();
|
||||
while (iter.hasNext()) {
|
||||
final PageAction pageAction = iter.next();
|
||||
if (pageAction.getID().equals(id)) {
|
||||
iter.remove();
|
||||
refreshPageActionIcons();
|
||||
return;
|
||||
}
|
||||
@ -131,8 +159,11 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
}
|
||||
|
||||
private ImageButton createImageButton() {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
final int width = mContext.getResources().getDimensionPixelSize(R.dimen.page_action_button_width);
|
||||
ImageButton imageButton = new ImageButton(mContext, null, R.style.UrlBar_ImageButton_Icon);
|
||||
imageButton.setLayoutParams(new LayoutParams(mContext.getResources().getDimensionPixelSize(R.dimen.page_action_button_width), LayoutParams.MATCH_PARENT));
|
||||
imageButton.setLayoutParams(new LayoutParams(width, LayoutParams.MATCH_PARENT));
|
||||
imageButton.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
|
||||
imageButton.setOnClickListener(this);
|
||||
imageButton.setOnLongClickListener(this);
|
||||
@ -163,47 +194,37 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
}
|
||||
|
||||
private void setActionForView(final ImageButton view, final PageAction pageAction) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
if (pageAction == null) {
|
||||
view.setTag(null);
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run () {
|
||||
view.setImageDrawable(null);
|
||||
view.setVisibility(View.GONE);
|
||||
view.setContentDescription(null);
|
||||
}
|
||||
});
|
||||
view.setImageDrawable(null);
|
||||
view.setVisibility(View.GONE);
|
||||
view.setContentDescription(null);
|
||||
return;
|
||||
}
|
||||
|
||||
view.setTag(pageAction.getID());
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run () {
|
||||
view.setImageDrawable(pageAction.getDrawable());
|
||||
view.setVisibility(View.VISIBLE);
|
||||
view.setContentDescription(pageAction.getTitle());
|
||||
}
|
||||
});
|
||||
view.setImageDrawable(pageAction.getDrawable());
|
||||
view.setVisibility(View.VISIBLE);
|
||||
view.setContentDescription(pageAction.getTitle());
|
||||
}
|
||||
|
||||
private void refreshPageActionIcons() {
|
||||
final Resources resources = mContext.getResources();
|
||||
for(int index = 0; index < this.getChildCount(); index++) {
|
||||
final ImageButton v = (ImageButton)this.getChildAt(index);
|
||||
final PageAction pageAction = getPageActionForViewAt(index);
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
// If there are more pageactions then buttons, set the menu icon. Otherwise set the page action's icon if there is a page action.
|
||||
if (index == (this.getChildCount() - 1) && mPageActionList.size() > mMaxVisiblePageActions) {
|
||||
final Resources resources = mContext.getResources();
|
||||
for (int i = 0; i < this.getChildCount(); i++) {
|
||||
final ImageButton v = (ImageButton) this.getChildAt(i);
|
||||
final PageAction pageAction = getPageActionForViewAt(i);
|
||||
|
||||
// If there are more page actions than buttons, set the menu icon.
|
||||
// Otherwise, set the page action's icon if there is a page action.
|
||||
if ((i == this.getChildCount() - 1) && (mPageActionList.size() > mMaxVisiblePageActions)) {
|
||||
v.setTag(MENU_BUTTON_KEY);
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run () {
|
||||
v.setImageDrawable(resources.getDrawable(R.drawable.icon_pageaction));
|
||||
v.setVisibility((pageAction != null) ? View.VISIBLE : View.GONE);
|
||||
v.setContentDescription(resources.getString(R.string.page_action_dropmarker_description));
|
||||
}
|
||||
});
|
||||
v.setImageDrawable(resources.getDrawable(R.drawable.icon_pageaction));
|
||||
v.setVisibility((pageAction != null) ? View.VISIBLE : View.GONE);
|
||||
v.setContentDescription(resources.getString(R.string.page_action_dropmarker_description));
|
||||
} else {
|
||||
setActionForView(v, pageAction);
|
||||
}
|
||||
@ -211,6 +232,8 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
}
|
||||
|
||||
private PageAction getPageActionForViewAt(int index) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
/**
|
||||
* We show the user the most recent pageaction added since this keeps the user aware of any new page actions being added
|
||||
* Also, the order of the pageAction is important i.e. if a page action is added, instead of shifting the pagactions to the
|
||||
@ -221,19 +244,20 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
* and hence we maintain the insertion order of the child Views which is essentially the reverse of their index
|
||||
*/
|
||||
|
||||
int buttonIndex = (this.getChildCount() - 1) - index;
|
||||
int totalVisibleButtons = ((mPageActionList.size() < this.getChildCount()) ? mPageActionList.size() : this.getChildCount());
|
||||
final int buttonIndex = (this.getChildCount() - 1) - index;
|
||||
|
||||
if (mPageActionList.size() > buttonIndex) {
|
||||
// Return the pageactions starting from the end of the list for the number of visible pageactions.
|
||||
return mPageActionList.get((mPageActionList.size() - totalVisibleButtons) + buttonIndex);
|
||||
final int buttonCount = Math.min(mPageActionList.size(), getChildCount());
|
||||
return mPageActionList.get((mPageActionList.size() - buttonCount) + buttonIndex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private PageAction getPageActionWithId(String id) {
|
||||
for(int i = 0; i < mPageActionList.size(); i++) {
|
||||
PageAction pageAction = mPageActionList.get(i);
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
for (PageAction pageAction : mPageActionList) {
|
||||
if (pageAction.getID().equals(id)) {
|
||||
return pageAction;
|
||||
}
|
||||
@ -241,15 +265,17 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
return null;
|
||||
}
|
||||
|
||||
private void showMenu(View mPageActionButton, int toShow) {
|
||||
private void showMenu(View pageActionButton, int toShow) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
|
||||
if (mPageActionsMenu == null) {
|
||||
mPageActionsMenu = new GeckoPopupMenu(mPageActionButton.getContext(), mPageActionButton);
|
||||
mPageActionsMenu = new GeckoPopupMenu(pageActionButton.getContext(), pageActionButton);
|
||||
mPageActionsMenu.inflate(0);
|
||||
mPageActionsMenu.setOnMenuItemClickListener(new GeckoPopupMenu.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
for(int i = 0; i < mPageActionList.size(); i++) {
|
||||
for (int i = 0; i < mPageActionList.size(); i++) {
|
||||
PageAction pageAction = mPageActionList.get(i);
|
||||
if (pageAction.key() == id) {
|
||||
pageAction.onClick();
|
||||
@ -263,12 +289,10 @@ public class PageActionLayout extends LinearLayout implements NativeEventListene
|
||||
Menu menu = mPageActionsMenu.getMenu();
|
||||
menu.clear();
|
||||
|
||||
for(int i = 0; i < mPageActionList.size(); i++) {
|
||||
if (i < toShow) {
|
||||
PageAction pageAction = mPageActionList.get(i);
|
||||
MenuItem item = menu.add(Menu.NONE, pageAction.key(), Menu.NONE, pageAction.getTitle());
|
||||
item.setIcon(pageAction.getDrawable());
|
||||
}
|
||||
for (int i = 0; i < mPageActionList.size() && i < toShow; i++) {
|
||||
PageAction pageAction = mPageActionList.get(i);
|
||||
MenuItem item = menu.add(Menu.NONE, pageAction.key(), Menu.NONE, pageAction.getTitle());
|
||||
item.setIcon(pageAction.getDrawable());
|
||||
}
|
||||
mPageActionsMenu.show();
|
||||
}
|
||||
|
@ -1595,6 +1595,7 @@ var BrowserApp = {
|
||||
type: "Search:Keyword",
|
||||
identifier: engine.identifier,
|
||||
name: engine.name,
|
||||
query: aData
|
||||
});
|
||||
break;
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
-keep public class * extends org.mozilla.gecko.sync.syncadapter.SyncAdapter
|
||||
-keep class org.mozilla.gecko.sync.syncadapter.SyncAdapter
|
||||
|
||||
-keep public class * extends android.support.v4.app.Fragment
|
||||
|
||||
# Preserve all native method names and the names of their classes.
|
||||
-keepclasseswithmembernames class * {
|
||||
native <methods>;
|
||||
|
@ -21,4 +21,7 @@ public class Constants {
|
||||
public static final String SEARCH_FRAGMENT = "org.mozilla.search.SEARCH_FRAGMENT";
|
||||
|
||||
public static final String AUTOCOMPLETE_ROW_LIMIT = "5";
|
||||
|
||||
public static final String YAHOO_WEB_SEARCH_BASE_URL = "https://search.yahoo.com/search?p=";
|
||||
public static final String YAHOO_WEB_SEARCH_RESULTS_FILTER = "//search.yahoo.com";
|
||||
}
|
||||
|
@ -39,14 +39,14 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
|
||||
@Override
|
||||
public void onSearch(String s) {
|
||||
startPostsearch();
|
||||
((PostSearchFragment) getSupportFragmentManager().findFragmentById(R.id.gecko))
|
||||
.setUrl("https://search.yahoo.com/search?p=" + Uri.encode(s));
|
||||
((PostSearchFragment) getSupportFragmentManager().findFragmentById(R.id.postsearch))
|
||||
.startSearch(s);
|
||||
}
|
||||
|
||||
private void startPresearch() {
|
||||
if (state != State.PRESEARCH) {
|
||||
state = State.PRESEARCH;
|
||||
findViewById(R.id.gecko).setVisibility(View.INVISIBLE);
|
||||
findViewById(R.id.postsearch).setVisibility(View.INVISIBLE);
|
||||
findViewById(R.id.presearch).setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
@ -55,7 +55,7 @@ public class MainActivity extends FragmentActivity implements AcceptsSearchQuery
|
||||
if (state != State.POSTSEARCH) {
|
||||
state = State.POSTSEARCH;
|
||||
findViewById(R.id.presearch).setVisibility(View.INVISIBLE);
|
||||
findViewById(R.id.gecko).setVisibility(View.VISIBLE);
|
||||
findViewById(R.id.postsearch).setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,23 +5,22 @@
|
||||
package org.mozilla.search;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.mozilla.gecko.GeckoView;
|
||||
import org.mozilla.gecko.GeckoViewChrome;
|
||||
import org.mozilla.gecko.GeckoViewContent;
|
||||
import org.mozilla.gecko.PrefsHelper;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
|
||||
public class PostSearchFragment extends Fragment {
|
||||
|
||||
private static final String LOGTAG = "PostSearchFragment";
|
||||
private GeckoView geckoView;
|
||||
private WebView webview;
|
||||
|
||||
public PostSearchFragment() {}
|
||||
|
||||
|
||||
@Override
|
||||
@ -30,71 +29,41 @@ public class PostSearchFragment extends Fragment {
|
||||
View mainView = inflater.inflate(R.layout.search_activity_detail, container, false);
|
||||
|
||||
|
||||
geckoView = (GeckoView) mainView.findViewById(R.id.gecko_view);
|
||||
|
||||
geckoView.setChromeDelegate(new MyGeckoViewChrome());
|
||||
geckoView.setContentDelegate(new SearchGeckoView());
|
||||
|
||||
PrefsHelper.setPref("privacy.clearOnShutdown.cache", true);
|
||||
PrefsHelper.setPref("privacy.clearOnShutdown.cookies", true);
|
||||
|
||||
|
||||
if (null == geckoView.getCurrentBrowser()) {
|
||||
// This pageload allows Fennec to be loaded in a background fragment.
|
||||
// Without supplying a URL, it doesn't look like Fennec will get loaded?
|
||||
geckoView.addBrowser("https://search.yahoo.com/search?p=firefox%20android");
|
||||
|
||||
}
|
||||
|
||||
webview = (WebView) mainView.findViewById(R.id.webview);
|
||||
webview.setWebViewClient(new WebViewClient(){
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
if (isSearchResultsPage(url)) {
|
||||
super.onPageStarted(view, url, favicon);
|
||||
} else {
|
||||
webview.stopLoading();
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(url));
|
||||
startActivity(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
return mainView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if a given URL is a page of search results.
|
||||
* <p>
|
||||
* Search results pages will be shown in the embedded view. Other pages are
|
||||
* opened in external browsers.
|
||||
*
|
||||
* @param url to test.
|
||||
* @return true if <code>url</code> is a page of search results.
|
||||
*/
|
||||
protected boolean isSearchResultsPage(String url) {
|
||||
return url.contains(Constants.YAHOO_WEB_SEARCH_RESULTS_FILTER);
|
||||
}
|
||||
|
||||
public void startSearch(String query) {
|
||||
setUrl(Constants.YAHOO_WEB_SEARCH_BASE_URL + Uri.encode(query));
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
if (null == geckoView.getCurrentBrowser()) {
|
||||
geckoView.addBrowser(url);
|
||||
} else {
|
||||
geckoView.getCurrentBrowser().loadUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class MyGeckoViewChrome extends GeckoViewChrome {
|
||||
@Override
|
||||
public void onReady(GeckoView view) {
|
||||
Log.i(LOGTAG, "Gecko is ready");
|
||||
|
||||
PrefsHelper.setPref("devtools.debugger.remote-enabled", true);
|
||||
|
||||
// The Gecko libraries have finished loading and we can use the rendering engine.
|
||||
// Let's add a browser (required) and load a page into it.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class SearchGeckoView extends GeckoViewContent {
|
||||
|
||||
@Override
|
||||
public void onPageStart(GeckoView geckoView, GeckoView.Browser browser, String s) {
|
||||
Log.i("OnPageStart", s);
|
||||
// Only load this page if it's the Yahoo search page that we're using.
|
||||
// TODO: Make this check more robust, and allow for other search providers.
|
||||
if (s.contains("//search.yahoo.com")) {
|
||||
super.onPageStart(geckoView, browser, s);
|
||||
|
||||
|
||||
} else {
|
||||
browser.stop();
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(s));
|
||||
startActivity(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageShow(GeckoView geckoView, GeckoView.Browser browser) {
|
||||
|
||||
}
|
||||
webview.loadUrl(url);
|
||||
}
|
||||
}
|
||||
|
@ -6,15 +6,11 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
tools:context="org.mozilla.search.PostSearchFragment">
|
||||
|
||||
<org.mozilla.gecko.GeckoView
|
||||
android:id="@+id/gecko_view"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"/>
|
||||
|
||||
<WebView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/webview"/>
|
||||
</RelativeLayout>
|
||||
|
@ -14,7 +14,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:name="org.mozilla.search.PostSearchFragment"
|
||||
android:id="@+id/gecko"
|
||||
android:id="@+id/postsearch"
|
||||
/>
|
||||
|
||||
<fragment
|
||||
|
@ -357,10 +357,6 @@ pref("media.navigator.enabled", true);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
pref("media.tabstreaming.width", 320);
|
||||
pref("media.tabstreaming.height", 240);
|
||||
pref("media.tabstreaming.time_per_frame", 40);
|
||||
|
||||
// TextTrack support
|
||||
pref("media.webvtt.enabled", true);
|
||||
pref("media.webvtt.regions.enabled", false);
|
||||
|
Loading…
Reference in New Issue
Block a user