Merge fx-team to m-c a=merge

This commit is contained in:
Wes Kocher 2014-07-15 17:26:32 -07:00
commit 2e408ff3b5
37 changed files with 528 additions and 249 deletions

View File

@ -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")

View File

@ -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))

View File

@ -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;

View File

@ -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) {

View File

@ -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)
}
}
}));
});
}

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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")

View File

@ -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);

View File

@ -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);

View File

@ -0,0 +1,4 @@
{
"id": "test-packaging",
"description": "Add-on development made easy."
}

View File

@ -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);

View File

@ -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");
}, []);
});
});

View File

@ -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," />';

View File

@ -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) {

View File

@ -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() {

View File

@ -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,

View File

@ -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/';

View File

@ -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;
}

View File

@ -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"

View File

@ -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);
}

View File

@ -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">

View File

@ -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">

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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();
}

View File

@ -1595,6 +1595,7 @@ var BrowserApp = {
type: "Search:Keyword",
identifier: engine.identifier,
name: engine.name,
query: aData
});
break;

View File

@ -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>;

View File

@ -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";
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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>

View File

@ -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

View File

@ -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);