зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound. a=merge
This commit is contained in:
Коммит
c966517190
|
@ -41,10 +41,9 @@ const ObserverDelegee = Class({
|
|||
this.delegate = delegate;
|
||||
},
|
||||
QueryInterface: function(iid) {
|
||||
const isObserver = iid.equals(Ci.nsIObserver);
|
||||
const isWeakReference = iid.equals(Ci.nsISupportsWeakReference);
|
||||
|
||||
if (!isObserver && !isWeakReference)
|
||||
if (!iid.equals(Ci.nsIObserver) &&
|
||||
!iid.equals(Ci.nsISupportsWeakReference) &&
|
||||
!iid.equals(Ci.nsISupports))
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
|
||||
return this;
|
||||
|
|
|
@ -295,6 +295,9 @@ let hides = filter(panelEvents, ({type}) => type === "popuphidden");
|
|||
let ready = filter(panelEvents, ({type, target}) =>
|
||||
getAttachEventType(modelFor(panelFor(target))) === type);
|
||||
|
||||
// Panel event emitted when the contents of the panel has been loaded.
|
||||
let readyToShow = filter(panelEvents, ({type}) => type === "DOMContentLoaded");
|
||||
|
||||
// Styles should be always added as soon as possible, and doesn't makes them
|
||||
// depends on `contentScriptWhen`
|
||||
let start = filter(panelEvents, ({type}) => type === "document-element-inserted");
|
||||
|
@ -317,6 +320,10 @@ on(ready, "data", ({target}) => {
|
|||
let window = domPanel.getContentDocument(target).defaultView;
|
||||
|
||||
workerFor(panel).attach(window);
|
||||
});
|
||||
|
||||
on(readyToShow, "data", ({target}) => {
|
||||
let panel = panelFor(target);
|
||||
|
||||
if (!modelFor(panel).ready) {
|
||||
modelFor(panel).ready = true;
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
const { create: makeFrame } = require("sdk/frame/utils");
|
||||
const { window } = require("sdk/addon/window");
|
||||
const { Loader } = require('sdk/test/loader');
|
||||
const loader = Loader(module);
|
||||
const Worker = loader.require("sdk/content/worker").Worker;
|
||||
|
||||
exports.testMembranelessMode = function(assert, done) {
|
||||
const loader = Loader(module);
|
||||
const Worker = loader.require("sdk/content/worker").Worker;
|
||||
|
||||
let url = "data:text/html;charset=utf-8," + encodeURIComponent(
|
||||
'<script>' +
|
||||
|
@ -48,13 +48,20 @@ exports.testMembranelessMode = function(assert, done) {
|
|||
done();
|
||||
}
|
||||
});
|
||||
worker.port.on("done", function () {
|
||||
|
||||
worker.port.on("done", () => {
|
||||
// cleanup
|
||||
element.parentNode.removeChild(element);
|
||||
worker.destroy();
|
||||
loader.unload();
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
worker.port.on("assert", function (data) {
|
||||
assert.ok(data.assertion, data.msg);
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ exports.testBufferMain = function (assert) {
|
|||
// invalid encoding for Buffer.toString
|
||||
assert.throws(() => {
|
||||
b.toString('invalid');
|
||||
}, TypeError, 'invalid encoding for Buffer.toString');
|
||||
}, RangeError, 'invalid encoding for Buffer.toString');
|
||||
|
||||
// try to toString() a 0-length slice of a buffer, both within and without the
|
||||
// valid buffer range
|
||||
|
@ -248,7 +248,7 @@ exports.testBufferWrite = function (assert) {
|
|||
|
||||
assert.throws(() => {
|
||||
b.write('test string', 0, 5, 'invalid');
|
||||
}, TypeError, 'invalid encoding with buffer write throws');
|
||||
}, RangeError, 'invalid encoding with buffer write throws');
|
||||
// try to write a 0-length string beyond the end of b
|
||||
assert.throws(function() {
|
||||
b.write('', 2048);
|
||||
|
|
|
@ -10,6 +10,7 @@ const {openWindow, closeWindow, openTab, closeTab,
|
|||
const {when} = require("sdk/dom/events");
|
||||
const {Item, Menu, Separator, Contexts, Readers } = require("sdk/context-menu@2");
|
||||
const prefs = require("sdk/preferences/service");
|
||||
const { before, after } = require('sdk/test/utils');
|
||||
|
||||
const testPageURI = require.resolve("./test-context-menu").replace(".js", ".html");
|
||||
|
||||
|
@ -1337,4 +1338,13 @@ if (require("@loader/options").isNative) {
|
|||
};
|
||||
}
|
||||
|
||||
before(exports, (name, assert) => {
|
||||
// Make sure Java doesn't activate
|
||||
prefs.set("plugin.state.java", 0);
|
||||
});
|
||||
|
||||
after(exports, (name, assert) => {
|
||||
prefs.reset("plugin.state.java");
|
||||
});
|
||||
|
||||
require("sdk/test").run(module.exports);
|
||||
|
|
|
@ -86,8 +86,9 @@ exports["test Panel API"] = test(function*(assert) {
|
|||
yield closeToolbox();
|
||||
|
||||
assert.equal(panel.readyState, "destroyed", "panel is destroyed");
|
||||
});
|
||||
|
||||
myTool.destroy();
|
||||
});
|
||||
|
||||
exports["test Panel communication"] = test(function*(assert) {
|
||||
const MyPanel = Class({
|
||||
|
@ -150,6 +151,7 @@ exports["test Panel communication"] = test(function*(assert) {
|
|||
yield closeToolbox();
|
||||
|
||||
assert.equal(panel.readyState, "destroyed", "panel is destroyed");
|
||||
myTool.destroy();
|
||||
});
|
||||
|
||||
exports["test communication with debuggee"] = test(function*(assert) {
|
||||
|
@ -233,6 +235,8 @@ exports["test communication with debuggee"] = test(function*(assert) {
|
|||
yield closeToolbox();
|
||||
|
||||
assert.equal(panel.readyState, "destroyed", "panel is destroyed");
|
||||
|
||||
myTool.destroy();
|
||||
});
|
||||
|
||||
|
||||
|
@ -267,6 +271,8 @@ exports["test viewFor panel"] = test(function*(assert) {
|
|||
assert.equal(frame.contentDocument.URL, url, "is expected iframe");
|
||||
|
||||
yield closeToolbox();
|
||||
|
||||
myTool.destroy();
|
||||
});
|
||||
|
||||
|
||||
|
@ -314,6 +320,8 @@ exports["test createView panel"] = test(function*(assert) {
|
|||
assert.equal(frame.contentDocument.URL, url, "is expected iframe");
|
||||
|
||||
yield closeToolbox();
|
||||
|
||||
myTool.destroy();
|
||||
});
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
|
|
|
@ -12,6 +12,7 @@ const { Class } = require("sdk/core/heritage");
|
|||
const { Cc, Ci, Cu } = require("chrome");
|
||||
const { notifyObservers } = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
const { defer } = require("sdk/core/promise");
|
||||
|
||||
const message = x => ({wrappedJSObject: x});
|
||||
|
||||
|
@ -120,4 +121,63 @@ exports["test weak observers are GC-ed on unload"] = (assert, end) => {
|
|||
});
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
exports["test weak observer unsubscribe"] = function*(assert) {
|
||||
const loader = Loader(module);
|
||||
const { Observer, observe, subscribe, unsubscribe } = loader.require("sdk/core/observer");
|
||||
const { WeakReference } = loader.require("sdk/core/reference");
|
||||
|
||||
let sawNotification = false;
|
||||
let firstWait = defer();
|
||||
let secondWait = defer();
|
||||
|
||||
const WeakObserver = Class({
|
||||
extends: Observer,
|
||||
implements: [WeakReference],
|
||||
observe: function() {
|
||||
sawNotification = true;
|
||||
firstWait.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
const StrongObserver = Class({
|
||||
extends: Observer,
|
||||
observe: function() {
|
||||
secondWait.resolve();
|
||||
}
|
||||
});
|
||||
|
||||
observe.define(Observer, (x, ...rest) => x.observe(...rest));
|
||||
|
||||
let weakObserver = new WeakObserver;
|
||||
let strongObserver = new StrongObserver();
|
||||
subscribe(weakObserver, "test-topic");
|
||||
subscribe(strongObserver, "test-wait");
|
||||
|
||||
notifyObservers(null, "test-topic", null);
|
||||
yield firstWait.promise;
|
||||
|
||||
assert.ok(sawNotification, "Should have seen notification before GC");
|
||||
sawNotification = false;
|
||||
|
||||
yield loader.require("sdk/test/memory").gc();
|
||||
|
||||
notifyObservers(null, "test-topic", null);
|
||||
notifyObservers(null, "test-wait", null);
|
||||
yield secondWait.promise;
|
||||
|
||||
assert.ok(sawNotification, "Should have seen notification after GC");
|
||||
sawNotification = false;
|
||||
|
||||
try {
|
||||
unsubscribe(weakObserver, "test-topic");
|
||||
unsubscribe(strongObserver, "test-wait");
|
||||
assert.pass("Should not have seen an exception");
|
||||
}
|
||||
catch (e) {
|
||||
assert.fail("Should not have seen an exception");
|
||||
}
|
||||
|
||||
loader.unload();
|
||||
};
|
||||
|
||||
require("sdk/test").run(exports);
|
||||
|
|
|
@ -1297,7 +1297,6 @@ exports["test panel addon global object"] = function*(assert) {
|
|||
exports["test panel load doesn't show"] = function*(assert) {
|
||||
let loader = Loader(module);
|
||||
|
||||
let showCount = 0;
|
||||
let panel = loader.require("sdk/panel").Panel({
|
||||
contentScript: "addEventListener('load', function(event) { self.postMessage('load'); });",
|
||||
contentScriptWhen: "start",
|
||||
|
@ -1335,6 +1334,24 @@ exports["test panel load doesn't show"] = function*(assert) {
|
|||
loader.unload();
|
||||
}
|
||||
|
||||
exports["test Panel without contentURL and contentScriptWhen=start should show"] = function*(assert) {
|
||||
let loader = Loader(module);
|
||||
|
||||
let panel = loader.require("sdk/panel").Panel({
|
||||
contentScriptWhen: "start",
|
||||
// No contentURL, the bug only shows up when contentURL is not explicitly set.
|
||||
});
|
||||
|
||||
yield new Promise(resolve => {
|
||||
panel.once("show", resolve);
|
||||
panel.show();
|
||||
});
|
||||
|
||||
assert.pass("Received show event");
|
||||
|
||||
loader.unload();
|
||||
}
|
||||
|
||||
if (packaging.isNative) {
|
||||
module.exports = {
|
||||
"test skip on jpm": (assert) => assert.pass("skipping this file with jpm")
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="cdaa0a4ac28c781709df8c318ed079e9e475503a">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -118,7 +118,7 @@
|
|||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9d83b3a8e72c773820ada75e5a2cd128a743cf35"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="10e78a05252b3de785f88c2d0b9ea8a428009c50"/>
|
||||
<project name="platform/system/media" path="system/media" revision="7ff72c2ea2496fa50b5e8a915e56e901c3ccd240"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3211e72ef1407171b52d8258fb92298cbd3ec651"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="85df9b5036010d9aa057c72cdfc7c86fc51f7c10"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="3ae56364946d4a5bf5a5f83f12f9a45a30398e33"/>
|
||||
<project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
|
||||
<project name="platform/system/vold" path="system/vold" revision="2e43efe1b30d0b98574d293059556aebd2f46454"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
|
@ -120,7 +120,7 @@
|
|||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9d83b3a8e72c773820ada75e5a2cd128a743cf35"/>
|
||||
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3211e72ef1407171b52d8258fb92298cbd3ec651"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="85df9b5036010d9aa057c72cdfc7c86fc51f7c10"/>
|
||||
<project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
|
||||
<project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="cdaa0a4ac28c781709df8c318ed079e9e475503a">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -118,7 +118,7 @@
|
|||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9d83b3a8e72c773820ada75e5a2cd128a743cf35"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="5356165f67f4a81c2ef28671c13697f1657590df"/>
|
||||
<project name="platform/system/media" path="system/media" revision="be0e2fe59a8043fa5200f75697df9220a99abe9d"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3211e72ef1407171b52d8258fb92298cbd3ec651"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="85df9b5036010d9aa057c72cdfc7c86fc51f7c10"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="36704b0da24debcab8090156568ac236315036bb"/>
|
||||
<project name="platform/system/security" path="system/security" revision="583374f69f531ba68fc3dcbff1f74893d2a96406"/>
|
||||
<project name="platform/system/vold" path="system/vold" revision="d4455b8cf361f8353e8aebac15ffd64b4aedd2b9"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eb1795a9002eb142ac58c8d68f8f4ba094af07ca"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="cdaa0a4ac28c781709df8c318ed079e9e475503a">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -111,7 +111,7 @@
|
|||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="5a48c04c4bb5f079bc757e29864a42427378e051"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9d83b3a8e72c773820ada75e5a2cd128a743cf35"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="576f57b6510de59c08568b53c0fb60588be8689e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3211e72ef1407171b52d8258fb92298cbd3ec651"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="85df9b5036010d9aa057c72cdfc7c86fc51f7c10"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/>
|
||||
<project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/>
|
||||
<project name="platform/system/vold" path="system/vold" revision="42fa2a0f14f965970a4b629a176bbd2666edf017"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"git": {
|
||||
"git_revision": "82f286f10a41aab84a0796c89fbefe67b179994b",
|
||||
"git_revision": "620aecfde85a8b093247837c55de2708e22be1e1",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "066f0e84321a010700467d1814ee0048dca7e5e1",
|
||||
"revision": "42da22fe3d59646d07bad417e194969dd2cc891d",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="c42985975f2bbc42859b9136ed348186d989b93d"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d0d11d190ccc50d7d66009bcc896ad4b42d3f0d"/>
|
||||
|
@ -120,7 +120,7 @@
|
|||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9d83b3a8e72c773820ada75e5a2cd128a743cf35"/>
|
||||
<project name="platform_system_core" path="system/core" remote="b2g" revision="542d1f59dc331b472307e5bd043101d14d5a3a3e"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="18c1180e848e7ab8691940481f5c1c8d22c37b3e"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3211e72ef1407171b52d8258fb92298cbd3ec651"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="85df9b5036010d9aa057c72cdfc7c86fc51f7c10"/>
|
||||
<project name="platform/system/media" path="system/media" revision="d90b836f66bf1d9627886c96f3a2d9c3007fbb80"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="56112dd7b811301b718d0643a82fd5cac9522073"/>
|
||||
<project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="7f2ee9f4cb926684883fc2a2e407045fd9db2199">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82f286f10a41aab84a0796c89fbefe67b179994b"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="620aecfde85a8b093247837c55de2708e22be1e1"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="2262d4a77d4f46ab230fd747bb91e9b77bad36cb"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -128,7 +128,7 @@
|
|||
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="6e18b61ee446bdd9880c07ae84197a087490c2e5"/>
|
||||
<project name="platform_system_bluetoothd" path="system/bluetoothd" remote="b2g" revision="9d83b3a8e72c773820ada75e5a2cd128a743cf35"/>
|
||||
<project name="platform/system/extras" path="system/extras" revision="18f7c51415917eb0e21b30f220db7bd0be4130a7"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="3211e72ef1407171b52d8258fb92298cbd3ec651"/>
|
||||
<project name="platform_system_libfdio" path="system/libfdio" remote="b2g" revision="85df9b5036010d9aa057c72cdfc7c86fc51f7c10"/>
|
||||
<project name="platform/system/media" path="system/media" revision="adf8fbacf7395858884690df5e3ce46bc75fa683"/>
|
||||
<project name="platform/system/netd" path="system/netd" revision="655392625db084a7122d65a15acf74db7f1da7f7"/>
|
||||
<project name="platform/system/security" path="system/security" revision="e6b3fdd892ad994ec3fd0b8959d630e31881801b"/>
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
<command id="Tools:WebIDE" oncommand="gDevToolsBrowser.openWebIDE();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:BrowserToolbox" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:BrowserContentToolbox" oncommand="gDevToolsBrowser.openContentProcessToolbox();" disabled="true" hidden="true"/>
|
||||
<command id="Tools:BrowserConsole" oncommand="HUDService.toggleBrowserConsole();"/>
|
||||
<command id="Tools:BrowserConsole" oncommand="HUDService.openBrowserConsoleOrFocus();"/>
|
||||
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/>
|
||||
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/>
|
||||
<command id="Tools:Eyedropper" oncommand="openEyedropper();"/>
|
||||
|
|
|
@ -5480,30 +5480,30 @@
|
|||
var event = document.createEvent("Events");
|
||||
event.initEvent("select", true, true);
|
||||
this.dispatchEvent(event);
|
||||
|
||||
this._selectedIndex = val;
|
||||
|
||||
switchPromise.then(() => {
|
||||
// If we cannot find the tabpanel that we were trying to switch to, then
|
||||
// it must have been removed before our Promise could be resolved. In
|
||||
// that case, we just cancel the tab switch.
|
||||
var updatedTabIndex = Array.indexOf(this.childNodes, newPanel);
|
||||
if (updatedTabIndex == -1) {
|
||||
gBrowser._cancelTabSwitch(toTab);
|
||||
} else {
|
||||
this.setAttribute("selectedIndex", updatedTabIndex);
|
||||
gBrowser._finalizeTabSwitch(toTab, fromTab);
|
||||
}
|
||||
}, () => {
|
||||
// If the promise rejected, that means we don't want to actually
|
||||
// flip the deck, so we cancel the tab switch.
|
||||
// We need to nullcheck the method we're about to call because
|
||||
// the binding might be dead at this point.
|
||||
if (gBrowser._cancelTabSwitch)
|
||||
gBrowser._cancelTabSwitch(toTab);
|
||||
});
|
||||
}
|
||||
|
||||
this._selectedIndex = val;
|
||||
|
||||
switchPromise.then(() => {
|
||||
// If we cannot find the tabpanel that we were trying to switch to, then
|
||||
// it must have been removed before our Promise could be resolved. In
|
||||
// that case, we just cancel the tab switch.
|
||||
var updatedTabIndex = Array.indexOf(this.childNodes, newPanel);
|
||||
if (updatedTabIndex == -1) {
|
||||
gBrowser._cancelTabSwitch(toTab);
|
||||
} else {
|
||||
this.setAttribute("selectedIndex", updatedTabIndex);
|
||||
gBrowser._finalizeTabSwitch(toTab, fromTab);
|
||||
}
|
||||
}, () => {
|
||||
// If the promise rejected, that means we don't want to actually
|
||||
// flip the deck, so we cancel the tab switch.
|
||||
// We need to nullcheck the method we're about to call because
|
||||
// the binding might be dead at this point.
|
||||
if (gBrowser._cancelTabSwitch)
|
||||
gBrowser._cancelTabSwitch(toTab);
|
||||
});
|
||||
|
||||
return val;
|
||||
]]>
|
||||
</setter>
|
||||
|
|
|
@ -429,7 +429,7 @@ skip-if = e10s
|
|||
skip-if = e10s # Bug 1100664 - test relies on linkedBrowser.docShell
|
||||
[browser_tabs_owner.js]
|
||||
[browser_testOpenNewRemoteTabsFromNonRemoteBrowsers.js]
|
||||
skip-if = !e10s && os == "linux" # Bug 994541 - Need OMTC enabled by default on Linux, or else we get blocked by an alert dialog when opening e10s window.
|
||||
run-if = e10s
|
||||
[browser_trackingUI.js]
|
||||
support-files =
|
||||
trackingPage.html
|
||||
|
|
|
@ -33,9 +33,13 @@ add_task(function* () {
|
|||
readerButton.click();
|
||||
yield promiseTabLoadEvent(tab);
|
||||
|
||||
ok(gBrowser.selectedBrowser.currentURI.spec.startsWith("about:reader"), "about:reader loaded after clicking reader mode button");
|
||||
let readerUrl = gBrowser.selectedBrowser.currentURI.spec;
|
||||
ok(readerUrl.startsWith("about:reader"), "about:reader loaded after clicking reader mode button");
|
||||
is_element_visible(readerButton, "Reader mode button is present on about:reader");
|
||||
|
||||
is(gURLBar.value, readerUrl, "gURLBar value is about:reader URL");
|
||||
is(gURLBar.textValue, url.substring("http://".length), "gURLBar is displaying original article URL");
|
||||
|
||||
readerButton.click();
|
||||
yield promiseTabLoadEvent(tab);
|
||||
is(gBrowser.selectedBrowser.currentURI.spec, url, "Original page loaded after clicking active reader mode button");
|
||||
|
|
|
@ -160,6 +160,11 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let originalUrl = ReaderParent.parseReaderUrl(aValue);
|
||||
if (originalUrl) {
|
||||
returnValue = originalUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the actiontype only if the user is not overriding actions.
|
||||
|
|
|
@ -37,12 +37,6 @@ let gSubDialog = {
|
|||
// Wait for the stylesheets injected during DOMContentLoaded to load before showing the dialog
|
||||
// otherwise there is a flicker of the stylesheet applying.
|
||||
this._frame.addEventListener("load", this._onLoad.bind(this));
|
||||
|
||||
chromeBrowser.addEventListener("unload", function(aEvent) {
|
||||
if (aEvent.target.location.href != "about:blank") {
|
||||
this.close();
|
||||
}
|
||||
}.bind(this), true);
|
||||
},
|
||||
|
||||
uninit: function() {
|
||||
|
|
|
@ -76,7 +76,7 @@ let gTests = [{
|
|||
dialog.document.documentElement.cancelDialog();
|
||||
|
||||
let closingEvent = yield closingPromise;
|
||||
ise(closingEvent.detail.button, "cancel", "closing event should indicate button was 'cancel'");
|
||||
ise(closingEvent.detail.button, "cancel", "closing event should indicate button was 'accept'");
|
||||
|
||||
yield deferredClose.promise;
|
||||
ise(rv.acceptCount, 0, "return value should NOT have been updated");
|
||||
|
@ -118,26 +118,6 @@ let gTests = [{
|
|||
ise(rv.acceptCount, 0, "return value should NOT have been updated");
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Check that 'back' navigation will close the dialog",
|
||||
run: function* () {
|
||||
let rv = { acceptCount: 0 };
|
||||
let deferredClose = Promise.defer();
|
||||
let dialogPromise = openAndLoadSubDialog(gDialogURL, null, rv,
|
||||
(aEvent) => dialogClosingCallback(deferredClose, aEvent));
|
||||
let dialog = yield dialogPromise;
|
||||
|
||||
// XXX Without the call to promiseDialogClosing the test causes
|
||||
// intermittent failures in browser_change_app_handler.js.
|
||||
let unusedClosingPromise = promiseDialogClosing(dialog);
|
||||
|
||||
info("cancelling the dialog");
|
||||
content.gSubDialog._frame.goBack();
|
||||
|
||||
yield deferredClose.promise;
|
||||
ise(rv.acceptCount, 0, "return value should NOT have been updated");
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "Hitting escape in the dialog",
|
||||
run: function* () {
|
||||
|
|
|
@ -219,7 +219,7 @@ Tools.shaderEditor = {
|
|||
tooltip: l10n("ToolboxShaderEditor.tooltip", shaderEditorStrings),
|
||||
|
||||
isTargetSupported: function(target) {
|
||||
return target.hasActor("webgl");
|
||||
return target.hasActor("webgl") && !target.chrome;
|
||||
},
|
||||
|
||||
build: function(iframeWindow, toolbox) {
|
||||
|
|
|
@ -13,6 +13,7 @@ support-files =
|
|||
doc_automation.html
|
||||
doc_bug_1125817.html
|
||||
doc_bug_1130901.html
|
||||
doc_bug_1112378.html
|
||||
440hz_sine.ogg
|
||||
head.js
|
||||
|
||||
|
@ -26,18 +27,19 @@ support-files =
|
|||
[browser_audionode-actor-connectnode-disconnect.js]
|
||||
[browser_audionode-actor-connectparam.js]
|
||||
skip-if = true # bug 1092571
|
||||
[browser_audionode-actor-add-automation-event.js]
|
||||
[browser_audionode-actor-get-automation-data-01.js]
|
||||
[browser_audionode-actor-get-automation-data-02.js]
|
||||
[browser_audionode-actor-get-automation-data-03.js]
|
||||
# [browser_audionode-actor-add-automation-event.js] bug 1134036
|
||||
# [browser_audionode-actor-get-automation-data-01.js] bug 1134036
|
||||
# [browser_audionode-actor-get-automation-data-02.js] bug 1134036
|
||||
# [browser_audionode-actor-get-automation-data-03.js] bug 1134036
|
||||
[browser_callwatcher-01.js]
|
||||
[browser_callwatcher-02.js]
|
||||
[browser_webaudio-actor-simple.js]
|
||||
[browser_webaudio-actor-destroy-node.js]
|
||||
[browser_webaudio-actor-connect-param.js]
|
||||
[browser_webaudio-actor-automation-event.js]
|
||||
# [browser_webaudio-actor-automation-event.js] bug 1134036
|
||||
|
||||
[browser_wa_automation-view-01.js]
|
||||
[browser_wa_automation-view-02.js]
|
||||
# [browser_wa_automation-view-01.js] bug 1134036
|
||||
# [browser_wa_automation-view-02.js] bug 1134036
|
||||
[browser_wa_controller-01.js]
|
||||
[browser_wa_destroy-node-01.js]
|
||||
[browser_wa_first-run.js]
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Bug 1112378
|
||||
* Tests to ensure that errors called on wrapped functions via call-watcher
|
||||
* correctly looks like the error comes from the content, not from within the devtools.
|
||||
*/
|
||||
|
||||
const BUG_1112378_URL = EXAMPLE_URL + "doc_bug_1112378.html";
|
||||
|
||||
add_task(function*() {
|
||||
let { target, panel } = yield initWebAudioEditor(BUG_1112378_URL);
|
||||
let { panelWin } = panel;
|
||||
let { gFront, $, $$, EVENTS, gAudioNodes } = panelWin;
|
||||
|
||||
loadFrameScripts();
|
||||
|
||||
reload(target);
|
||||
|
||||
yield waitForGraphRendered(panelWin, 2, 0);
|
||||
|
||||
let error = yield evalInDebuggee("throwError()");
|
||||
is(error.lineNumber, 21, "error has correct lineNumber");
|
||||
is(error.columnNumber, 11, "error has correct columnNumber");
|
||||
is(error.name, "TypeError", "error has correct name");
|
||||
is(error.message, "Argument 1 is not valid for any of the 2-argument overloads of AudioNode.connect.", "error has correct message");
|
||||
is(error.stringified, "TypeError: Argument 1 is not valid for any of the 2-argument overloads of AudioNode.connect.", "error is stringified correctly");
|
||||
ise(error.instanceof, true, "error is correctly an instanceof TypeError");
|
||||
is(error.fileName, "http://example.com/browser/browser/devtools/webaudioeditor/test/doc_bug_1112378.html", "error has correct fileName");
|
||||
|
||||
error = yield evalInDebuggee("throwDOMException()");
|
||||
is(error.lineNumber, 37, "exception has correct lineNumber");
|
||||
is(error.columnNumber, 0, "exception has correct columnNumber");
|
||||
is(error.code, 9, "exception has correct code");
|
||||
is(error.result, 2152923145, "exception has correct result");
|
||||
is(error.name, "NotSupportedError", "exception has correct name");
|
||||
is(error.message, "Operation is not supported", "exception has correct message");
|
||||
is(error.stringified, "NotSupportedError: Operation is not supported", "exception is stringified correctly");
|
||||
ise(error.instanceof, true, "exception is correctly an instance of DOMException");
|
||||
is(error.filename, "http://example.com/browser/browser/devtools/webaudioeditor/test/doc_bug_1112378.html", "exception has correct filename");
|
||||
|
||||
yield teardown(target);
|
||||
});
|
|
@ -0,0 +1,57 @@
|
|||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Web Audio Editor test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<script type="text/javascript;version=1.8">
|
||||
"use strict";
|
||||
|
||||
let ctx = new AudioContext();
|
||||
let osc = ctx.createOscillator();
|
||||
|
||||
function throwError () {
|
||||
try {
|
||||
osc.connect({});
|
||||
} catch (e) {
|
||||
return {
|
||||
lineNumber: e.lineNumber,
|
||||
fileName: e.fileName,
|
||||
columnNumber: e.columnNumber,
|
||||
message: e.message,
|
||||
instanceof: e instanceof TypeError,
|
||||
stringified: e.toString(),
|
||||
name: e.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function throwDOMException () {
|
||||
try {
|
||||
osc.frequency.setValueAtTime(0, -1);
|
||||
} catch (e) {
|
||||
return {
|
||||
lineNumber: e.lineNumber,
|
||||
columnNumber: e.columnNumber,
|
||||
filename: e.filename,
|
||||
message: e.message,
|
||||
code: e.code,
|
||||
result: e.result,
|
||||
instanceof: e instanceof DOMException,
|
||||
stringified: e.toString(),
|
||||
name: e.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -16,10 +16,13 @@ let { Promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
|
|||
let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {});
|
||||
let { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
|
||||
|
||||
let { WebAudioFront } = devtools.require("devtools/server/actors/webaudio");
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let mm = null;
|
||||
|
||||
const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-utils.js";
|
||||
const EXAMPLE_URL = "http://example.com/browser/browser/devtools/webaudioeditor/test/";
|
||||
const SIMPLE_CONTEXT_URL = EXAMPLE_URL + "doc_simple-context.html";
|
||||
const COMPLEX_CONTEXT_URL = EXAMPLE_URL + "doc_complex-context.html";
|
||||
|
@ -47,6 +50,15 @@ registerCleanupFunction(() => {
|
|||
Cu.forceGC();
|
||||
});
|
||||
|
||||
/**
|
||||
* Call manually in tests that use frame script utils after initializing
|
||||
* the web audio editor. Call after init but before navigating to a different page.
|
||||
*/
|
||||
function loadFrameScripts () {
|
||||
mm = gBrowser.selectedBrowser.messageManager;
|
||||
mm.loadFrameScript(FRAME_SCRIPT_UTILS_URL, false);
|
||||
}
|
||||
|
||||
function addTab(aUrl, aWindow) {
|
||||
info("Adding tab: " + aUrl);
|
||||
|
||||
|
@ -440,6 +452,33 @@ function waitForInspectorRender (panelWin, EVENTS) {
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a string `script` and evaluates it directly in the content
|
||||
* in potentially a different process.
|
||||
*/
|
||||
function evalInDebuggee (script) {
|
||||
let deferred = Promise.defer();
|
||||
|
||||
if (!mm) {
|
||||
throw new Error("`loadFrameScripts()` must be called when using MessageManager.");
|
||||
}
|
||||
|
||||
let id = generateUUID().toString();
|
||||
mm.sendAsyncMessage("devtools:test:eval", { script: script, id: id });
|
||||
mm.addMessageListener("devtools:test:eval:response", handler);
|
||||
|
||||
function handler ({ data }) {
|
||||
if (id !== data.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
mm.removeMessageListener("devtools:test:eval:response", handler);
|
||||
deferred.resolve(data.value);
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of audio node properties to test against expectations of the AudioNode actor
|
||||
*/
|
||||
|
|
|
@ -96,8 +96,10 @@
|
|||
<tabs>
|
||||
<tab id="properties-tab"
|
||||
label="&webAudioEditorUI.tab.properties2;"/>
|
||||
<!-- bug 1134036
|
||||
<tab id="automation-tab"
|
||||
label="&webAudioEditorUI.tab.automation;"/>
|
||||
-->
|
||||
</tabs>
|
||||
<tabpanels flex="1">
|
||||
<!-- Properties Panel -->
|
||||
|
|
|
@ -251,6 +251,21 @@ HUD_SERVICE.prototype =
|
|||
return this._browserConsoleDefer.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens or focuses the Browser Console.
|
||||
*/
|
||||
openBrowserConsoleOrFocus: function HS_openBrowserConsoleOrFocus()
|
||||
{
|
||||
let hud = this.getBrowserConsole();
|
||||
if (hud) {
|
||||
hud.iframeWindow.focus();
|
||||
return promise.resolve(hud);
|
||||
}
|
||||
else {
|
||||
return this.toggleBrowserConsole();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the Browser Console instance, if open.
|
||||
*
|
||||
|
@ -763,7 +778,8 @@ const HUDService = new HUD_SERVICE();
|
|||
(() => {
|
||||
let methods = ["openWebConsole", "openBrowserConsole",
|
||||
"toggleBrowserConsole", "getOpenWebConsole",
|
||||
"getBrowserConsole", "getHudByWindow", "getHudReferenceById"];
|
||||
"getBrowserConsole", "getHudByWindow",
|
||||
"openBrowserConsoleOrFocus", "getHudReferenceById"];
|
||||
for (let method of methods) {
|
||||
exports[method] = HUDService[method].bind(HUDService);
|
||||
}
|
||||
|
|
|
@ -377,3 +377,4 @@ skip-if = e10s # Bug 1042253 - webconsole e10s tests (Linux debug timeout)
|
|||
[browser_webconsole_console_custom_styles.js]
|
||||
[browser_webconsole_console_api_stackframe.js]
|
||||
[browser_webconsole_column_numbers.js]
|
||||
[browser_console_open_or_focus.js]
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
*/
|
||||
|
||||
// Test that the "browser console" menu item opens or focuses (if already open)
|
||||
// the console window instead of toggling it open/close.
|
||||
|
||||
|
||||
"use strict";
|
||||
|
||||
let test = asyncTest(function* () {
|
||||
let wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||
.getService(Components.interfaces.nsIWindowMediator);
|
||||
let currWindow, hud, mainWindow;
|
||||
|
||||
mainWindow = Services.wm.getMostRecentWindow(null);
|
||||
|
||||
yield HUDService.openBrowserConsoleOrFocus();
|
||||
|
||||
hud = HUDService.getBrowserConsole();
|
||||
|
||||
console.log("testmessage");
|
||||
yield waitForMessages({
|
||||
webconsole: hud,
|
||||
messages: [{
|
||||
text: "testmessage"
|
||||
}],
|
||||
});
|
||||
|
||||
currWindow = Services.wm.getMostRecentWindow(null);
|
||||
is(currWindow.document.documentURI, devtools.Tools.webConsole.url,
|
||||
"The Browser Console is open and has focus");
|
||||
|
||||
mainWindow.focus();
|
||||
|
||||
yield HUDService.openBrowserConsoleOrFocus();
|
||||
|
||||
currWindow = Services.wm.getMostRecentWindow(null);
|
||||
is(currWindow.document.documentURI, devtools.Tools.webConsole.url,
|
||||
"The Browser Console is open and has focus");
|
||||
|
||||
yield HUDService.toggleBrowserConsole();
|
||||
|
||||
hud = HUDService.getBrowserConsole();
|
||||
ok(!hud, "Browser Console has been closed");
|
||||
});
|
|
@ -23,7 +23,7 @@
|
|||
fullscreenbutton="true"
|
||||
screenX="4" screenY="4"
|
||||
width="640" height="480"
|
||||
persist="screenX screenY width height">
|
||||
persist="screenX screenY width height sizemode">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"></script>
|
||||
<script type="application/javascript" src="webide.js"></script>
|
||||
|
|
|
@ -26,8 +26,6 @@ let ReaderParent = {
|
|||
"Reader:ListStatusRequest",
|
||||
"Reader:RemoveFromList",
|
||||
"Reader:Share",
|
||||
"Reader:ShowToast",
|
||||
"Reader:ToolbarVisibility",
|
||||
"Reader:SystemUIVisibility",
|
||||
"Reader:UpdateReaderButton",
|
||||
],
|
||||
|
@ -70,18 +68,10 @@ let ReaderParent = {
|
|||
// XXX: To implement.
|
||||
break;
|
||||
|
||||
case "Reader:ShowToast":
|
||||
// XXX: To implement.
|
||||
break;
|
||||
|
||||
case "Reader:SystemUIVisibility":
|
||||
// XXX: To implement.
|
||||
break;
|
||||
|
||||
case "Reader:ToolbarVisibility":
|
||||
// XXX: To implement.
|
||||
break;
|
||||
|
||||
case "Reader:UpdateReaderButton": {
|
||||
let browser = message.target;
|
||||
if (message.data && message.data.isArticle !== undefined) {
|
||||
|
@ -122,23 +112,37 @@ let ReaderParent = {
|
|||
|
||||
let win = event.target.ownerDocument.defaultView;
|
||||
let url = win.gBrowser.selectedBrowser.currentURI.spec;
|
||||
|
||||
if (url.startsWith("about:reader")) {
|
||||
win.openUILinkIn(this._getOriginalUrl(url), "current");
|
||||
let originalURL = this._getOriginalUrl(url);
|
||||
if (!originalURL) {
|
||||
Cu.reportError("Error finding original URL for about:reader URL: " + url);
|
||||
} else {
|
||||
win.openUILinkIn(originalURL, "current");
|
||||
}
|
||||
} else {
|
||||
win.openUILinkIn("about:reader?url=" + encodeURIComponent(url), "current");
|
||||
}
|
||||
},
|
||||
|
||||
parseReaderUrl: function(url) {
|
||||
if (!url.startsWith("about:reader?")) {
|
||||
return null;
|
||||
}
|
||||
return this._getOriginalUrl(url);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns original URL from an about:reader URL.
|
||||
*
|
||||
* @param url An about:reader URL.
|
||||
* @return The original URL for the article, or null if we did not find
|
||||
* a properly formatted about:reader URL.
|
||||
*/
|
||||
_getOriginalUrl: function(url) {
|
||||
let searchParams = new URLSearchParams(url.split("?")[1]);
|
||||
let searchParams = new URLSearchParams(url.substring("about:reader?".length));
|
||||
if (!searchParams.has("url")) {
|
||||
Cu.reportError("Error finding original URL for about:reader URL: " + url);
|
||||
return url;
|
||||
return null;
|
||||
}
|
||||
return decodeURIComponent(searchParams.get("url"));
|
||||
},
|
||||
|
|
|
@ -174,8 +174,7 @@ browser.jar:
|
|||
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
|
||||
* skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css)
|
||||
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
|
||||
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
|
||||
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
|
|
|
@ -280,8 +280,7 @@ browser.jar:
|
|||
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
|
||||
* skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css)
|
||||
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
|
||||
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
|
||||
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
|
|
Двоичные данные
browser/themes/shared/incontentprefs/icons.png
Двоичные данные
browser/themes/shared/incontentprefs/icons.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 4.6 KiB |
|
@ -0,0 +1,129 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
viewBox="0 0 24 24">
|
||||
<style>
|
||||
use:not(:target) {
|
||||
display: none;
|
||||
}
|
||||
use {
|
||||
fill: #fbfbfb;
|
||||
stroke: rgba(0,0,0,0.4);
|
||||
stroke-width: .5px;
|
||||
}
|
||||
use[id$="-native"] {
|
||||
fill: ThreeDHighlight;
|
||||
}
|
||||
</style>
|
||||
<defs style="display: none;">
|
||||
<g id="general-shape">
|
||||
<path
|
||||
d="M18.97,3H5.03C3.914,3,3,3.914,3,5.03v13.94C3,20.086,3.914,21,5.03,21H18.97c1.117,0,2.03-0.914,2.03-2.03
|
||||
V5.03C21,3.914,20.086,3,18.97,3z M5.35,19.326c-0.404,0-0.731-0.327-0.731-0.731c0-0.404,0.327-0.731,0.731-0.731
|
||||
c0.404,0,0.731,0.327,0.731,0.731C6.081,19,5.754,19.326,5.35,19.326z M5.35,6.168c-0.403,0-0.731-0.328-0.731-0.731
|
||||
c0-0.404,0.328-0.731,0.731-0.731c0.403,0,0.731,0.327,0.731,0.731C6.081,5.84,5.753,6.168,5.35,6.168z M15.243,14.035
|
||||
c0,0.229-0.186,0.416-0.414,0.416c-0.229,0-0.415,0.186-0.415,0.414v3.347c0,0.228-0.185,0.384-0.414,0.384l-4.141,0.03
|
||||
c-0.227,0-0.414-0.186-0.414-0.414v-3.347c0-0.228-0.185-0.414-0.414-0.414c-0.227,0-0.414-0.187-0.414-0.416V6.582
|
||||
c0-0.229,0.187-0.414,0.414-0.414h5.798c0.228,0,0.414,0.185,0.414,0.414V14.035z M18.509,19.326c-0.404,0-0.731-0.327-0.731-0.731
|
||||
c0-0.404,0.327-0.731,0.731-0.731c0.404,0,0.731,0.327,0.731,0.731C19.24,19,18.913,19.326,18.509,19.326z M18.509,6.168
|
||||
c-0.404,0-0.731-0.328-0.731-0.731c0-0.404,0.327-0.731,0.731-0.731c0.404,0,0.731,0.327,0.731,0.731
|
||||
C19.24,5.84,18.913,6.168,18.509,6.168z"/>
|
||||
<path
|
||||
d="M12.757,7.824h-1.657c-0.456,0-0.828,0.373-0.828,0.828v8.282c0,0.456,0.373,0.828,0.828,0.828h1.657
|
||||
c0.456,0,0.828-0.373,0.828-0.828V8.652C13.586,8.196,13.213,7.824,12.757,7.824z"/>
|
||||
</g>
|
||||
<g id="search-shape">
|
||||
<path
|
||||
d="M2,10.018c0,4.43,3.585,8.019,8.009,8.019
|
||||
c1.603,0,3.095-0.473,4.348-1.285l4.806,4.81c0.58,0.583,1.523,0.583,2.105,0l0.296-0.297c0.582-0.583,0.582-1.527,0-2.11
|
||||
l-4.808-4.814c0.8-1.247,1.265-2.73,1.265-4.323c0-4.43-3.587-8.018-8.012-8.018C5.585,2,2,5.589,2,10.018z M5.104,10.021
|
||||
c0-2.716,2.196-4.915,4.906-4.915c2.71,0,4.908,2.199,4.908,4.915c0,2.712-2.198,4.911-4.908,4.911
|
||||
C7.3,14.931,5.104,12.732,5.104,10.021z"/>
|
||||
</g>
|
||||
<g id="content-shape">
|
||||
<path
|
||||
d="M16.286,2H5.571C4.388,2,3.429,2.96,3.429,4.143v15.714
|
||||
C3.429,21.04,4.388,22,5.571,22h12.857c1.185,0,2.143-0.96,2.143-2.143V6.286L16.286,2z M18.945,19.223c0,0.22-0.18,0.4-0.4,0.4
|
||||
h-13.2c-0.22,0-0.4-0.18-0.4-0.4v-0.846c0-0.22,0.18-0.4,0.4-0.4h13.2c0.22,0,0.4,0.18,0.4,0.4V19.223z M18.945,15.223
|
||||
c0,0.22-0.18,0.4-0.4,0.4h-13.2c-0.22,0-0.4-0.18-0.4-0.4v-0.846c0-0.22,0.18-0.4,0.4-0.4h13.2c0.22,0,0.4,0.18,0.4,0.4V15.223z
|
||||
M18.945,11.229c0,0.22-0.18,0.4-0.4,0.4h-13.2c-0.22,0-0.4-0.18-0.4-0.4v-0.846c0-0.22,0.18-0.4,0.4-0.4h13.2
|
||||
c0.22,0,0.4,0.18,0.4,0.4V11.229z M14.833,7.707v-4.65l4.65,4.65H14.833z"/>
|
||||
</g>
|
||||
<g id="applications-shape">
|
||||
<path
|
||||
d="M16.673,8.914C16.089,4.122,13.248,1,12,1c-1.25,0-3.986,3.122-4.767,7.914l-3.122,3.131v7.889h2.268
|
||||
l2.978-3.436c0.28,0.29,0.737,1.666,1.065,1.858h3.155c0.331-0.193,0.789-1.569,1.068-1.858l3.123,3.436h2.12v-7.84L16.673,8.914z
|
||||
M12.042,8.735c-0.604,0-1.279,0.06-1.818,0.165c0.478-1.453,1.345-3.117,1.781-3.117c0.435,0,1.301,1.655,1.775,3.1
|
||||
C13.265,8.789,12.615,8.735,12.042,8.735z M12.524,19.145c0.076,0.196,0.119,0.602,0.119,0.86c0,0.66-0.524,1.074-0.687,1.074
|
||||
c-0.163,0-0.615-0.414-0.615-1.074c0-0.257,0.045-0.664,0.119-0.86h-0.754c-0.089,0.345-0.39,1.005-0.39,1.408
|
||||
c0,1.458,1.328,2.447,1.686,2.447c0.359,0,1.686-0.951,1.686-2.407c0-0.404-0.301-1.103-0.388-1.449H12.524z"/>
|
||||
</g>
|
||||
<g id="privacy-shape">
|
||||
<path
|
||||
d="M21.632,9.541c-0.083,1.403,0.246,3.079-1.597,5.498
|
||||
c-1.965,2.578-3.914,2.594-4.284,2.575c-2.249-0.117-2.502-1.875-3.792-1.875c-1.13,0-2.012,1.745-3.711,1.836
|
||||
c-0.37,0.02-2.319,0.042-4.284-2.536c-1.841-2.419-1.514-4.095-1.597-5.498C2.287,8.138,2,6.618,2,6.618s0.887,0.895,2.033,0.973
|
||||
C5.179,7.67,5.394,7.191,7.811,6.501C10.424,5.752,12,8.814,12,8.814s1.776-3.016,4.189-2.313c2.414,0.7,2.515,1.169,3.661,1.091
|
||||
C20.996,7.513,22,6.618,22,6.618S21.713,8.138,21.632,9.541z M8.117,10.129c-1.429-0.314-2.028,0.223-2.642,0.451
|
||||
c-0.534,0.202-1.02,0.264-1.02,0.264s0.083,0.819,1.515,1.521c1.432,0.703,4.37,0.338,4.37,0.338S10.651,10.687,8.117,10.129z
|
||||
M18.525,10.58c-0.612-0.228-1.212-0.765-2.642-0.451c-2.534,0.558-2.223,2.573-2.223,2.573s2.938,0.365,4.37-0.338
|
||||
c1.432-0.702,1.515-1.521,1.515-1.521S19.059,10.782,18.525,10.58z"/>
|
||||
</g>
|
||||
<g id="security-shape">
|
||||
<path
|
||||
d="M18.909,9.783h-0.863V8.086C18.046,4.725,15.339,2,12,2
|
||||
C8.661,2,5.954,4.725,5.954,8.086v1.697H5.091c-0.955,0-1.728,0.779-1.728,1.739v8.738c0,0.961,0.773,1.74,1.728,1.74h13.818
|
||||
c0.954,0,1.728-0.779,1.728-1.74v-8.738C20.637,10.562,19.863,9.783,18.909,9.783z M8.545,8.086c0-1.92,1.547-3.478,3.455-3.478
|
||||
c1.908,0,3.455,1.557,3.455,3.478v1.697h-6.91V8.086z M5.181,16.092l-0.909-1.2v-2.284l2.728,3.483H5.181z M8.818,16.092
|
||||
l-2.773-3.657h1.727l2.864,3.657H8.818z M12,16.092l-2.773-3.657h1.727l2.864,3.657H12z M15.637,16.092l-2.773-3.657h1.727
|
||||
l2.864,3.657H15.637z M19.728,16.092h-0.455l-2.773-3.657h1.727l1.501,1.916V16.092z"/>
|
||||
</g>
|
||||
<g id="sync-shape">
|
||||
<path
|
||||
d="M17.024,3.351 c-0.562,0.331 -1.311,0.879 -1.821,1.698 -0.367,0.592 -0.752,1.288 -1.08,1.914 0.987,0.413 1.862,1.095
|
||||
2.476,2.029 0.614,0.957 0.929,2.122 0.83,3.351 -0.201,1.787 -1.359,3.433 -3.046,4.36 -0.696,-0.774 -1.951,-2.945
|
||||
-1.951,-2.945 -0.007,0.007 -0.004,2.556 -0.871,4.334 -0.573,1.184 -1.24,2.202 -2.305,2.995 1.431,0.51 2.915,0.886
|
||||
4.282,0.909 l 0.162,0.002 c 2.99,0.021 5.844,-0.48 5.844,-0.48 0,0 -1.236,-0.802 -1.808,-1.346 1.86,-1.072 3.111,-2.791
|
||||
3.634,-4.708 0.283,-0.759 0.478,-1.566 0.57,-2.409 C 22.383,9.011 20.33,5.278 17.024,3.351 Z M 6.569,12.302 C 6.526,10.271
|
||||
7.755,8.327 9.644,7.29 c 0.696,0.774 2.32,2.899 2.32,2.899 0,0 -0.064,-5.157 1.657,-7.973 -6.097,-0.668 -9.69,0.443
|
||||
-9.69,0.443 0,0 1.763,0.607 2.333,1.136 C 6.122,3.891 5.984,3.992 5.85,4.096 4.4,5.064 3.368,6.449 2.825,7.994 2.436,8.892
|
||||
2.171,9.863 2.06,10.887 1.622,14.886 3.629,18.572 6.871,20.515 7.39,20.124 7.975,19.631 8.61,18.983 9.189,18.389 9.647,17.682
|
||||
10.021,16.967 8.082,16.208 6.714,14.404 6.569,12.302 Z"/>
|
||||
</g>
|
||||
<g id="advanced-shape">
|
||||
<path
|
||||
d="M19.173,16.163c0.004,0.04,0.007,0.08,0.007,0.121c0,1.748-3.197,3.165-7.14,3.165 c-3.943,0-7.14-1.417-7.14-3.165c0
|
||||
-0.037,0.003-0.073,0.006-0.109C3.11,16.572,2,17.243,2,18.341C2,20.362,6.477,22,12,22 c5.523,0,10-1.638,10-3.659
|
||||
C22,17.22,20.922,16.553,19.173,16.163z"/>
|
||||
<path
|
||||
d="M18.224,15.979c0.006-0.11-0.018-0.285-0.054-0.39c0,0-0.762-2.205-1.176-3.403
|
||||
c-0.624-1.807-2.112-6.139-2.112-6.139c-0.036-0.104-0.031-0.273,0.01-0.376l0.497-1.234c0.041-0.102,0.116-0.266,0.166-0.364
|
||||
l0.986-1.942c0.05-0.098,0.013-0.133-0.081-0.077L9.965,5.871c-0.095,0.056-0.203,0.186-0.24,0.29c0,0-0.252,0.7-0.412,1.144
|
||||
C8.64,9.173,7.968,11.04,7.296,12.908c-0.26,0.723-0.52,1.446-0.78,2.168c-0.056,0.156-0.112,0.311-0.168,0.466
|
||||
c-0.093,0.26-0.049,0.617,0.032,0.881c0.237,0.763,1.001,1.189,1.708,1.435c0.611,0.213,1.254,0.328,1.895,0.403
|
||||
c0.895,0.105,1.805,0.14,2.706,0.112c1.356-0.041,2.767-0.261,4.004-0.846c0.429-0.203,0.854-0.459,1.174-0.816
|
||||
c0.121-0.135,0.226-0.287,0.297-0.455C18.215,16.134,18.224,15.979,18.224,15.979z M14.063,16.131
|
||||
c0.019,0.108-0.046,0.156-0.143,0.104l-1.466-0.772c-0.097-0.052-0.257-0.052-0.354,0l-1.466,0.773
|
||||
c-0.097,0.052-0.162,0.004-0.143-0.104l0.28-1.636c0.019-0.109-0.031-0.261-0.109-0.338l-1.186-1.158
|
||||
c-0.079-0.077-0.054-0.153,0.055-0.169l1.638-0.239c0.109-0.016,0.238-0.11,0.286-0.209l0.733-1.488
|
||||
c0.049-0.099,0.128-0.099,0.177,0l0.733,1.488c0.049,0.099,0.178,0.193,0.286,0.209l1.639,0.239
|
||||
c0.109,0.016,0.134,0.092,0.055,0.169l-1.186,1.158c-0.079,0.077-0.128,0.229-0.109,0.338L14.063,16.131z"/>
|
||||
</g>
|
||||
</defs>
|
||||
<use id="general" xlink:href="#general-shape"/>
|
||||
<use id="general-native" xlink:href="#general-shape"/>
|
||||
<use id="search" xlink:href="#search-shape"/>
|
||||
<use id="search-native" xlink:href="#search-shape"/>
|
||||
<use id="content" xlink:href="#content-shape"/>
|
||||
<use id="content-native" xlink:href="#content-shape"/>
|
||||
<use id="applications" xlink:href="#applications-shape"/>
|
||||
<use id="applications-native" xlink:href="#applications-shape"/>
|
||||
<use id="privacy" xlink:href="#privacy-shape"/>
|
||||
<use id="privacy-native" xlink:href="#privacy-shape"/>
|
||||
<use id="security" xlink:href="#security-shape"/>
|
||||
<use id="security-native" xlink:href="#security-shape"/>
|
||||
<use id="sync" xlink:href="#sync-shape"/>
|
||||
<use id="sync-native" xlink:href="#sync-shape"/>
|
||||
<use id="advanced" xlink:href="#advanced-shape"/>
|
||||
<use id="advanced-native" xlink:href="#advanced-shape"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 8.9 KiB |
Двоичные данные
browser/themes/shared/incontentprefs/icons@2x.png
Двоичные данные
browser/themes/shared/incontentprefs/icons@2x.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 11 KiB |
|
@ -43,78 +43,36 @@ treecol {
|
|||
visibility: collapse;
|
||||
}
|
||||
|
||||
.category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.png");
|
||||
}
|
||||
|
||||
#category-general > .category-icon {
|
||||
-moz-image-region: rect(0, 24px, 24px, 0);
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#general");
|
||||
}
|
||||
|
||||
#category-search > .category-icon {
|
||||
-moz-image-region: rect(0, 192px, 24px, 168px);
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#search");
|
||||
}
|
||||
|
||||
#category-content > .category-icon {
|
||||
-moz-image-region: rect(0, 48px, 24px, 24px);
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#content");
|
||||
}
|
||||
|
||||
#category-application > .category-icon {
|
||||
-moz-image-region: rect(0, 72px, 24px, 48px);
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#applications");
|
||||
}
|
||||
|
||||
#category-privacy > .category-icon {
|
||||
-moz-image-region: rect(0, 96px, 24px, 72px);
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#privacy");
|
||||
}
|
||||
|
||||
#category-security > .category-icon {
|
||||
-moz-image-region: rect(0, 120px, 24px, 96px);
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#security");
|
||||
}
|
||||
|
||||
#category-sync > .category-icon {
|
||||
-moz-image-region: rect(0, 144px, 24px, 120px);
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#sync");
|
||||
}
|
||||
|
||||
#category-advanced > .category-icon {
|
||||
-moz-image-region: rect(0, 168px, 24px, 144px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons@2x.png");
|
||||
}
|
||||
|
||||
#category-general > .category-icon {
|
||||
-moz-image-region: rect(0, 48px, 48px, 0);
|
||||
}
|
||||
|
||||
#category-search > .category-icon {
|
||||
-moz-image-region: rect(0, 384px, 48px, 336px);
|
||||
}
|
||||
|
||||
#category-content > .category-icon {
|
||||
-moz-image-region: rect(0, 96px, 48px, 48px);
|
||||
}
|
||||
|
||||
#category-application > .category-icon {
|
||||
-moz-image-region: rect(0, 144px, 48px, 96px);
|
||||
}
|
||||
|
||||
#category-privacy > .category-icon {
|
||||
-moz-image-region: rect(0, 192px, 48px, 144px);
|
||||
}
|
||||
|
||||
#category-security > .category-icon {
|
||||
-moz-image-region: rect(0, 240px, 48px, 192px);
|
||||
}
|
||||
|
||||
#category-sync > .category-icon {
|
||||
-moz-image-region: rect(0, 288px, 48px, 240px);
|
||||
}
|
||||
|
||||
#category-advanced > .category-icon {
|
||||
-moz-image-region: rect(0, 336px, 48px, 288px);
|
||||
}
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#advanced");
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
|
|
|
@ -202,8 +202,7 @@ browser.jar:
|
|||
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
|
||||
* skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css)
|
||||
skin/classic/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
|
||||
skin/classic/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
|
||||
skin/classic/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
|
||||
skin/classic/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
|
@ -670,8 +669,7 @@ browser.jar:
|
|||
* skin/classic/aero/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
|
||||
* skin/classic/aero/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css)
|
||||
skin/classic/aero/browser/preferences/in-content/favicon.ico (../shared/incontentprefs/favicon.ico)
|
||||
skin/classic/aero/browser/preferences/in-content/icons.png (../shared/incontentprefs/icons.png)
|
||||
skin/classic/aero/browser/preferences/in-content/icons@2x.png (../shared/incontentprefs/icons@2x.png)
|
||||
skin/classic/aero/browser/preferences/in-content/icons.svg (../shared/incontentprefs/icons.svg)
|
||||
skin/classic/aero/browser/preferences/in-content/search.css (../shared/incontentprefs/search.css)
|
||||
skin/classic/aero/browser/preferences/applications.css (preferences/applications.css)
|
||||
skin/classic/aero/browser/preferences/aboutPermissions.css (preferences/aboutPermissions.css)
|
||||
|
|
|
@ -4,6 +4,40 @@
|
|||
|
||||
%include ../../../shared/incontentprefs/preferences.inc.css
|
||||
|
||||
@media not all and (-moz-windows-default-theme) {
|
||||
#category-general > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#general-native");
|
||||
}
|
||||
|
||||
#category-search > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#search-native");
|
||||
}
|
||||
|
||||
#category-content > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#content-native");
|
||||
}
|
||||
|
||||
#category-application > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#applications-native");
|
||||
}
|
||||
|
||||
#category-privacy > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#privacy-native");
|
||||
}
|
||||
|
||||
#category-security > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#security-native");
|
||||
}
|
||||
|
||||
#category-sync > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#sync-native");
|
||||
}
|
||||
|
||||
#category-advanced > .category-icon {
|
||||
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.svg#advanced-native");
|
||||
}
|
||||
}
|
||||
|
||||
.actionsMenu > .menulist-label-box > .menulist-icon {
|
||||
-moz-margin-end: 9px;
|
||||
}
|
||||
|
|
|
@ -53,41 +53,38 @@ struct SavedFrame::Lookup {
|
|||
JSAtom *functionDisplayName;
|
||||
SavedFrame *parent;
|
||||
JSPrincipals *principals;
|
||||
};
|
||||
|
||||
class SavedFrame::AutoLookupRooter : public JS::CustomAutoRooter
|
||||
{
|
||||
public:
|
||||
AutoLookupRooter(JSContext *cx, JSAtom *source, uint32_t line, uint32_t column,
|
||||
JSAtom *functionDisplayName, SavedFrame *parent, JSPrincipals *principals)
|
||||
: JS::CustomAutoRooter(cx),
|
||||
value(source, line, column, functionDisplayName, parent, principals) {}
|
||||
|
||||
operator const SavedFrame::Lookup&() const { return value; }
|
||||
SavedFrame::Lookup &get() { return value; }
|
||||
|
||||
private:
|
||||
virtual void trace(JSTracer *trc) {
|
||||
gc::MarkStringUnbarriered(trc, &value.source, "SavedFrame::Lookup::source");
|
||||
if (value.functionDisplayName) {
|
||||
gc::MarkStringUnbarriered(trc, &value.functionDisplayName,
|
||||
void trace(JSTracer *trc) {
|
||||
gc::MarkStringUnbarriered(trc, &source, "SavedFrame::Lookup::source");
|
||||
if (functionDisplayName) {
|
||||
gc::MarkStringUnbarriered(trc, &functionDisplayName,
|
||||
"SavedFrame::Lookup::functionDisplayName");
|
||||
}
|
||||
if (value.parent)
|
||||
gc::MarkObjectUnbarriered(trc, &value.parent, "SavedFrame::Lookup::parent");
|
||||
if (parent) {
|
||||
gc::MarkObjectUnbarriered(trc, &parent,
|
||||
"SavedFrame::Lookup::parent");
|
||||
}
|
||||
}
|
||||
|
||||
SavedFrame::Lookup value;
|
||||
};
|
||||
|
||||
class SavedFrame::HandleLookup
|
||||
{
|
||||
class MOZ_STACK_CLASS SavedFrame::AutoLookupVector : public JS::CustomAutoRooter {
|
||||
public:
|
||||
MOZ_IMPLICIT HandleLookup(SavedFrame::AutoLookupRooter &lookup) : ref(lookup) { }
|
||||
SavedFrame::Lookup *operator->() { return &ref.get(); }
|
||||
operator const SavedFrame::Lookup&() const { return ref; }
|
||||
explicit AutoLookupVector(JSContext *cx)
|
||||
: JS::CustomAutoRooter(cx),
|
||||
lookups(cx)
|
||||
{ }
|
||||
|
||||
typedef Vector<Lookup, 20> LookupVector;
|
||||
inline LookupVector *operator->() { return &lookups; }
|
||||
inline Lookup &operator[](size_t i) { return lookups[i]; }
|
||||
|
||||
private:
|
||||
SavedFrame::AutoLookupRooter &ref;
|
||||
LookupVector lookups;
|
||||
|
||||
virtual void trace(JSTracer *trc) {
|
||||
for (size_t i = 0; i < lookups.length(); i++)
|
||||
lookups[i].trace(trc);
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ HashNumber
|
||||
|
@ -580,12 +577,14 @@ SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFram
|
|||
// SavedFrame objects at that time.
|
||||
//
|
||||
// To avoid making many copies of FrameIter (whose copy constructor is
|
||||
// relatively slow), we save the subset of FrameIter's data that is relevant
|
||||
// to our needs in a FrameState object, and maintain a vector of FrameState
|
||||
// objects instead of a vector of FrameIter objects.
|
||||
// relatively slow), we use a vector of `SavedFrame::Lookup` objects, which
|
||||
// only contain the FrameIter data we need. The `SavedFrame::Lookup`
|
||||
// objects are partially initialized with everything except their parent
|
||||
// pointers on the first pass, and then we fill in the parent pointers as we
|
||||
// return in the second pass.
|
||||
|
||||
// Accumulate the vector of FrameState objects in |stackState|.
|
||||
AutoFrameStateVector stackState(cx);
|
||||
// Accumulate the vector of Lookup objects in |stackChain|.
|
||||
SavedFrame::AutoLookupVector stackChain(cx);
|
||||
while (!iter.done()) {
|
||||
AutoLocationValueRooter location(cx);
|
||||
|
||||
|
@ -595,12 +594,18 @@ SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFram
|
|||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
FrameState frameState(iter);
|
||||
frameState.location = location.get();
|
||||
if (!stackState->append(frameState))
|
||||
return false;
|
||||
}
|
||||
// Use growByUninitialized and placement-new instead of just append.
|
||||
// We'd ideally like to use an emplace method once Vector supports it.
|
||||
if (!stackChain->growByUninitialized(1))
|
||||
return false;
|
||||
new (&stackChain->back()) SavedFrame::Lookup(
|
||||
location->source,
|
||||
location->line,
|
||||
location->column,
|
||||
iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr,
|
||||
nullptr,
|
||||
iter.compartment()->principals
|
||||
);
|
||||
|
||||
++iter;
|
||||
|
||||
|
@ -617,18 +622,13 @@ SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFram
|
|||
}
|
||||
}
|
||||
|
||||
// Iterate through |stackState| in reverse order and get or create the
|
||||
// Iterate through |stackChain| in reverse order and get or create the
|
||||
// actual SavedFrame instances.
|
||||
RootedSavedFrame parentFrame(cx, nullptr);
|
||||
for (size_t i = stackState->length(); i != 0; i--) {
|
||||
SavedFrame::AutoLookupRooter lookup(cx,
|
||||
stackState[i-1].location.source,
|
||||
stackState[i-1].location.line,
|
||||
stackState[i-1].location.column,
|
||||
stackState[i-1].name,
|
||||
parentFrame,
|
||||
stackState[i-1].principals);
|
||||
parentFrame = getOrCreateSavedFrame(cx, lookup);
|
||||
for (size_t i = stackChain->length(); i != 0; i--) {
|
||||
SavedFrame::AutoLookupRooter lookup(cx, &stackChain[i-1]);
|
||||
lookup->parent = parentFrame;
|
||||
parentFrame.set(getOrCreateSavedFrame(cx, lookup));
|
||||
if (!parentFrame)
|
||||
return false;
|
||||
}
|
||||
|
@ -640,7 +640,8 @@ SavedStacks::insertFrames(JSContext *cx, FrameIter &iter, MutableHandleSavedFram
|
|||
SavedFrame *
|
||||
SavedStacks::getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup lookup)
|
||||
{
|
||||
DependentAddPtr<SavedFrame::Set> p(cx, frames, lookup);
|
||||
const SavedFrame::Lookup &lookupInstance = *lookup;
|
||||
DependentAddPtr<SavedFrame::Set> p(cx, frames, lookupInstance);
|
||||
if (p)
|
||||
return *p;
|
||||
|
||||
|
@ -648,7 +649,7 @@ SavedStacks::getOrCreateSavedFrame(JSContext *cx, SavedFrame::HandleLookup looku
|
|||
if (!frame)
|
||||
return nullptr;
|
||||
|
||||
if (!p.add(cx, frames, lookup, frame))
|
||||
if (!p.add(cx, frames, lookupInstance, frame))
|
||||
return nullptr;
|
||||
|
||||
return frame;
|
||||
|
@ -778,31 +779,6 @@ SavedStacks::chooseSamplingProbability(JSContext *cx)
|
|||
allocationSamplingProbability = allocationTrackingDbg->allocationSamplingProbability;
|
||||
}
|
||||
|
||||
SavedStacks::FrameState::FrameState(const FrameIter &iter)
|
||||
: principals(iter.compartment()->principals),
|
||||
name(iter.isNonEvalFunctionFrame() ? iter.functionDisplayAtom() : nullptr),
|
||||
location()
|
||||
{
|
||||
}
|
||||
|
||||
SavedStacks::FrameState::FrameState(const FrameState &fs)
|
||||
: principals(fs.principals),
|
||||
name(fs.name),
|
||||
location(fs.location)
|
||||
{
|
||||
}
|
||||
|
||||
SavedStacks::FrameState::~FrameState()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SavedStacks::FrameState::trace(JSTracer *trc) {
|
||||
if (name)
|
||||
gc::MarkStringUnbarriered(trc, &name, "SavedStacks::FrameState::name");
|
||||
location.trace(trc);
|
||||
}
|
||||
|
||||
bool
|
||||
SavedStacksMetadataCallback(JSContext *cx, JSObject **pmetadata)
|
||||
{
|
||||
|
|
|
@ -55,8 +55,9 @@ class SavedFrame : public NativeObject {
|
|||
HashPolicy,
|
||||
SystemAllocPolicy> Set;
|
||||
|
||||
class AutoLookupRooter;
|
||||
class HandleLookup;
|
||||
typedef RootedGeneric<Lookup*> AutoLookupRooter;
|
||||
typedef AutoLookupRooter &HandleLookup;
|
||||
class AutoLookupVector;
|
||||
|
||||
private:
|
||||
static bool finishSavedFrameInit(JSContext *cx, HandleObject ctor, HandleObject proto);
|
||||
|
@ -221,44 +222,6 @@ class SavedStacks {
|
|||
|
||||
void sweepPCLocationMap();
|
||||
bool getLocation(JSContext *cx, const FrameIter &iter, MutableHandleLocationValue locationp);
|
||||
|
||||
struct FrameState
|
||||
{
|
||||
FrameState() : principals(nullptr), name(nullptr), location() { }
|
||||
explicit FrameState(const FrameIter &iter);
|
||||
FrameState(const FrameState &fs);
|
||||
|
||||
~FrameState();
|
||||
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
// Note: we don't have to hold/drop principals, because we're
|
||||
// only alive while the stack is being walked and during this
|
||||
// time the principals are kept alive by the stack itself.
|
||||
JSPrincipals *principals;
|
||||
JSAtom *name;
|
||||
LocationValue location;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS AutoFrameStateVector : public JS::CustomAutoRooter {
|
||||
public:
|
||||
explicit AutoFrameStateVector(JSContext *cx)
|
||||
: JS::CustomAutoRooter(cx),
|
||||
frames(cx)
|
||||
{ }
|
||||
|
||||
typedef Vector<FrameState, 20> FrameStateVector;
|
||||
inline FrameStateVector *operator->() { return &frames; }
|
||||
inline FrameState &operator[](size_t i) { return frames[i]; }
|
||||
|
||||
private:
|
||||
FrameStateVector frames;
|
||||
|
||||
virtual void trace(JSTracer *trc) {
|
||||
for (size_t i = 0; i < frames.length(); i++)
|
||||
frames[i].trace(trc);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
bool SavedStacksMetadataCallback(JSContext *cx, JSObject **pmetadata);
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.EnumSet;
|
||||
|
@ -114,6 +116,8 @@ import android.support.v4.app.Fragment;
|
|||
import android.support.v4.app.FragmentManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Base64;
|
||||
import android.util.Base64OutputStream;
|
||||
import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
|
@ -766,6 +770,7 @@ public class BrowserApp extends GeckoApp
|
|||
"Accounts:Create",
|
||||
"CharEncoding:Data",
|
||||
"CharEncoding:State",
|
||||
"Favicon:CacheLoad",
|
||||
"Feedback:LastUrl",
|
||||
"Feedback:MaybeLater",
|
||||
"Feedback:OpenPlayStore",
|
||||
|
@ -774,8 +779,7 @@ public class BrowserApp extends GeckoApp
|
|||
"Reader:Share",
|
||||
"Settings:Show",
|
||||
"Telemetry:Gather",
|
||||
"Updater:Launch",
|
||||
"BrowserToolbar:Visibility");
|
||||
"Updater:Launch");
|
||||
|
||||
Distribution distribution = Distribution.init(this);
|
||||
|
||||
|
@ -1309,6 +1313,7 @@ public class BrowserApp extends GeckoApp
|
|||
"Accounts:Create",
|
||||
"CharEncoding:Data",
|
||||
"CharEncoding:State",
|
||||
"Favicon:CacheLoad",
|
||||
"Feedback:LastUrl",
|
||||
"Feedback:MaybeLater",
|
||||
"Feedback:OpenPlayStore",
|
||||
|
@ -1317,8 +1322,7 @@ public class BrowserApp extends GeckoApp
|
|||
"Reader:Share",
|
||||
"Settings:Show",
|
||||
"Telemetry:Gather",
|
||||
"Updater:Launch",
|
||||
"BrowserToolbar:Visibility");
|
||||
"Updater:Launch");
|
||||
|
||||
if (AppConstants.MOZ_ANDROID_BEAM) {
|
||||
NfcAdapter nfc = NfcAdapter.getDefaultAdapter(this);
|
||||
|
@ -1534,17 +1538,6 @@ public class BrowserApp extends GeckoApp
|
|||
return (mTabsPanel != null && mTabsPanel.isSideBar());
|
||||
}
|
||||
|
||||
private void setBrowserToolbarVisible(final boolean visible) {
|
||||
ThreadUtils.postToUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mDynamicToolbar.isEnabled()) {
|
||||
mDynamicToolbar.setVisible(visible, VisibilityTransition.IMMEDIATE);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isSideBar() {
|
||||
return (HardwareUtils.isTablet() && getOrientation() == Configuration.ORIENTATION_LANDSCAPE);
|
||||
}
|
||||
|
@ -1634,6 +1627,10 @@ public class BrowserApp extends GeckoApp
|
|||
}
|
||||
});
|
||||
|
||||
} else if ("Favicon:CacheLoad".equals(event)) {
|
||||
final String url = message.getString("url");
|
||||
getFaviconFromCache(callback, url);
|
||||
|
||||
} else if ("Feedback:LastUrl".equals(event)) {
|
||||
getLastUrl(callback);
|
||||
|
||||
|
@ -1705,15 +1702,58 @@ public class BrowserApp extends GeckoApp
|
|||
}
|
||||
} else if ("Updater:Launch".equals(event)) {
|
||||
handleUpdaterLaunch();
|
||||
|
||||
} else if ("BrowserToolbar:Visibility".equals(event)) {
|
||||
setBrowserToolbarVisible(message.getBoolean("visible"));
|
||||
|
||||
} else {
|
||||
super.handleMessage(event, message, callback);
|
||||
}
|
||||
}
|
||||
|
||||
private void getFaviconFromCache(final EventCallback callback, final String url) {
|
||||
final OnFaviconLoadedListener listener = new OnFaviconLoadedListener() {
|
||||
@Override
|
||||
public void onFaviconLoaded(final String url, final String faviconURL, final Bitmap favicon) {
|
||||
ThreadUtils.assertOnUiThread();
|
||||
// Convert Bitmap to Base64 data URI in background.
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ByteArrayOutputStream out = null;
|
||||
Base64OutputStream b64 = null;
|
||||
|
||||
// Failed to load favicon from local.
|
||||
if (favicon == null) {
|
||||
callback.sendError("Failed to get favicon from cache");
|
||||
} else {
|
||||
try {
|
||||
out = new ByteArrayOutputStream();
|
||||
out.write("data:image/png;base64,".getBytes());
|
||||
b64 = new Base64OutputStream(out, Base64.NO_WRAP);
|
||||
favicon.compress(Bitmap.CompressFormat.PNG, 100, b64);
|
||||
callback.sendSuccess(new String(out.toByteArray()));
|
||||
} catch (IOException e) {
|
||||
Log.w(LOGTAG, "Failed to convert to base64 data URI");
|
||||
callback.sendError("Failed to convert favicon to a base64 data URI");
|
||||
} finally {
|
||||
try {
|
||||
if (out != null) {
|
||||
out.close();
|
||||
}
|
||||
if (b64 != null) {
|
||||
b64.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.w(LOGTAG, "Failed to close the streams");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
Favicons.getSizedFaviconForPageFromLocal(getContext(),
|
||||
url,
|
||||
listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a dummy Intent to do a default browser check.
|
||||
*
|
||||
|
|
|
@ -392,7 +392,7 @@ public abstract class GeckoApp
|
|||
onPreparePanel(featureId, mMenuPanel, mMenu);
|
||||
}
|
||||
|
||||
return mMenuPanel;
|
||||
return mMenuPanel;
|
||||
}
|
||||
|
||||
return super.onCreatePanelView(featureId);
|
||||
|
@ -505,7 +505,7 @@ public abstract class GeckoApp
|
|||
mMenuPanel.addView((GeckoMenu) mMenu);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
// Handle hardware menu key presses separately so that we can show a custom menu in some cases.
|
||||
|
@ -839,7 +839,11 @@ public abstract class GeckoApp
|
|||
|
||||
@Override
|
||||
public void onToastHidden(ButtonToast.ReasonHidden reason) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Toast:Hidden", buttonId));
|
||||
if (reason == ButtonToast.ReasonHidden.TIMEOUT ||
|
||||
reason == ButtonToast.ReasonHidden.TOUCH_OUTSIDE ||
|
||||
reason == ButtonToast.ReasonHidden.REPLACED) {
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Toast:Hidden", buttonId));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1059,7 +1063,7 @@ public abstract class GeckoApp
|
|||
public void requestRender() {
|
||||
mLayerView.requestRender();
|
||||
}
|
||||
|
||||
|
||||
public void hidePlugins(Tab tab) {
|
||||
for (Layer layer : tab.getPluginLayers()) {
|
||||
if (layer instanceof PluginLayer) {
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
import android.text.format.DateUtils;
|
||||
import org.mozilla.gecko.db.RemoteClient;
|
||||
import org.mozilla.gecko.db.RemoteTab;
|
||||
import org.mozilla.gecko.home.TwoLinePageRow;
|
||||
|
@ -20,6 +20,12 @@ import android.widget.BaseExpandableListAdapter;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An adapter that populates group and child views with remote client and tab
|
||||
* data maintained in a monolithic static array.
|
||||
|
@ -28,6 +34,15 @@ import android.widget.TextView;
|
|||
* specialization to home fragment styles.
|
||||
*/
|
||||
public class RemoteTabsExpandableListAdapter extends BaseExpandableListAdapter {
|
||||
/**
|
||||
* If a device claims to have synced before this date, we will assume it has never synced.
|
||||
*/
|
||||
private static final Date EARLIEST_VALID_SYNCED_DATE;
|
||||
static {
|
||||
final Calendar c = GregorianCalendar.getInstance();
|
||||
c.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
|
||||
EARLIEST_VALID_SYNCED_DATE = c.getTime();
|
||||
}
|
||||
protected final ArrayList<RemoteClient> clients;
|
||||
private final boolean showGroupIndicator;
|
||||
protected int groupLayoutId;
|
||||
|
@ -156,7 +171,7 @@ public class RemoteTabsExpandableListAdapter extends BaseExpandableListAdapter {
|
|||
// It's OK to access the DB on the main thread here, as we're just
|
||||
// getting a string.
|
||||
final GeckoProfile profile = GeckoProfile.get(context);
|
||||
holder.lastModifiedView.setText(profile.getDB().getTabsAccessor().getLastSyncedString(context, now, client.lastModified));
|
||||
holder.lastModifiedView.setText(this.getLastSyncedString(context, now, client.lastModified));
|
||||
|
||||
// These views exists only in some of our group views: they are present
|
||||
// for the home panel groups and not for the tabs panel groups.
|
||||
|
@ -215,4 +230,19 @@ public class RemoteTabsExpandableListAdapter extends BaseExpandableListAdapter {
|
|||
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a relative "Last synced" time span for the given tab record.
|
||||
*
|
||||
* @param now local time.
|
||||
* @param time to format string for.
|
||||
* @return string describing time span
|
||||
*/
|
||||
public String getLastSyncedString(Context context, long now, long time) {
|
||||
if (new Date(time).before(EARLIEST_VALID_SYNCED_DATE)) {
|
||||
return context.getString(R.string.remote_tabs_never_synced);
|
||||
}
|
||||
final CharSequence relativeTimeSpanString = DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
|
||||
return context.getResources().getString(R.string.remote_tabs_last_synced, relativeTimeSpanString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -798,7 +798,12 @@ sync_java_files = [
|
|||
'background/fxa/FxAccountClientException.java',
|
||||
'background/fxa/FxAccountRemoteError.java',
|
||||
'background/fxa/FxAccountUtils.java',
|
||||
'background/fxa/oauth/FxAccountAbstractClient.java',
|
||||
'background/fxa/oauth/FxAccountAbstractClientException.java',
|
||||
'background/fxa/oauth/FxAccountOAuthClient10.java',
|
||||
'background/fxa/oauth/FxAccountOAuthRemoteError.java',
|
||||
'background/fxa/PasswordStretcher.java',
|
||||
'background/fxa/profile/FxAccountProfileClient10.java',
|
||||
'background/fxa/QuickPasswordStretcher.java',
|
||||
'background/fxa/SkewHandler.java',
|
||||
'background/healthreport/AndroidConfigurationProvider.java',
|
||||
|
@ -835,7 +840,9 @@ sync_java_files = [
|
|||
'browserid/MockMyIDTokenFactory.java',
|
||||
'browserid/RSACryptoImplementation.java',
|
||||
'browserid/SigningPrivateKey.java',
|
||||
'browserid/verifier/BrowserIDRemoteVerifierClient.java',
|
||||
'browserid/verifier/AbstractBrowserIDRemoteVerifierClient.java',
|
||||
'browserid/verifier/BrowserIDRemoteVerifierClient10.java',
|
||||
'browserid/verifier/BrowserIDRemoteVerifierClient20.java',
|
||||
'browserid/verifier/BrowserIDVerifierClient.java',
|
||||
'browserid/verifier/BrowserIDVerifierDelegate.java',
|
||||
'browserid/verifier/BrowserIDVerifierException.java',
|
||||
|
@ -962,10 +969,12 @@ sync_java_files = [
|
|||
'sync/middleware/MiddlewareRepository.java',
|
||||
'sync/middleware/MiddlewareRepositorySession.java',
|
||||
'sync/MigrationSentinelSyncStage.java',
|
||||
'sync/net/AbstractBearerTokenAuthHeaderProvider.java',
|
||||
'sync/net/AuthHeaderProvider.java',
|
||||
'sync/net/BaseResource.java',
|
||||
'sync/net/BaseResourceDelegate.java',
|
||||
'sync/net/BasicAuthHeaderProvider.java',
|
||||
'sync/net/BearerAuthHeaderProvider.java',
|
||||
'sync/net/BrowserIDAuthHeaderProvider.java',
|
||||
'sync/net/ConnectionMonitorThread.java',
|
||||
'sync/net/HandleProgressException.java',
|
||||
|
|
|
@ -0,0 +1,225 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.background.fxa.oauth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.mozilla.gecko.background.fxa.FxAccountClientException;
|
||||
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientMalformedResponseException;
|
||||
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException.FxAccountAbstractClientRemoteException;
|
||||
import org.mozilla.gecko.fxa.FxAccountConstants;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.net.AuthHeaderProvider;
|
||||
import org.mozilla.gecko.sync.net.BaseResource;
|
||||
import org.mozilla.gecko.sync.net.BaseResourceDelegate;
|
||||
import org.mozilla.gecko.sync.net.Resource;
|
||||
import org.mozilla.gecko.sync.net.SyncResponse;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageResponse;
|
||||
|
||||
import ch.boye.httpclientandroidlib.HttpEntity;
|
||||
import ch.boye.httpclientandroidlib.HttpHeaders;
|
||||
import ch.boye.httpclientandroidlib.HttpResponse;
|
||||
import ch.boye.httpclientandroidlib.client.ClientProtocolException;
|
||||
import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
|
||||
import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
|
||||
|
||||
public abstract class FxAccountAbstractClient {
|
||||
protected static final String LOG_TAG = FxAccountAbstractClient.class.getSimpleName();
|
||||
|
||||
protected static final String ACCEPT_HEADER = "application/json;charset=utf-8";
|
||||
protected static final String AUTHORIZATION_RESPONSE_TYPE = "token";
|
||||
|
||||
public static final String JSON_KEY_ERROR = "error";
|
||||
public static final String JSON_KEY_MESSAGE = "message";
|
||||
public static final String JSON_KEY_CODE = "code";
|
||||
public static final String JSON_KEY_ERRNO = "errno";
|
||||
|
||||
protected static final String[] requiredErrorStringFields = { JSON_KEY_ERROR, JSON_KEY_MESSAGE };
|
||||
protected static final String[] requiredErrorLongFields = { JSON_KEY_CODE, JSON_KEY_ERRNO };
|
||||
|
||||
/**
|
||||
* The server's URI.
|
||||
* <p>
|
||||
* We assume throughout that this ends with a trailing slash (and guarantee as
|
||||
* much in the constructor).
|
||||
*/
|
||||
protected final String serverURI;
|
||||
|
||||
protected final Executor executor;
|
||||
|
||||
public FxAccountAbstractClient(String serverURI, Executor executor) {
|
||||
if (serverURI == null) {
|
||||
throw new IllegalArgumentException("Must provide a server URI.");
|
||||
}
|
||||
if (executor == null) {
|
||||
throw new IllegalArgumentException("Must provide a non-null executor.");
|
||||
}
|
||||
this.serverURI = serverURI.endsWith("/") ? serverURI : serverURI + "/";
|
||||
if (!this.serverURI.endsWith("/")) {
|
||||
throw new IllegalArgumentException("Constructed serverURI must end with a trailing slash: " + this.serverURI);
|
||||
}
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a typed value extracted from a successful response (in an
|
||||
* endpoint-dependent way).
|
||||
*/
|
||||
public interface RequestDelegate<T> {
|
||||
public void handleError(Exception e);
|
||||
public void handleFailure(FxAccountAbstractClientRemoteException e);
|
||||
public void handleSuccess(T result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intepret a response from the auth server.
|
||||
* <p>
|
||||
* Throw an appropriate exception on errors; otherwise, return the response's
|
||||
* status code.
|
||||
*
|
||||
* @return response's HTTP status code.
|
||||
* @throws FxAccountClientException
|
||||
*/
|
||||
public static int validateResponse(HttpResponse response) throws FxAccountAbstractClientRemoteException {
|
||||
final int status = response.getStatusLine().getStatusCode();
|
||||
if (status == 200) {
|
||||
return status;
|
||||
}
|
||||
int code;
|
||||
int errno;
|
||||
String error;
|
||||
String message;
|
||||
ExtendedJSONObject body;
|
||||
try {
|
||||
body = new SyncStorageResponse(response).jsonObjectBody();
|
||||
body.throwIfFieldsMissingOrMisTyped(requiredErrorStringFields, String.class);
|
||||
body.throwIfFieldsMissingOrMisTyped(requiredErrorLongFields, Long.class);
|
||||
code = body.getLong(JSON_KEY_CODE).intValue();
|
||||
errno = body.getLong(JSON_KEY_ERRNO).intValue();
|
||||
error = body.getString(JSON_KEY_ERROR);
|
||||
message = body.getString(JSON_KEY_MESSAGE);
|
||||
} catch (Exception e) {
|
||||
throw new FxAccountAbstractClientMalformedResponseException(response);
|
||||
}
|
||||
throw new FxAccountAbstractClientRemoteException(response, code, errno, error, message, body);
|
||||
}
|
||||
|
||||
protected <T> void invokeHandleError(final RequestDelegate<T> delegate, final Exception e) {
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.handleError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected <T> void post(BaseResource resource, final ExtendedJSONObject requestBody, final RequestDelegate<T> delegate) {
|
||||
try {
|
||||
if (requestBody == null) {
|
||||
resource.post((HttpEntity) null);
|
||||
} else {
|
||||
resource.post(requestBody);
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
invokeHandleError(delegate, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate resource callbacks into request callbacks invoked on the provided
|
||||
* executor.
|
||||
* <p>
|
||||
* Override <code>handleSuccess</code> to parse the body of the resource
|
||||
* request and call the request callback. <code>handleSuccess</code> is
|
||||
* invoked via the executor, so you don't need to delegate further.
|
||||
*/
|
||||
protected abstract class ResourceDelegate<T> extends BaseResourceDelegate {
|
||||
protected abstract void handleSuccess(final int status, HttpResponse response, final ExtendedJSONObject body);
|
||||
|
||||
protected final RequestDelegate<T> delegate;
|
||||
|
||||
/**
|
||||
* Create a delegate for an un-authenticated resource.
|
||||
*/
|
||||
public ResourceDelegate(final Resource resource, final RequestDelegate<T> delegate) {
|
||||
super(resource);
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthHeaderProvider getAuthHeaderProvider() {
|
||||
return super.getAuthHeaderProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserAgent() {
|
||||
return FxAccountConstants.USER_AGENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleHttpResponse(HttpResponse response) {
|
||||
try {
|
||||
final int status = validateResponse(response);
|
||||
invokeHandleSuccess(status, response);
|
||||
} catch (FxAccountAbstractClientRemoteException e) {
|
||||
invokeHandleFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected void invokeHandleFailure(final FxAccountAbstractClientRemoteException e) {
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
delegate.handleFailure(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void invokeHandleSuccess(final int status, final HttpResponse response) {
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ExtendedJSONObject body = new SyncResponse(response).jsonObjectBody();
|
||||
ResourceDelegate.this.handleSuccess(status, response, body);
|
||||
} catch (Exception e) {
|
||||
delegate.handleError(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleHttpProtocolException(final ClientProtocolException e) {
|
||||
invokeHandleError(delegate, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleHttpIOException(IOException e) {
|
||||
invokeHandleError(delegate, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportException(GeneralSecurityException e) {
|
||||
invokeHandleError(delegate, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addHeaders(HttpRequestBase request, DefaultHttpClient client) {
|
||||
super.addHeaders(request, client);
|
||||
|
||||
// The basics.
|
||||
final Locale locale = Locale.getDefault();
|
||||
request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, Utils.getLanguageTag(locale));
|
||||
request.addHeader(HttpHeaders.ACCEPT, ACCEPT_HEADER);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.background.fxa.oauth;
|
||||
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.HTTPFailureException;
|
||||
import org.mozilla.gecko.sync.net.SyncStorageResponse;
|
||||
|
||||
import ch.boye.httpclientandroidlib.HttpResponse;
|
||||
|
||||
/**
|
||||
* From <a href="https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md">https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md</a>.
|
||||
*/
|
||||
public class FxAccountAbstractClientException extends Exception {
|
||||
private static final long serialVersionUID = 1953459541558266597L;
|
||||
|
||||
public FxAccountAbstractClientException(String detailMessage) {
|
||||
super(detailMessage);
|
||||
}
|
||||
|
||||
public FxAccountAbstractClientException(Exception e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public static class FxAccountAbstractClientRemoteException extends FxAccountAbstractClientException {
|
||||
private static final long serialVersionUID = 1209313149952001097L;
|
||||
|
||||
public final HttpResponse response;
|
||||
public final long httpStatusCode;
|
||||
public final long apiErrorNumber;
|
||||
public final String error;
|
||||
public final String message;
|
||||
public final ExtendedJSONObject body;
|
||||
|
||||
public FxAccountAbstractClientRemoteException(HttpResponse response, long httpStatusCode, long apiErrorNumber, String error, String message, ExtendedJSONObject body) {
|
||||
super(new HTTPFailureException(new SyncStorageResponse(response)));
|
||||
if (body == null) {
|
||||
throw new IllegalArgumentException("body must not be null");
|
||||
}
|
||||
this.response = response;
|
||||
this.httpStatusCode = httpStatusCode;
|
||||
this.apiErrorNumber = apiErrorNumber;
|
||||
this.error = error;
|
||||
this.message = message;
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "<FxAccountAbstractClientRemoteException " + this.httpStatusCode + " [" + this.apiErrorNumber + "]: " + this.message + ">";
|
||||
}
|
||||
}
|
||||
|
||||
public static class FxAccountAbstractClientMalformedResponseException extends FxAccountAbstractClientRemoteException {
|
||||
private static final long serialVersionUID = 1209313149952001098L;
|
||||
|
||||
public FxAccountAbstractClientMalformedResponseException(HttpResponse response) {
|
||||
super(response, 0, FxAccountOAuthRemoteError.UNKNOWN_ERROR, "Response malformed", "Response malformed", new ExtendedJSONObject());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.background.fxa.oauth;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.net.BaseResource;
|
||||
|
||||
import ch.boye.httpclientandroidlib.HttpResponse;
|
||||
|
||||
/**
|
||||
* Talk to an fxa-oauth-server to get "implicitly granted" OAuth tokens.
|
||||
* <p>
|
||||
* To use this client, you will need a pre-allocated fxa-oauth-server
|
||||
* "client_id" with special "implicit grant" permissions.
|
||||
* <p>
|
||||
* This client was written against the API documented at <a href="https://github.com/mozilla/fxa-oauth-server/blob/41538990df9e91158558ae5a8115194383ac3b05/docs/api.md">https://github.com/mozilla/fxa-oauth-server/blob/41538990df9e91158558ae5a8115194383ac3b05/docs/api.md</a>.
|
||||
*/
|
||||
public class FxAccountOAuthClient10 extends FxAccountAbstractClient {
|
||||
protected static final String LOG_TAG = FxAccountOAuthClient10.class.getSimpleName();
|
||||
|
||||
protected static final String AUTHORIZATION_RESPONSE_TYPE = "token";
|
||||
|
||||
protected static final String JSON_KEY_ACCESS_TOKEN = "access_token";
|
||||
protected static final String JSON_KEY_ASSERTION = "assertion";
|
||||
protected static final String JSON_KEY_CLIENT_ID = "client_id";
|
||||
protected static final String JSON_KEY_RESPONSE_TYPE = "response_type";
|
||||
protected static final String JSON_KEY_SCOPE = "scope";
|
||||
protected static final String JSON_KEY_STATE = "state";
|
||||
protected static final String JSON_KEY_TOKEN_TYPE = "token_type";
|
||||
|
||||
// access_token: A string that can be used for authorized requests to service providers.
|
||||
// scope: A string of space-separated permissions that this token has. May differ from requested scopes, since user can deny permissions.
|
||||
// token_type: A string representing the token type. Currently will always be "bearer".
|
||||
protected static final String[] AUTHORIZATION_RESPONSE_REQUIRED_STRING_FIELDS = new String[] { JSON_KEY_ACCESS_TOKEN, JSON_KEY_SCOPE, JSON_KEY_TOKEN_TYPE };
|
||||
|
||||
public FxAccountOAuthClient10(String serverURI, Executor executor) {
|
||||
super(serverURI, executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Thin container for an authorization response.
|
||||
*/
|
||||
public static class AuthorizationResponse {
|
||||
public final String access_token;
|
||||
public final String token_type;
|
||||
public final String scope;
|
||||
|
||||
public AuthorizationResponse(String access_token, String token_type, String scope) {
|
||||
this.access_token = access_token;
|
||||
this.token_type = token_type;
|
||||
this.scope = scope;
|
||||
}
|
||||
}
|
||||
|
||||
public void authorization(String client_id, String assertion, String state, String scope,
|
||||
RequestDelegate<AuthorizationResponse> delegate) {
|
||||
final BaseResource resource;
|
||||
try {
|
||||
resource = new BaseResource(new URI(serverURI + "authorization"));
|
||||
} catch (URISyntaxException e) {
|
||||
invokeHandleError(delegate, e);
|
||||
return;
|
||||
}
|
||||
|
||||
resource.delegate = new ResourceDelegate<AuthorizationResponse>(resource, delegate) {
|
||||
@Override
|
||||
public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
|
||||
try {
|
||||
body.throwIfFieldsMissingOrMisTyped(AUTHORIZATION_RESPONSE_REQUIRED_STRING_FIELDS, String.class);
|
||||
String access_token = body.getString(JSON_KEY_ACCESS_TOKEN);
|
||||
String token_type = body.getString(JSON_KEY_TOKEN_TYPE);
|
||||
String scope = body.getString(JSON_KEY_SCOPE);
|
||||
delegate.handleSuccess(new AuthorizationResponse(access_token, token_type, scope));
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
delegate.handleError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
final ExtendedJSONObject requestBody = new ExtendedJSONObject();
|
||||
requestBody.put(JSON_KEY_RESPONSE_TYPE, AUTHORIZATION_RESPONSE_TYPE);
|
||||
requestBody.put(JSON_KEY_CLIENT_ID, client_id);
|
||||
requestBody.put(JSON_KEY_ASSERTION, assertion);
|
||||
if (scope != null) {
|
||||
requestBody.put(JSON_KEY_SCOPE, scope);
|
||||
}
|
||||
if (state != null) {
|
||||
requestBody.put(JSON_KEY_STATE, state);
|
||||
}
|
||||
|
||||
post(resource, requestBody, delegate);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.background.fxa.oauth;
|
||||
|
||||
public interface FxAccountOAuthRemoteError {
|
||||
public static final int ATTEMPT_TO_CREATE_AN_ACCOUNT_THAT_ALREADY_EXISTS = 101;
|
||||
public static final int UNKNOWN_CLIENT_ID = 101;
|
||||
public static final int INCORRECT_CLIENT_SECRET = 102;
|
||||
public static final int REDIRECT_URI_DOES_NOT_MATCH_REGISTERED_VALUE = 103;
|
||||
public static final int INVALID_FXA_ASSERTION = 104;
|
||||
public static final int UNKNOWN_CODE = 105;
|
||||
public static final int INCORRECT_CODE = 106;
|
||||
public static final int EXPIRED_CODE = 107;
|
||||
public static final int INVALID_TOKEN = 108;
|
||||
public static final int INVALID_REQUEST_PARAMETER = 109;
|
||||
public static final int UNKNOWN_ERROR = 999;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.background.fxa.profile;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClient;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.net.AuthHeaderProvider;
|
||||
import org.mozilla.gecko.sync.net.BaseResource;
|
||||
import org.mozilla.gecko.sync.net.BearerAuthHeaderProvider;
|
||||
|
||||
import ch.boye.httpclientandroidlib.HttpResponse;
|
||||
|
||||
|
||||
/**
|
||||
* Talk to an fxa-profile-server to get profile information like name, age, gender, and avatar image.
|
||||
* <p>
|
||||
* This client was written against the API documented at <a href="https://github.com/mozilla/fxa-profile-server/blob/0c065619f5a2e867f813a343b4c67da3fe2c82a4/docs/API.md">https://github.com/mozilla/fxa-profile-server/blob/0c065619f5a2e867f813a343b4c67da3fe2c82a4/docs/API.md</a>.
|
||||
*/
|
||||
public class FxAccountProfileClient10 extends FxAccountAbstractClient {
|
||||
public FxAccountProfileClient10(String serverURI, Executor executor) {
|
||||
super(serverURI, executor);
|
||||
}
|
||||
|
||||
public void profile(final String token, RequestDelegate<ExtendedJSONObject> delegate) {
|
||||
BaseResource resource;
|
||||
try {
|
||||
resource = new BaseResource(new URI(serverURI + "profile"));
|
||||
} catch (URISyntaxException e) {
|
||||
invokeHandleError(delegate, e);
|
||||
return;
|
||||
}
|
||||
|
||||
resource.delegate = new ResourceDelegate<ExtendedJSONObject>(resource, delegate) {
|
||||
@Override
|
||||
public AuthHeaderProvider getAuthHeaderProvider() {
|
||||
return new BearerAuthHeaderProvider(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleSuccess(int status, HttpResponse response, ExtendedJSONObject body) {
|
||||
try {
|
||||
delegate.handleSuccess(body);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
delegate.handleError(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
resource.get();
|
||||
}
|
||||
}
|
|
@ -186,8 +186,8 @@ public class JSONWebTokenUtils {
|
|||
System.out.println("Malformed certificate -- got exception trying to dump contents.");
|
||||
return false;
|
||||
}
|
||||
System.out.println("certificate header: " + c.getString("header"));
|
||||
System.out.println("certificate payload: " + c.getString("payload"));
|
||||
System.out.println("certificate header: " + c.getObject("header").toJSONString());
|
||||
System.out.println("certificate payload: " + c.getObject("payload").toJSONString());
|
||||
System.out.println("certificate signature: " + c.getString("signature"));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
|
@ -244,8 +244,8 @@ public class JSONWebTokenUtils {
|
|||
return false;
|
||||
}
|
||||
dumpCertificate(a.getString("certificate"));
|
||||
System.out.println("assertion header: " + a.getString("header"));
|
||||
System.out.println("assertion payload: " + a.getString("payload"));
|
||||
System.out.println("assertion header: " + a.getObject("header").toJSONString());
|
||||
System.out.println("assertion payload: " + a.getObject("payload").toJSONString());
|
||||
System.out.println("assertion signature: " + a.getString("signature"));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -5,29 +5,23 @@
|
|||
package org.mozilla.gecko.browserid.verifier;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.mozilla.gecko.background.common.log.Logger;
|
||||
import org.mozilla.gecko.browserid.verifier.BrowserIDVerifierException.BrowserIDVerifierErrorResponseException;
|
||||
import org.mozilla.gecko.browserid.verifier.BrowserIDVerifierException.BrowserIDVerifierMalformedResponseException;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.net.BaseResource;
|
||||
import org.mozilla.gecko.sync.net.BaseResourceDelegate;
|
||||
import org.mozilla.gecko.sync.net.Resource;
|
||||
import org.mozilla.gecko.sync.net.SyncResponse;
|
||||
|
||||
import ch.boye.httpclientandroidlib.HttpResponse;
|
||||
import ch.boye.httpclientandroidlib.NameValuePair;
|
||||
import ch.boye.httpclientandroidlib.client.ClientProtocolException;
|
||||
import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity;
|
||||
import ch.boye.httpclientandroidlib.message.BasicNameValuePair;
|
||||
|
||||
public class BrowserIDRemoteVerifierClient implements BrowserIDVerifierClient {
|
||||
public abstract class AbstractBrowserIDRemoteVerifierClient implements BrowserIDVerifierClient {
|
||||
public static final String LOG_TAG = AbstractBrowserIDRemoteVerifierClient.class.getSimpleName();
|
||||
|
||||
protected static class RemoteVerifierResourceDelegate extends BaseResourceDelegate {
|
||||
private final BrowserIDVerifierDelegate delegate;
|
||||
|
||||
|
@ -93,44 +87,9 @@ public class BrowserIDRemoteVerifierClient implements BrowserIDVerifierClient {
|
|||
}
|
||||
}
|
||||
|
||||
public static final String LOG_TAG = "BrowserIDRemoteVerifierClient";
|
||||
|
||||
public static final String DEFAULT_VERIFIER_URL = "https://verifier.login.persona.org/verify";
|
||||
|
||||
protected final URI verifierUri;
|
||||
|
||||
public BrowserIDRemoteVerifierClient(URI verifierUri) {
|
||||
public AbstractBrowserIDRemoteVerifierClient(URI verifierUri) {
|
||||
this.verifierUri = verifierUri;
|
||||
}
|
||||
|
||||
public BrowserIDRemoteVerifierClient() throws URISyntaxException {
|
||||
this.verifierUri = new URI(DEFAULT_VERIFIER_URL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify(String audience, String assertion, final BrowserIDVerifierDelegate delegate) {
|
||||
if (audience == null) {
|
||||
throw new IllegalArgumentException("audience cannot be null.");
|
||||
}
|
||||
if (assertion == null) {
|
||||
throw new IllegalArgumentException("assertion cannot be null.");
|
||||
}
|
||||
if (delegate == null) {
|
||||
throw new IllegalArgumentException("delegate cannot be null.");
|
||||
}
|
||||
|
||||
BaseResource r = new BaseResource(verifierUri);
|
||||
|
||||
r.delegate = new RemoteVerifierResourceDelegate(r, delegate);
|
||||
|
||||
List<NameValuePair> nvps = Arrays.asList(new NameValuePair[] {
|
||||
new BasicNameValuePair("audience", audience),
|
||||
new BasicNameValuePair("assertion", assertion) });
|
||||
|
||||
try {
|
||||
r.post(new UrlEncodedFormEntity(nvps, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
delegate.handleError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.browserid.verifier;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.mozilla.gecko.sync.net.BaseResource;
|
||||
|
||||
import ch.boye.httpclientandroidlib.NameValuePair;
|
||||
import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity;
|
||||
import ch.boye.httpclientandroidlib.message.BasicNameValuePair;
|
||||
|
||||
/**
|
||||
* The verifier protocol changed: version 1 posts form-encoded data; version 2
|
||||
* posts JSON data.
|
||||
*/
|
||||
public class BrowserIDRemoteVerifierClient10 extends AbstractBrowserIDRemoteVerifierClient {
|
||||
public static final String LOG_TAG = BrowserIDRemoteVerifierClient10.class.getSimpleName();
|
||||
|
||||
public static final String DEFAULT_VERIFIER_URL = "https://verifier.login.persona.org/verify";
|
||||
|
||||
public BrowserIDRemoteVerifierClient10() throws URISyntaxException {
|
||||
super(new URI(DEFAULT_VERIFIER_URL));
|
||||
}
|
||||
|
||||
public BrowserIDRemoteVerifierClient10(URI verifierUri) {
|
||||
super(verifierUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify(String audience, String assertion, final BrowserIDVerifierDelegate delegate) {
|
||||
if (audience == null) {
|
||||
throw new IllegalArgumentException("audience cannot be null.");
|
||||
}
|
||||
if (assertion == null) {
|
||||
throw new IllegalArgumentException("assertion cannot be null.");
|
||||
}
|
||||
if (delegate == null) {
|
||||
throw new IllegalArgumentException("delegate cannot be null.");
|
||||
}
|
||||
|
||||
BaseResource r = new BaseResource(verifierUri);
|
||||
|
||||
r.delegate = new RemoteVerifierResourceDelegate(r, delegate);
|
||||
|
||||
List<NameValuePair> nvps = Arrays.asList(new NameValuePair[] {
|
||||
new BasicNameValuePair("audience", audience),
|
||||
new BasicNameValuePair("assertion", assertion) });
|
||||
|
||||
try {
|
||||
r.post(new UrlEncodedFormEntity(nvps, "UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
delegate.handleError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.browserid.verifier;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.net.BaseResource;
|
||||
|
||||
/**
|
||||
* The verifier protocol changed: version 1 posts form-encoded data; version 2
|
||||
* posts JSON data.
|
||||
*/
|
||||
public class BrowserIDRemoteVerifierClient20 extends AbstractBrowserIDRemoteVerifierClient {
|
||||
public static final String LOG_TAG = BrowserIDRemoteVerifierClient20.class.getSimpleName();
|
||||
|
||||
public static final String DEFAULT_VERIFIER_URL = "https://verifier.accounts.firefox.com/v2";
|
||||
|
||||
protected static final String JSON_KEY_ASSERTION = "assertion";
|
||||
protected static final String JSON_KEY_AUDIENCE = "audience";
|
||||
|
||||
public BrowserIDRemoteVerifierClient20() throws URISyntaxException {
|
||||
super(new URI(DEFAULT_VERIFIER_URL));
|
||||
}
|
||||
|
||||
public BrowserIDRemoteVerifierClient20(URI verifierUri) {
|
||||
super(verifierUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void verify(String audience, String assertion, final BrowserIDVerifierDelegate delegate) {
|
||||
if (audience == null) {
|
||||
throw new IllegalArgumentException("audience cannot be null.");
|
||||
}
|
||||
if (assertion == null) {
|
||||
throw new IllegalArgumentException("assertion cannot be null.");
|
||||
}
|
||||
if (delegate == null) {
|
||||
throw new IllegalArgumentException("delegate cannot be null.");
|
||||
}
|
||||
|
||||
BaseResource r = new BaseResource(verifierUri);
|
||||
r.delegate = new RemoteVerifierResourceDelegate(r, delegate);
|
||||
|
||||
final ExtendedJSONObject requestBody = new ExtendedJSONObject();
|
||||
requestBody.put(JSON_KEY_AUDIENCE, audience);
|
||||
requestBody.put(JSON_KEY_ASSERTION, assertion);
|
||||
|
||||
try {
|
||||
r.post(requestBody);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
delegate.handleError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -259,17 +259,4 @@ public class LocalTabsAccessor implements TabsAccessor {
|
|||
private boolean isFilteredURL(String url) {
|
||||
return FILTERED_URL_PATTERN.matcher(url).lookingAt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a relative "Last synced" time span for the given tab record.
|
||||
*
|
||||
* @param now local time.
|
||||
* @param time to format string for.
|
||||
* @return string describing time span
|
||||
*/
|
||||
@Override
|
||||
public String getLastSyncedString(Context context, long now, long time) {
|
||||
final CharSequence relativeTimeSpanString = DateUtils.getRelativeTimeSpanString(time, now, DateUtils.MINUTE_IN_MILLIS);
|
||||
return context.getResources().getString(R.string.remote_tabs_last_synced, relativeTimeSpanString);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,10 +119,6 @@ class StubTabsAccessor implements TabsAccessor {
|
|||
}
|
||||
|
||||
public synchronized void persistLocalTabs(final ContentResolver cr, final Iterable<Tab> tabs) { }
|
||||
|
||||
public String getLastSyncedString(Context context, long now, long time) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -23,5 +23,4 @@ public interface TabsAccessor {
|
|||
public void getTabs(final Context context, final OnQueryTabsCompleteListener listener);
|
||||
public void getTabs(final Context context, final int limit, final OnQueryTabsCompleteListener listener);
|
||||
public void persistLocalTabs(final ContentResolver cr, final Iterable<Tab> tabs);
|
||||
public String getLastSyncedString(Context context, long now, long time);
|
||||
}
|
||||
|
|
|
@ -51,10 +51,6 @@ class JavaPanZoomController
|
|||
// Animation stops is the velocity is below this threshold when flinging.
|
||||
private static final float FLING_STOPPED_THRESHOLD = 0.1f;
|
||||
|
||||
// The distance the user has to pan before we recognize it as such (e.g. to avoid 1-pixel pans
|
||||
// between the touch-down and touch-up of a click). In units of density-independent pixels.
|
||||
public static final float PAN_THRESHOLD = 1/16f * GeckoAppShell.getDpi();
|
||||
|
||||
// Angle from axis within which we stay axis-locked
|
||||
private static final double AXIS_LOCK_ANGLE = Math.PI / 6.0; // 30 degrees
|
||||
|
||||
|
@ -479,7 +475,7 @@ class JavaPanZoomController
|
|||
if (mTarget.getFullScreenState() == FullScreenState.NON_ROOT_ELEMENT && !mSubscroller.scrolling()) {
|
||||
return false;
|
||||
}
|
||||
if (panDistance(event) < PAN_THRESHOLD) {
|
||||
if (panDistance(event) < PanZoomController.PAN_THRESHOLD) {
|
||||
return false;
|
||||
}
|
||||
cancelTouch();
|
||||
|
|
|
@ -36,7 +36,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
|
|||
private static final String LOGTAG = "GeckoHomeConfigBackend";
|
||||
|
||||
// Increment this to trigger a migration.
|
||||
private static final int VERSION = 2;
|
||||
private static final int VERSION = 3;
|
||||
|
||||
// This key was originally used to store only an array of panel configs.
|
||||
private static final String PREFS_CONFIG_KEY_OLD = "home_panels";
|
||||
|
@ -73,12 +73,7 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
|
|||
EnumSet.of(PanelConfig.Flags.DEFAULT_PANEL)));
|
||||
|
||||
panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.BOOKMARKS));
|
||||
|
||||
// We disable reader mode support on low memory devices. Hence the
|
||||
// reading list panel should not show up on such devices.
|
||||
if (!HardwareUtils.isLowMemoryPlatform()) {
|
||||
panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.READING_LIST));
|
||||
}
|
||||
panelConfigs.add(createBuiltinPanelConfig(mContext, PanelType.READING_LIST));
|
||||
|
||||
final PanelConfig historyEntry = createBuiltinPanelConfig(mContext, PanelType.HISTORY);
|
||||
final PanelConfig recentTabsEntry = createBuiltinPanelConfig(mContext, PanelType.RECENT_TABS);
|
||||
|
@ -173,6 +168,31 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the reading list panel already exists.
|
||||
*
|
||||
* @param jsonPanels JSONArray array representing the curent set of panel configs.
|
||||
*
|
||||
* @return boolean Whether or not the reading list panel exists.
|
||||
*/
|
||||
private static boolean readingListPanelExists(JSONArray jsonPanels) {
|
||||
final int count = jsonPanels.length();
|
||||
for (int i = 0; i < count; i++) {
|
||||
try {
|
||||
final JSONObject jsonPanelConfig = jsonPanels.getJSONObject(i);
|
||||
final PanelConfig panelConfig = new PanelConfig(jsonPanelConfig);
|
||||
if (panelConfig.getType() == PanelType.READING_LIST) {
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// It's okay to ignore this exception, since an invalid reading list
|
||||
// panel config is equivalent to no reading list panel.
|
||||
Log.e(LOGTAG, "Exception loading PanelConfig from JSON", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrates JSON config data storage.
|
||||
*
|
||||
|
@ -231,6 +251,19 @@ class HomeConfigPrefsBackend implements HomeConfigBackend {
|
|||
addBuiltinPanelConfig(context, jsonPanels,
|
||||
PanelType.REMOTE_TABS, Position.FRONT, Position.BACK);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// Add the "Reading List" panel if it does not exist. At one time,
|
||||
// the Reading List panel was shown only to devices that were not
|
||||
// considered "low memory". Now, we expose the panel to all devices.
|
||||
// This migration should only occur for "low memory" devices.
|
||||
// Note: This will not agree with the default configuration, which
|
||||
// has REMOTE_TABS after READING_LIST on some devices.
|
||||
if (!readingListPanelExists(jsonPanels)) {
|
||||
addBuiltinPanelConfig(context, jsonPanels,
|
||||
PanelType.READING_LIST, Position.BACK, Position.BACK);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<!ENTITY no_space_to_start_error "There is not enough space available for &brandShortName; to start.">
|
||||
<!ENTITY error_loading_file "An error occurred when trying to load files required to run &brandShortName;">
|
||||
|
||||
<!ENTITY onboard_start_message "Welcome to &brandShortName;!">
|
||||
<!ENTITY onboard_start_subtext "Committed to you, your privacy, and an Open Web">
|
||||
<!ENTITY onboard_start_message2 "Welcome to &brandShortName;">
|
||||
<!ENTITY onboard_start_subtext2 "More privacy features and ways to customize than ever.">
|
||||
<!ENTITY onboard_start_button_account "Sign in to &brandShortName;">
|
||||
<!ENTITY onboard_start_button_browser "Start Browsing">
|
||||
|
||||
|
@ -575,6 +575,8 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
|||
"Last synced" is one of the user's other Sync clients, typically Firefox on
|
||||
their desktop or laptop.-->
|
||||
<!ENTITY remote_tabs_last_synced "Last synced: &formatS;">
|
||||
<!-- Localization note: Used when the sync has not happend yet, showed in place of a date -->
|
||||
<!ENTITY remote_tabs_never_synced "Last synced: never">
|
||||
|
||||
<!-- Find-In-Page strings -->
|
||||
<!-- LOCALIZATION NOTE (find_matchcase): This is meant to appear as an icon that changes color
|
||||
|
|
|
@ -669,9 +669,10 @@ if not CONFIG['MOZILLA_OFFICIAL']:
|
|||
'org/lucasr/dspec/RawResource.java'
|
||||
] ]
|
||||
|
||||
# Putting branding earlier allows branders to override default resources.
|
||||
ANDROID_RES_DIRS += [
|
||||
SRCDIR + '/resources',
|
||||
TOPSRCDIR + '/' + CONFIG['MOZ_BRANDING_DIRECTORY'] + '/res',
|
||||
SRCDIR + '/resources',
|
||||
OBJDIR + '/res',
|
||||
]
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import org.mozilla.gecko.overlays.service.sharemethods.SendTab;
|
|||
import org.mozilla.gecko.overlays.service.sharemethods.ShareMethod;
|
||||
import org.mozilla.gecko.sync.setup.activities.WebURLFinder;
|
||||
import org.mozilla.gecko.mozglue.ContextUtils;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.UIAsyncTask;
|
||||
|
||||
|
@ -214,14 +213,8 @@ public class ShareDialog extends Locales.LocaleAwareActivity implements SendTabT
|
|||
sendTabList.setAdapter(adapter);
|
||||
sendTabList.setSendTabTargetSelectedListener(this);
|
||||
|
||||
// If we're a low memory device, just hide the reading list button. Otherwise, configure it.
|
||||
final OverlayDialogButton readinglistBtn = (OverlayDialogButton) findViewById(R.id.overlay_share_reading_list_btn);
|
||||
|
||||
if (HardwareUtils.isLowMemoryPlatform()) {
|
||||
readinglistBtn.setVisibility(View.GONE);
|
||||
return;
|
||||
}
|
||||
|
||||
final String readingListEnabledLabel = resources.getString(R.string.overlay_share_reading_list_btn_label);
|
||||
final Drawable readingListEnabledIcon = resources.getDrawable(R.drawable.overlay_readinglist_icon);
|
||||
readinglistBtn.setEnabledLabelAndIcon(readingListEnabledLabel, readingListEnabledIcon);
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
<string name="no_space_to_start_error">&no_space_to_start_error;</string>
|
||||
<string name="error_loading_file">&error_loading_file;</string>
|
||||
|
||||
<string name="firstrun_welcome_message">&onboard_start_message;</string>
|
||||
<string name="firstrun_welcome_subtext">&onboard_start_subtext;</string>
|
||||
<string name="firstrun_welcome_message">&onboard_start_message2;</string>
|
||||
<string name="firstrun_welcome_subtext">&onboard_start_subtext2;</string>
|
||||
<string name="firstrun_welcome_button_account">&onboard_start_button_account;</string>
|
||||
<string name="firstrun_welcome_button_browser">&onboard_start_button_browser;</string>
|
||||
<string name="firstrun_empty_contentDescription"></string>
|
||||
|
@ -387,6 +387,7 @@
|
|||
<string name="remote_tabs_panel_moved_title">&remote_tabs_panel_moved_title;</string>
|
||||
<string name="remote_tabs_panel_moved_desc">&remote_tabs_panel_moved_desc;</string>
|
||||
<string name="remote_tabs_panel_moved_link">&remote_tabs_panel_moved_link;</string>
|
||||
<string name="remote_tabs_never_synced">&remote_tabs_never_synced;</string>
|
||||
|
||||
<string name="filepicker_title">&filepicker_title;</string>
|
||||
<string name="filepicker_audio_title">&filepicker_audio_title;</string>
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.sync.net;
|
||||
|
||||
import ch.boye.httpclientandroidlib.Header;
|
||||
import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
|
||||
import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
|
||||
import ch.boye.httpclientandroidlib.message.BasicHeader;
|
||||
import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
|
||||
|
||||
/**
|
||||
* An <code>AuthHeaderProvider</code> that returns an Authorization header for
|
||||
* bearer tokens, adding a simple prefix.
|
||||
*/
|
||||
public abstract class AbstractBearerTokenAuthHeaderProvider implements AuthHeaderProvider {
|
||||
protected final String header;
|
||||
|
||||
public AbstractBearerTokenAuthHeaderProvider(String token) {
|
||||
if (token == null) {
|
||||
throw new IllegalArgumentException("token must not be null.");
|
||||
}
|
||||
|
||||
this.header = getPrefix() + " " + token;
|
||||
}
|
||||
|
||||
protected abstract String getPrefix();
|
||||
|
||||
@Override
|
||||
public Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client) {
|
||||
return new BasicHeader("Authorization", header);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.sync.net;
|
||||
|
||||
/**
|
||||
* An <code>AuthHeaderProvider</code> that returns an Authorization header for
|
||||
* Bearer tokens in the format expected by a Mozilla Firefox Accounts Profile Server.
|
||||
* <p>
|
||||
* See <a href="https://github.com/mozilla/fxa-profile-server/blob/master/docs/API.md">https://github.com/mozilla/fxa-profile-server/blob/master/docs/API.md</a>.
|
||||
*/
|
||||
public class BearerAuthHeaderProvider extends AbstractBearerTokenAuthHeaderProvider {
|
||||
public BearerAuthHeaderProvider(String token) {
|
||||
super(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getPrefix() {
|
||||
return "Bearer";
|
||||
}
|
||||
}
|
|
@ -4,12 +4,6 @@
|
|||
|
||||
package org.mozilla.gecko.sync.net;
|
||||
|
||||
import ch.boye.httpclientandroidlib.Header;
|
||||
import ch.boye.httpclientandroidlib.client.methods.HttpRequestBase;
|
||||
import ch.boye.httpclientandroidlib.impl.client.DefaultHttpClient;
|
||||
import ch.boye.httpclientandroidlib.message.BasicHeader;
|
||||
import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
|
||||
|
||||
/**
|
||||
* An <code>AuthHeaderProvider</code> that returns an Authorization header for
|
||||
* BrowserID assertions in the format expected by a Mozilla Services Token
|
||||
|
@ -17,21 +11,13 @@ import ch.boye.httpclientandroidlib.protocol.BasicHttpContext;
|
|||
* <p>
|
||||
* See <a href="http://docs.services.mozilla.com/token/apis.html">http://docs.services.mozilla.com/token/apis.html</a>.
|
||||
*/
|
||||
public class BrowserIDAuthHeaderProvider implements AuthHeaderProvider {
|
||||
protected final String assertion;
|
||||
|
||||
public class BrowserIDAuthHeaderProvider extends AbstractBearerTokenAuthHeaderProvider {
|
||||
public BrowserIDAuthHeaderProvider(String assertion) {
|
||||
if (assertion == null) {
|
||||
throw new IllegalArgumentException("assertion must not be null.");
|
||||
}
|
||||
|
||||
this.assertion = assertion;
|
||||
super(assertion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Header getAuthHeader(HttpRequestBase request, BasicHttpContext context, DefaultHttpClient client) {
|
||||
Header header = new BasicHeader("Authorization", "BrowserID " + assertion);
|
||||
|
||||
return header;
|
||||
protected String getPrefix() {
|
||||
return "BrowserID";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -405,6 +405,7 @@ public class TabsPanel extends LinearLayout
|
|||
int height = getVerticalPanelHeight();
|
||||
dispatchLayoutChange(getWidth(), height);
|
||||
}
|
||||
mHeaderVisible = true;
|
||||
}
|
||||
|
||||
public void prepareToDrag() {
|
||||
|
@ -414,6 +415,7 @@ public class TabsPanel extends LinearLayout
|
|||
} else {
|
||||
prepareToShow(TabsPanel.Panel.NORMAL_TABS);
|
||||
}
|
||||
mHeaderVisible = true;
|
||||
if (mIsSideBar) {
|
||||
prepareSidebarAnimation(getWidth());
|
||||
}
|
||||
|
|
|
@ -17,14 +17,6 @@ import android.view.ViewConfiguration;
|
|||
public final class HardwareUtils {
|
||||
private static final String LOGTAG = "GeckoHardwareUtils";
|
||||
|
||||
// Minimum memory threshold for a device to be considered
|
||||
// a low memory platform (see isLowMemoryPlatform). This value
|
||||
// has be in sync with Gecko's equivalent threshold (defined in
|
||||
// xpcom/base/nsMemoryImpl.cpp) and should only be used in cases
|
||||
// where we can't depend on Gecko to be up and running e.g. show/hide
|
||||
// reading list capabilities in HomePager.
|
||||
private static final int LOW_MEMORY_THRESHOLD_MB = 384;
|
||||
|
||||
private static final boolean IS_AMAZON_DEVICE = Build.MANUFACTURER.equalsIgnoreCase("Amazon");
|
||||
public static final boolean IS_KINDLE_DEVICE = IS_AMAZON_DEVICE &&
|
||||
(Build.MODEL.equals("Kindle Fire") ||
|
||||
|
@ -96,17 +88,4 @@ public final class HardwareUtils {
|
|||
public static int getMemSize() {
|
||||
return SysInfo.getMemSize();
|
||||
}
|
||||
|
||||
public static boolean isLowMemoryPlatform() {
|
||||
final int memSize = getMemSize();
|
||||
|
||||
// Fallback to false if we fail to read meminfo
|
||||
// for some reason.
|
||||
if (memSize == 0) {
|
||||
Log.w(LOGTAG, "Could not compute system memory. Falling back to isLowMemoryPlatform = false.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return memSize < LOW_MEMORY_THRESHOLD_MB;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@ let Reader = {
|
|||
STATUS_FETCH_FAILED_UNSUPPORTED_FORMAT: 3,
|
||||
STATUS_FETCHED_ARTICLE: 4,
|
||||
|
||||
get _hasUsedToolbar() {
|
||||
delete this._hasUsedToolbar;
|
||||
return this._hasUsedToolbar = Services.prefs.getBoolPref("reader.has_used_toolbar");
|
||||
},
|
||||
|
||||
observe: function Reader_observe(aMessage, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "Reader:FetchContent": {
|
||||
|
@ -103,10 +108,6 @@ let Reader = {
|
|||
});
|
||||
break;
|
||||
|
||||
case "Reader:ShowToast":
|
||||
NativeWindow.toast.show(message.data.toast, "short");
|
||||
break;
|
||||
|
||||
case "Reader:SystemUIVisibility":
|
||||
Messaging.sendRequest({
|
||||
type: "SystemUI:Visibility",
|
||||
|
@ -114,11 +115,12 @@ let Reader = {
|
|||
});
|
||||
break;
|
||||
|
||||
case "Reader:ToolbarVisibility":
|
||||
Messaging.sendRequest({
|
||||
type: "BrowserToolbar:Visibility",
|
||||
visible: message.data.visible
|
||||
});
|
||||
case "Reader:ToolbarHidden":
|
||||
if (!this._hasUsedToolbar) {
|
||||
NativeWindow.toast.show(Strings.browser.GetStringFromName("readerMode.toolbarTip"), "short");
|
||||
Services.prefs.setBoolPref("reader.has_used_toolbar", true);
|
||||
this._hasUsedToolbar = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Reader:UpdateReaderButton": {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
let Ci = Components.interfaces, Cc = Components.classes, Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Messaging.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm")
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
|
@ -130,9 +131,20 @@ let Passwords = {
|
|||
}, true);
|
||||
|
||||
// Create item icon.
|
||||
let img = document.createElement("img");
|
||||
let img = document.createElement("div");
|
||||
img.className = "icon";
|
||||
img.setAttribute("src", login.hostname + "/favicon.ico");
|
||||
|
||||
// Load favicon from cache.
|
||||
Messaging.sendRequestForResult({
|
||||
type: "Favicon:CacheLoad",
|
||||
url: login.hostname,
|
||||
}).then(function(faviconUrl) {
|
||||
img.style.backgroundImage= "url('" + faviconUrl + "')";
|
||||
img.style.visibility = "visible";
|
||||
}, function(data) {
|
||||
debug("Favicon cache failure : " + data);
|
||||
img.style.visibility = "visible";
|
||||
});
|
||||
loginItem.appendChild(img);
|
||||
|
||||
// Create item details.
|
||||
|
@ -192,8 +204,8 @@ let Passwords = {
|
|||
let detailItem = document.querySelector("#login-details > .login-item");
|
||||
let login = detailItem.login = listItem.login;
|
||||
let favicon = detailItem.querySelector(".icon");
|
||||
favicon.setAttribute("src", login.hostname + "/favicon.ico");
|
||||
|
||||
favicon.style["background-image"] = listItem.querySelector(".icon").style["background-image"];
|
||||
favicon.style.visibility = "visible";
|
||||
document.getElementById("details-header").setAttribute("link", login.hostname);
|
||||
|
||||
document.getElementById("detail-hostname").textContent = login.hostname;
|
||||
|
@ -209,7 +221,7 @@ let Passwords = {
|
|||
userInputs = domain.split(".").filter(part => part.length > 3);
|
||||
}
|
||||
|
||||
let lastChanged = new Date(login.timePasswordChanged);
|
||||
let lastChanged = new Date(login.QueryInterface(Ci.nsILoginMetaInfo).timePasswordChanged);
|
||||
let days = Math.round((Date.now() - lastChanged) / 1000 / 60 / 60/ 24);
|
||||
document.getElementById("detail-age").textContent = gStringBundle.formatStringFromName("passwordsDetails.age", [days], 1);
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</div>
|
||||
<div id="login-details" class="list" hidden="true">
|
||||
<div class="login-item list-item">
|
||||
<img class="icon"/>
|
||||
<div class="icon"/>
|
||||
<div id="details-header" class="inner">
|
||||
<div class="details">
|
||||
<div id="detail-hostname" class="hostname"></div>
|
||||
|
|
|
@ -179,8 +179,7 @@ lazilyLoadedObserverScripts.forEach(function (aScript) {
|
|||
"Reader:ListStatusRequest",
|
||||
"Reader:RemoveFromList",
|
||||
"Reader:Share",
|
||||
"Reader:ShowToast",
|
||||
"Reader:ToolbarVisibility",
|
||||
"Reader:ToolbarHidden",
|
||||
"Reader:SystemUIVisibility",
|
||||
"Reader:UpdateReaderButton",
|
||||
], "chrome://browser/content/Reader.js"],
|
||||
|
|
|
@ -365,6 +365,10 @@ getUserMedia.sharingCameraAndMicrophone.message2 = Camera and microphone are on
|
|||
readerMode.enter = Enter Reader Mode
|
||||
readerMode.exit = Exit Reader Mode
|
||||
|
||||
# LOCALIZATION NOTE (readerMode.toolbarTip):
|
||||
# Tip shown to users the first time we hide the reader mode toolbar.
|
||||
readerMode.toolbarTip=Tap the screen to show reader options
|
||||
|
||||
#Open in App
|
||||
openInApp.pageAction = Open in App
|
||||
openInApp.ok = OK
|
||||
|
|
|
@ -26,7 +26,7 @@ let AppConstants = Object.freeze({
|
|||
#endif
|
||||
|
||||
ACCESSIBILITY:
|
||||
#ifdef MOZ_ACCESSIBILITY
|
||||
#ifdef ACCESSIBILITY
|
||||
true,
|
||||
#else
|
||||
false,
|
||||
|
|
|
@ -34,7 +34,7 @@ EXTRA_JS_MODULES += [
|
|||
for var in ('ANDROID_PACKAGE_NAME', 'MOZ_APP_VERSION'):
|
||||
DEFINES[var] = CONFIG[var]
|
||||
|
||||
for var in ('NIGHTLY_BUILD', 'RELEASE_BUILD', 'MOZ_ACCESSIBILITY',
|
||||
for var in ('NIGHTLY_BUILD', 'RELEASE_BUILD', 'ACCESSIBILITY',
|
||||
'MOZILLA_OFFICIAL', 'MOZ_OFFICIAL_BRANDING', 'MOZ_SERVICES_HEALTHREPORT',
|
||||
'MOZ_DEVICES', 'MOZ_DEVICES', 'MOZ_SAFE_BROWSING',
|
||||
'MOZ_TELEMETRY_REPORTING', 'MOZ_WEBRTC'):
|
||||
|
|
|
@ -83,6 +83,16 @@
|
|||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-image: url("resource://android/res/drawable-mdpi-v4/favicon.png");
|
||||
background-position: center;
|
||||
background-size: 32px 32px;
|
||||
background-repeat: no-repeat;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@media screen and (min-resolution: 1.25dppx) {
|
||||
#filter-button {
|
||||
background-image: url("resource://android/res/drawable-hdpi-v4/ab_search.png");
|
||||
|
@ -91,6 +101,10 @@
|
|||
#filter-clear {
|
||||
background-image: url("resource://android/res/drawable-hdpi-v4/close_edit_mode_light.png");
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-image: url("resource://android/res/drawable-hdpi-v4/favicon.png");
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-resolution: 2dppx) {
|
||||
|
@ -101,4 +115,8 @@
|
|||
#filter-clear {
|
||||
background-image: url("resource://android/res/drawable-hdpi-v4/close_edit_mode_light.png");
|
||||
}
|
||||
|
||||
.icon {
|
||||
background-image: url("resource://android/res/drawable-xhdpi-v4/favicon.png");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,14 +175,10 @@ def parse_commit(message, jobs):
|
|||
# Argument parser based on try flag flags
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-b', dest='build_types')
|
||||
parser.add_argument('-p', dest='platforms')
|
||||
parser.add_argument('-u', dest='tests')
|
||||
parser.add_argument('-p', nargs='?', dest='platforms', const='all', default='all')
|
||||
parser.add_argument('-u', nargs='?', dest='tests', const='all', default='all')
|
||||
args, unknown = parser.parse_known_args(parts[1:])
|
||||
|
||||
# Sanity check platforms...
|
||||
if args.platforms is None:
|
||||
return []
|
||||
|
||||
# Then builds...
|
||||
if args.build_types is None:
|
||||
return []
|
||||
|
|
|
@ -9,13 +9,11 @@ task:
|
|||
scopes:
|
||||
- 'docker-worker:cache:sources-gecko'
|
||||
- 'docker-worker:cache:sources-gaia'
|
||||
- 'docker-worker:cache:build-b2g-desktop-objects'
|
||||
|
||||
payload:
|
||||
cache:
|
||||
sources-gaia: '/home/worker/gaia'
|
||||
sources-gecko: '/home/worker/gecko'
|
||||
build-b2g-desktop-objects: '/home/worker/object-folder'
|
||||
|
||||
env:
|
||||
MOZCONFIG: 'b2g/config/mozconfigs/linux64_gecko/nightly'
|
||||
|
|
|
@ -4,6 +4,13 @@ $inherits:
|
|||
build_type: 'debug'
|
||||
|
||||
task:
|
||||
scopes:
|
||||
- 'docker-worker:cache:build-b2g-desktop-objects-debug'
|
||||
|
||||
payload:
|
||||
cache:
|
||||
build-b2g-desktop-objects-debug: '/home/worker/object-folder'
|
||||
|
||||
extra:
|
||||
treeherder:
|
||||
collection:
|
||||
|
|
|
@ -4,6 +4,13 @@ $inherits:
|
|||
build_type: 'opt'
|
||||
|
||||
task:
|
||||
scopes:
|
||||
- 'docker-worker:cache:build-b2g-desktop-objects-opt'
|
||||
|
||||
payload:
|
||||
cache:
|
||||
build-b2g-desktop-objects-opt: '/home/worker/object-folder'
|
||||
|
||||
payload:
|
||||
env:
|
||||
MOZCONFIG: 'b2g/config/mozconfigs/linux64_gecko/nightly'
|
||||
|
|
|
@ -420,13 +420,8 @@ AboutReader.prototype = {
|
|||
this._toolbarElement.classList.toggle("toolbar-hidden");
|
||||
this._setSystemUIVisibility(visible);
|
||||
|
||||
if (!visible && !this._hasUsedToolbar) {
|
||||
this._hasUsedToolbar = Services.prefs.getBoolPref("reader.has_used_toolbar");
|
||||
if (!this._hasUsedToolbar) {
|
||||
this._mm.sendAsyncMessage("Reader:ShowToast", { toast: gStrings.GetStringFromName("aboutReader.toolbarTip") });
|
||||
Services.prefs.setBoolPref("reader.has_used_toolbar", true);
|
||||
this._hasUsedToolbar = true;
|
||||
}
|
||||
if (!visible) {
|
||||
this._mm.sendAsyncMessage("Reader:ToolbarHidden");
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -434,10 +429,6 @@ AboutReader.prototype = {
|
|||
this._setToolbarVisibility(!this._getToolbarVisibility());
|
||||
},
|
||||
|
||||
_setBrowserToolbarVisiblity: function Reader_setBrowserToolbarVisiblity(visible) {
|
||||
this._mm.sendAsyncMessage("Reader:ToolbarVisibility", { visible: visible });
|
||||
},
|
||||
|
||||
_setSystemUIVisibility: function Reader_setSystemUIVisibility(visible) {
|
||||
this._mm.sendAsyncMessage("Reader:SystemUIVisibility", { visible: visible });
|
||||
},
|
||||
|
|
|
@ -160,9 +160,9 @@ function getOriginActivationType(origin) {
|
|||
|
||||
let directories = Services.prefs.getCharPref("social.directories").split(',');
|
||||
if (directories.indexOf(origin) >= 0)
|
||||
return 'directory';
|
||||
return "directory";
|
||||
|
||||
return 'foreign';
|
||||
return "foreign";
|
||||
}
|
||||
|
||||
let ActiveProviders = {
|
||||
|
@ -549,9 +549,15 @@ this.SocialService = {
|
|||
let brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
|
||||
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
|
||||
|
||||
// internal activation does not have a host, use the manifest origin in that case
|
||||
let requestingURI = Services.io.newURI(data.installType == "internal" ?
|
||||
data.manifest.origin : data.url, null, null);
|
||||
|
||||
// foreign activation uses the activation url for origin, directory or
|
||||
// internal (in-product) activations use the origin defined in the manifest
|
||||
let url = data.installType == "foreign" ?
|
||||
data.url :
|
||||
data.installType == "directory" ||
|
||||
data.installType == "internal" ?
|
||||
data.manifest.origin : undefined;
|
||||
let requestingURI = Services.io.newURI(url, null, null);
|
||||
let productName = brandBundle.GetStringFromName("brandShortName");
|
||||
|
||||
let message = browserBundle.formatStringFromName("service.install.description",
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
<vbox class="description" flex="1">
|
||||
<label id="warningText">&aboutWarningText.label;</label>
|
||||
<checkbox id="showWarningNextTime" label="&aboutWarningCheckbox.label;" checked="true"/>
|
||||
<hbox pack="center">
|
||||
<hbox class="button-container">
|
||||
<button id="warningButton" class="primary" oncommand="ShowPrefs();" label="&aboutWarningButton.label;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
|
|
|
@ -7,7 +7,7 @@ const {Cc, Ci, Cu, Cr} = require("chrome");
|
|||
const events = require("sdk/event/core");
|
||||
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||
const protocol = require("devtools/server/protocol");
|
||||
const {ContentObserver} = require("devtools/content-observer");
|
||||
const {serializeStack, parseStack} = require("toolkit/loader");
|
||||
|
||||
const {on, once, off, emit} = events;
|
||||
const {method, Arg, Option, RetVal} = protocol;
|
||||
|
@ -417,7 +417,12 @@ let CallWatcherActor = exports.CallWatcherActor = protocol.ActorClass({
|
|||
let originalFunc = Cu.unwaiveXrays(target[name]);
|
||||
|
||||
Cu.exportFunction(function(...args) {
|
||||
let result = Cu.waiveXrays(originalFunc.apply(this, args));
|
||||
let result;
|
||||
try {
|
||||
result = Cu.waiveXrays(originalFunc.apply(this, args));
|
||||
} catch (e) {
|
||||
throw createContentError(e, unwrappedWindow);
|
||||
}
|
||||
|
||||
if (self._recording) {
|
||||
let stack = getStack(name);
|
||||
|
@ -693,3 +698,45 @@ function getBitToEnumValue(type, object, arg) {
|
|||
// Cache the combined bitmask value
|
||||
return table[arg] = flags.join(" | ") || arg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new error from an error that originated from content but was called
|
||||
* from a wrapped overridden method. This is so we can make our own error
|
||||
* that does not look like it originated from the call watcher.
|
||||
*
|
||||
* We use toolkit/loader's parseStack and serializeStack rather than the
|
||||
* parsing done in the local `getStack` function, because it does not expose
|
||||
* column number, would have to change the protocol models `call-stack-items` and `call-details`
|
||||
* which hurts backwards compatibility, and the local `getStack` is an optimized, hot function.
|
||||
*/
|
||||
function createContentError (e, win) {
|
||||
let { message, name, stack } = e;
|
||||
let parsedStack = parseStack(stack);
|
||||
let { fileName, lineNumber, columnNumber } = parsedStack[parsedStack.length - 1];
|
||||
let error;
|
||||
|
||||
let isDOMException = e instanceof Ci.nsIDOMDOMException;
|
||||
let constructor = isDOMException ? win.DOMException : (win[e.name] || win.Error);
|
||||
|
||||
if (isDOMException) {
|
||||
error = new constructor(message, name);
|
||||
Object.defineProperties(error, {
|
||||
code: { value: e.code },
|
||||
columnNumber: { value: 0 }, // columnNumber is always 0 for DOMExceptions?
|
||||
filename: { value: fileName }, // note the lowercase `filename`
|
||||
lineNumber: { value: lineNumber },
|
||||
result: { value: e.result },
|
||||
stack: { value: serializeStack(parsedStack) }
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Constructing an error here retains all the stack information,
|
||||
// and we can add message, fileName and lineNumber via constructor, though
|
||||
// need to manually add columnNumber.
|
||||
error = new constructor(message, fileName, lineNumber);
|
||||
Object.defineProperty(error, "columnNumber", {
|
||||
value: columnNumber
|
||||
});
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -14,10 +14,10 @@ const protocol = require("devtools/server/protocol");
|
|||
const { CallWatcherActor, CallWatcherFront } = require("devtools/server/actors/call-watcher");
|
||||
const { ThreadActor } = require("devtools/server/actors/script");
|
||||
const AutomationTimeline = require("./utils/automation-timeline");
|
||||
|
||||
const { on, once, off, emit } = events;
|
||||
const { types, method, Arg, Option, RetVal } = protocol;
|
||||
|
||||
const ENABLE_AUTOMATION = false;
|
||||
const AUTOMATION_GRANULARITY = 2000;
|
||||
const AUTOMATION_GRANULARITY_MAX = 6000;
|
||||
|
||||
|
@ -680,7 +680,7 @@ let WebAudioActor = exports.WebAudioActor = protocol.ActorClass({
|
|||
else if (WebAudioFront.NODE_CREATION_METHODS.has(name)) {
|
||||
this._handleCreationCall(functionCall);
|
||||
}
|
||||
else if (WebAudioFront.AUTOMATION_METHODS.has(name)) {
|
||||
else if (ENABLE_AUTOMATION && WebAudioFront.AUTOMATION_METHODS.has(name)) {
|
||||
this._handleAutomationCall(functionCall);
|
||||
}
|
||||
},
|
||||
|
|
|
@ -26,5 +26,3 @@ aboutReader.fontTypeSample=Aa
|
|||
# LOCALIZATION NOTE (aboutReader.fontSizeSample): String used to sample a relative font size
|
||||
# for the font size setting. Tapping different samples will change the font size.
|
||||
aboutReader.fontSizeSample=A
|
||||
|
||||
aboutReader.toolbarTip=Tap the screen to show reader options
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
# 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/.
|
||||
|
||||
# OSX only. Default menu label when there is no xul menubar.
|
||||
|
||||
quitMenuitem.label=Quit
|
||||
quitMenuitem.key=q
|
|
@ -38,6 +38,7 @@
|
|||
locale/@AB_CD@/global/devtools/styleinspector.properties (%chrome/global/devtools/styleinspector.properties)
|
||||
locale/@AB_CD@/global/dialogOverlay.dtd (%chrome/global/dialogOverlay.dtd)
|
||||
locale/@AB_CD@/global/editMenuOverlay.dtd (%chrome/global/editMenuOverlay.dtd)
|
||||
locale/@AB_CD@/global/fallbackMenubar.properties (%chrome/global/fallbackMenubar.properties)
|
||||
locale/@AB_CD@/global/filefield.properties (%chrome/global/filefield.properties)
|
||||
locale/@AB_CD@/global/filepicker.dtd (%chrome/global/filepicker.dtd)
|
||||
locale/@AB_CD@/global/filepicker.properties (%chrome/global/filepicker.properties)
|
||||
|
|
|
@ -77,6 +77,10 @@ ul {
|
|||
min-width: 150px;
|
||||
}
|
||||
|
||||
.button-container > button:first-child {
|
||||
-moz-margin-start: 0;
|
||||
}
|
||||
|
||||
/* Trees */
|
||||
tree {
|
||||
min-height: 12em;
|
||||
|
|
|
@ -130,6 +130,7 @@ public:
|
|||
|
||||
protected:
|
||||
void ConstructNativeMenus();
|
||||
void ConstructFallbackNativeMenus();
|
||||
nsresult InsertMenuAtIndex(nsMenuX* aMenu, uint32_t aIndex);
|
||||
void RemoveMenuAtIndex(uint32_t aIndex);
|
||||
void HideItem(nsIDOMDocument* inDoc, const nsAString & inID, nsIContent** outHiddenNode);
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include "nsIDocument.h"
|
||||
#include "nsIDOMDocument.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIAppStartup.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsToolkitCompsCID.h"
|
||||
|
||||
NativeMenuItemTarget* nsMenuBarX::sNativeEventTarget = nil;
|
||||
nsMenuBarX* nsMenuBarX::sLastGeckoMenuBarPainted = nullptr; // Weak
|
||||
|
@ -80,7 +83,9 @@ nsMenuBarX::~nsMenuBarX()
|
|||
sPrefItemContent = nullptr;
|
||||
|
||||
// make sure we unregister ourselves as a content observer
|
||||
UnregisterForContentChanges(mContent);
|
||||
if (mContent) {
|
||||
UnregisterForContentChanges(mContent);
|
||||
}
|
||||
|
||||
// We have to manually clear the array here because clearing causes menu items
|
||||
// to call back into the menu bar to unregister themselves. We don't want to
|
||||
|
@ -96,21 +101,24 @@ nsMenuBarX::~nsMenuBarX()
|
|||
|
||||
nsresult nsMenuBarX::Create(nsIWidget* aParent, nsIContent* aContent)
|
||||
{
|
||||
if (!aParent || !aContent)
|
||||
if (!aParent)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
mParentWindow = aParent;
|
||||
mContent = aContent;
|
||||
|
||||
AquifyMenuBar();
|
||||
if (mContent) {
|
||||
AquifyMenuBar();
|
||||
|
||||
nsresult rv = nsMenuGroupOwnerX::Create(aContent);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
nsresult rv = nsMenuGroupOwnerX::Create(mContent);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
RegisterForContentChanges(aContent, this);
|
||||
|
||||
ConstructNativeMenus();
|
||||
RegisterForContentChanges(mContent, this);
|
||||
ConstructNativeMenus();
|
||||
} else {
|
||||
ConstructFallbackNativeMenus();
|
||||
}
|
||||
|
||||
// Give this to the parent window. The parent takes ownership.
|
||||
static_cast<nsCocoaWindow*>(mParentWindow)->SetMenuBar(this);
|
||||
|
@ -138,6 +146,49 @@ void nsMenuBarX::ConstructNativeMenus()
|
|||
}
|
||||
}
|
||||
|
||||
void nsMenuBarX::ConstructFallbackNativeMenus()
|
||||
{
|
||||
if (sApplicationMenu) {
|
||||
// Menu has already been built.
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStringBundle> stringBundle;
|
||||
|
||||
nsCOMPtr<nsIStringBundleService> bundleSvc = do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
||||
bundleSvc->CreateBundle("chrome://global/locale/fallbackMenubar.properties", getter_AddRefs(stringBundle));
|
||||
|
||||
if (!stringBundle) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsXPIDLString labelUTF16;
|
||||
nsXPIDLString keyUTF16;
|
||||
|
||||
const char16_t* labelProp = MOZ_UTF16("quitMenuitem.label");
|
||||
const char16_t* keyProp = MOZ_UTF16("quitMenuitem.key");
|
||||
|
||||
stringBundle->GetStringFromName(labelProp, getter_Copies(labelUTF16));
|
||||
stringBundle->GetStringFromName(keyProp, getter_Copies(keyUTF16));
|
||||
|
||||
NSString* labelStr = [NSString stringWithUTF8String:
|
||||
NS_ConvertUTF16toUTF8(labelUTF16).get()];
|
||||
NSString* keyStr= [NSString stringWithUTF8String:
|
||||
NS_ConvertUTF16toUTF8(keyUTF16).get()];
|
||||
|
||||
if (!nsMenuBarX::sNativeEventTarget) {
|
||||
nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init];
|
||||
}
|
||||
|
||||
sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain];
|
||||
NSMenuItem* quitMenuItem = [[[NSMenuItem alloc] initWithTitle:labelStr
|
||||
action:@selector(menuItemHit:)
|
||||
keyEquivalent:keyStr] autorelease];
|
||||
[quitMenuItem setTarget:nsMenuBarX::sNativeEventTarget];
|
||||
[quitMenuItem setTag:eCommand_ID_Quit];
|
||||
[sApplicationMenu addItem:quitMenuItem];
|
||||
}
|
||||
|
||||
uint32_t nsMenuBarX::GetMenuCount()
|
||||
{
|
||||
return mMenuArray.Length();
|
||||
|
@ -878,23 +929,25 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
|||
return;
|
||||
}
|
||||
|
||||
int tag = [sender tag];
|
||||
|
||||
if (!gMenuItemsExecuteCommands) {
|
||||
return;
|
||||
}
|
||||
|
||||
int tag = [sender tag];
|
||||
|
||||
MenuItemInfo* info = [sender representedObject];
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
nsMenuGroupOwnerX* menuGroupOwner = [info menuGroupOwner];
|
||||
if (!menuGroupOwner)
|
||||
return;
|
||||
|
||||
nsMenuGroupOwnerX* menuGroupOwner = nullptr;
|
||||
nsMenuBarX* menuBar = nullptr;
|
||||
if (menuGroupOwner->MenuObjectType() == eMenuBarObjectType)
|
||||
menuBar = static_cast<nsMenuBarX*>(menuGroupOwner);
|
||||
MenuItemInfo* info = [sender representedObject];
|
||||
|
||||
if (info) {
|
||||
menuGroupOwner = [info menuGroupOwner];
|
||||
if (!menuGroupOwner) {
|
||||
return;
|
||||
}
|
||||
if (menuGroupOwner->MenuObjectType() == eMenuBarObjectType) {
|
||||
menuBar = static_cast<nsMenuBarX*>(menuGroupOwner);
|
||||
}
|
||||
}
|
||||
|
||||
// Do special processing if this is for an app-global command.
|
||||
if (tag == eCommand_ID_About) {
|
||||
|
@ -934,7 +987,10 @@ static BOOL gMenuItemsExecuteCommands = YES;
|
|||
nsMenuUtilsX::DispatchCommandTo(mostSpecificContent);
|
||||
}
|
||||
else {
|
||||
[NSApp terminate:nil];
|
||||
nsCOMPtr<nsIAppStartup> appStartup = do_GetService(NS_APPSTARTUP_CONTRACTID);
|
||||
if (appStartup) {
|
||||
appStartup->Quit(nsIAppStartup::eAttemptQuit);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -418,6 +418,11 @@ nsWebShellWindow::WindowDeactivated()
|
|||
#ifdef USE_NATIVE_MENUS
|
||||
static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow)
|
||||
{
|
||||
nsCOMPtr<nsINativeMenuService> nms = do_GetService("@mozilla.org/widget/nativemenuservice;1");
|
||||
if (!nms) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the menubar tag (if there is more than one, we ignore all but
|
||||
// the first).
|
||||
nsCOMPtr<nsIDOMNodeList> menubarElements;
|
||||
|
@ -428,13 +433,13 @@ static void LoadNativeMenus(nsIDOMDocument *aDOMDoc, nsIWidget *aParentWindow)
|
|||
nsCOMPtr<nsIDOMNode> menubarNode;
|
||||
if (menubarElements)
|
||||
menubarElements->Item(0, getter_AddRefs(menubarNode));
|
||||
if (!menubarNode)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsINativeMenuService> nms = do_GetService("@mozilla.org/widget/nativemenuservice;1");
|
||||
nsCOMPtr<nsIContent> menubarContent(do_QueryInterface(menubarNode));
|
||||
if (nms && menubarContent)
|
||||
if (menubarNode) {
|
||||
nsCOMPtr<nsIContent> menubarContent(do_QueryInterface(menubarNode));
|
||||
nms->CreateNativeMenuBar(aParentWindow, menubarContent);
|
||||
} else {
|
||||
nms->CreateNativeMenuBar(aParentWindow, nullptr);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче