diff --git a/b2g/config/aries/sources.xml b/b2g/config/aries/sources.xml index de02c5b4809..f00171dcb0f 100644 --- a/b2g/config/aries/sources.xml +++ b/b2g/config/aries/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/dolphin/sources.xml b/b2g/config/dolphin/sources.xml index 135f313e197..3aa0fbef8ec 100644 --- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/emulator-ics/sources.xml b/b2g/config/emulator-ics/sources.xml index cba477d2bb5..bd9dcb63a1c 100644 --- a/b2g/config/emulator-ics/sources.xml +++ b/b2g/config/emulator-ics/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/emulator-jb/sources.xml b/b2g/config/emulator-jb/sources.xml index 5c25f6215b7..c2c7089b4d2 100644 --- a/b2g/config/emulator-jb/sources.xml +++ b/b2g/config/emulator-jb/sources.xml @@ -17,10 +17,10 @@ - + - + diff --git a/b2g/config/emulator-kk/sources.xml b/b2g/config/emulator-kk/sources.xml index c12c5ffd8b6..effb01c23fd 100644 --- a/b2g/config/emulator-kk/sources.xml +++ b/b2g/config/emulator-kk/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/emulator-l/sources.xml b/b2g/config/emulator-l/sources.xml index 64218ced8d1..582eb668512 100644 --- a/b2g/config/emulator-l/sources.xml +++ b/b2g/config/emulator-l/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/emulator/sources.xml b/b2g/config/emulator/sources.xml index cba477d2bb5..bd9dcb63a1c 100644 --- a/b2g/config/emulator/sources.xml +++ b/b2g/config/emulator/sources.xml @@ -19,7 +19,7 @@ - + diff --git a/b2g/config/flame-kk/sources.xml b/b2g/config/flame-kk/sources.xml index 0212b3ae013..32c9572419a 100644 --- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-kk/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 47e376bfc2c..0f8885c9373 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,9 +1,9 @@ { "git": { - "git_revision": "9b7ed13e0dee26b9f16ae5fbc076fa8bd588b256", + "git_revision": "477b5672811ed970a7476fe6f67dba546a302dce", "remote": "https://git.mozilla.org/releases/gaia.git", "branch": "" }, - "revision": "d5e509fd9697316bcbc267413a30478dcd4dbca9", + "revision": "5bab67b888d1491d1718cf1a7349bcef3114cbab", "repo_path": "integration/gaia-central" } diff --git a/b2g/config/nexus-4/sources.xml b/b2g/config/nexus-4/sources.xml index c9d5fa79d7a..20482a65ce5 100644 --- a/b2g/config/nexus-4/sources.xml +++ b/b2g/config/nexus-4/sources.xml @@ -17,10 +17,10 @@ - + - + diff --git a/b2g/config/nexus-5-l/sources.xml b/b2g/config/nexus-5-l/sources.xml index df7a909f06b..2f5c9c1cb9f 100644 --- a/b2g/config/nexus-5-l/sources.xml +++ b/b2g/config/nexus-5-l/sources.xml @@ -15,7 +15,7 @@ - + @@ -23,7 +23,7 @@ - + diff --git a/browser/devtools/performance/modules/global.js b/browser/devtools/performance/modules/global.js index 70f6b2926e6..2038a5fefe5 100644 --- a/browser/devtools/performance/modules/global.js +++ b/browser/devtools/performance/modules/global.js @@ -65,6 +65,10 @@ const CATEGORIES = [{ color: "#d99b28", abbrev: "events", label: L10N.getStr("category.events") +}, { + color: "#8fa1b2", + abbrev: "tools", + label: L10N.getStr("category.tools") }]; /** @@ -81,6 +85,9 @@ const CATEGORY_MAPPINGS = { "1024": CATEGORIES[5], // js::ProfileEntry::Category::GRAPHICS "2048": CATEGORIES[6], // js::ProfileEntry::Category::STORAGE "4096": CATEGORIES[7], // js::ProfileEntry::Category::EVENTS + + // non-bitmasks for specially-assigned categories + "9000": CATEGORIES[8], }; /** @@ -106,17 +113,17 @@ const [CATEGORY_MASK, CATEGORY_MASK_LIST] = (function () { return [ function (name, index) { if (!(name in bitmasksForCategory)) { - throw new Error(`Category abbreviation '${name}' does not exist.`); + throw new Error(`Category abbreviation "${name}" does not exist.`); } if (arguments.length == 1) { if (bitmasksForCategory[name].length != 1) { - throw new Error(`Expected exactly one category number for '${name}'.`); + throw new Error(`Expected exactly one category number for "${name}".`); } else { return bitmasksForCategory[name][0]; } } else { if (index > bitmasksForCategory[name].length) { - throw new Error(`Index '${index}' too high for category '${name}'.`); + throw new Error(`Index "${index}" too high for category "${name}".`); } else { return bitmasksForCategory[name][index - 1]; } @@ -125,7 +132,7 @@ const [CATEGORY_MASK, CATEGORY_MASK_LIST] = (function () { function (name) { if (!(name in bitmasksForCategory)) { - throw new Error(`Category abbreviation '${name}' does not exist.`); + throw new Error(`Category abbreviation "${name}" does not exist.`); } return bitmasksForCategory[name]; } @@ -135,11 +142,15 @@ const [CATEGORY_MASK, CATEGORY_MASK_LIST] = (function () { // Human-readable "other" category bitmask. Older Geckos don't have all the // necessary instrumentation in the sampling profiler backend for creating // a categories graph, in which case we default to the "other" category. -const CATEGORY_OTHER = CATEGORY_MASK('other'); +const CATEGORY_OTHER = CATEGORY_MASK("other"); // Human-readable JIT category bitmask. Certain pseudo-frames in a sample, -// like "EnterJIT", don't have any associated `cateogry` information. -const CATEGORY_JIT = CATEGORY_MASK('js'); +// like "EnterJIT", don't have any associated `category` information. +const CATEGORY_JIT = CATEGORY_MASK("js"); + +// Human-readable "devtools" category bitmask. Not emitted from frames themselves, +// but used manually in the client. +const CATEGORY_DEVTOOLS = CATEGORY_MASK("tools"); // Exported symbols. exports.L10N = L10N; @@ -150,3 +161,4 @@ exports.CATEGORY_MASK = CATEGORY_MASK; exports.CATEGORY_MASK_LIST = CATEGORY_MASK_LIST; exports.CATEGORY_OTHER = CATEGORY_OTHER; exports.CATEGORY_JIT = CATEGORY_JIT; +exports.CATEGORY_DEVTOOLS = CATEGORY_DEVTOOLS; diff --git a/browser/devtools/performance/modules/logic/frame-utils.js b/browser/devtools/performance/modules/logic/frame-utils.js index faa2b26a098..1ddaa8669c8 100644 --- a/browser/devtools/performance/modules/logic/frame-utils.js +++ b/browser/devtools/performance/modules/logic/frame-utils.js @@ -6,8 +6,8 @@ const { Cc, Ci, Cu, Cr } = require("chrome"); loader.lazyRequireGetter(this, "Services"); -loader.lazyRequireGetter(this, "CATEGORY_OTHER", - "devtools/performance/global", true); +loader.lazyRequireGetter(this, "global", + "devtools/performance/global"); // Character codes used in various parsing helper functions. const CHAR_CODE_A = "a".charCodeAt(0); @@ -162,33 +162,55 @@ function parseLocation(location, fallbackLine, fallbackColumn) { }; /** - * Checks if the specified function represents a chrome or content frame. + * Sets the properties of `isContent` and `category` on a frame. * - * @param string location - * The location of the frame. - * @param number category [optional] - * If a chrome frame, the category. - * @return boolean - * True if a content frame, false if a chrome frame. + * @param {InflatedFrame} frame */ -function isContent({ location, category }) { +function computeIsContentAndCategory(frame) { // Only C++ stack frames have associated category information. - if (category) { - return false; + if (frame.category) { + return; } + let location = frame.location; + // Locations in frames with function names look like: // "functionName (foo://bar)". // Look for the starting left parenthesis, then try to match a // scheme name. for (let i = 0; i < location.length; i++) { if (location.charCodeAt(i) === CHAR_CODE_LPAREN) { - return isContentScheme(location, i + 1); + if (isContentScheme(location, i + 1)) { + frame.isContent = true; + return; + } + + for (let j = i + 1; j < location.length; j++) { + if (location.charCodeAt(j) === CHAR_CODE_R && + isChromeScheme(location, j) && + (location.indexOf("resource://gre/modules/devtools") !== -1 || + location.indexOf("resource:///modules/devtools") !== -1)) { + frame.category = global.CATEGORY_DEVTOOLS; + return; + } + } + + break; } } // If there was no left parenthesis, try matching from the start. - return isContentScheme(location, 0); + if (isContentScheme(location, 0)) { + frame.isContent = true; + return; + } + + if (location === "EnterJIT") { + frame.category = global.CATEGORY_JIT; + return; + } + + frame.category = global.CATEGORY_OTHER; } /** @@ -247,10 +269,17 @@ function InflatedFrame(index, frameTable, stringTable, allocationsTable) { this.optimizations = frame[OPTIMIZATIONS_SLOT]; this.line = frame[LINE_SLOT]; this.column = undefined; - this.category = category; - this.metaCategory = category || CATEGORY_OTHER; this.allocations = allocationsTable ? allocationsTable[index] : 0; - this.isContent = isContent(this); + this.category = category; + this.isContent = false; + + // Attempt to compute if this frame is a content frame, and if not, + // its category. + // + // Since only C++ stack frames have associated category information, + // attempt to generate a useful category, fallback to the one provided + // by the profiling data, or fallback to an unknown category. + computeIsContentAndCategory(this); }; /** @@ -284,7 +313,7 @@ InflatedFrame.prototype.getFrameKey = function getFrameKey(options) { // non-leaf platform frames don't give any meaningful context, and so we // can safely filter them out. options.isMetaCategoryOut = true; - return this.metaCategory; + return this.category; } // Return an empty string denoting that this frame should be skipped. @@ -418,8 +447,8 @@ function isNumeric(c) { return c >= CHAR_CODE_0 && c <= CHAR_CODE_9; } +exports.computeIsContentAndCategory = computeIsContentAndCategory; exports.parseLocation = parseLocation; -exports.isContent = isContent; exports.getInflatedFrameCache = getInflatedFrameCache; exports.getOrAddInflatedFrame = getOrAddInflatedFrame; exports.InflatedFrame = InflatedFrame; diff --git a/browser/devtools/performance/modules/logic/tree-model.js b/browser/devtools/performance/modules/logic/tree-model.js index 7275ee97490..ebc0ce2f6d3 100644 --- a/browser/devtools/performance/modules/logic/tree-model.js +++ b/browser/devtools/performance/modules/logic/tree-model.js @@ -9,12 +9,6 @@ loader.lazyRequireGetter(this, "L10N", "devtools/performance/global", true); loader.lazyRequireGetter(this, "CATEGORY_MAPPINGS", "devtools/performance/global", true); -loader.lazyRequireGetter(this, "CATEGORIES", - "devtools/performance/global", true); -loader.lazyRequireGetter(this, "CATEGORY_JIT", - "devtools/performance/global", true); -loader.lazyRequireGetter(this, "CATEGORY_OTHER", - "devtools/performance/global", true); loader.lazyRequireGetter(this, "JITOptimizations", "devtools/performance/jit", true); loader.lazyRequireGetter(this, "FrameUtils", @@ -377,15 +371,15 @@ function FrameNode(frameKey, { location, line, category, allocations, isContent this.key = frameKey; this.location = location; this.line = line; - this.category = category; this.allocations = allocations; this.samples = 0; this.duration = 0; this.calls = []; - this.isContent = isContent; + this.isContent = !!isContent; this._optimizations = null; this._stringTable = null; - this.isMetaCategory = isMetaCategory; + this.isMetaCategory = !!isMetaCategory; + this.category = category; } FrameNode.prototype = { @@ -462,19 +456,7 @@ FrameNode.prototype = { * function name and source url. */ _computeInfo: function() { - // "EnterJIT" pseudoframes are special, not actually on the stack. - if (this.location == "EnterJIT") { - this.category = CATEGORY_JIT; - } - - if (this.isMetaCategory && !this.category) { - this.category = CATEGORY_OTHER; - } - - // Since only C++ stack frames have associated category information, - // default to an "unknown" category otherwise. let categoryData = CATEGORY_MAPPINGS[this.category] || {}; - let parsedData = FrameUtils.parseLocation(this.location, this.line, this.column); parsedData.nodeType = "Frame"; parsedData.categoryData = categoryData; diff --git a/browser/devtools/performance/test/browser.ini b/browser/devtools/performance/test/browser.ini index fd9399fb943..ac8cd1276b0 100644 --- a/browser/devtools/performance/test/browser.ini +++ b/browser/devtools/performance/test/browser.ini @@ -117,8 +117,6 @@ skip-if = e10s # GC events seem unreliable in multiprocess [browser_perf-recording-selected-03.js] [browser_perf-recording-selected-04.js] [browser_perf-theme-toggle-01.js] -[browser_profiler_categories.js] -[browser_profiler_content-check.js] [browser_profiler_tree-abstract-01.js] [browser_profiler_tree-abstract-02.js] [browser_profiler_tree-abstract-03.js] diff --git a/browser/devtools/performance/test/browser_markers-timestamp.js b/browser/devtools/performance/test/browser_markers-timestamp.js index db46a354144..86cc6d545b1 100644 --- a/browser/devtools/performance/test/browser_markers-timestamp.js +++ b/browser/devtools/performance/test/browser_markers-timestamp.js @@ -26,6 +26,7 @@ function* spawnTest () { let maxMarkerTime = model._timelineStartTime + model.getDuration() + TIME_CLOSE_TO; + ok(markers.every(({stack}) => typeof stack === "number"), "All markers have stack references."); ok(markers.every(({name}) => name === "TimeStamp"), "All markers found are TimeStamp markers"); ok(markers.length === 2, "found 2 TimeStamp markers"); ok(markers.every(({start}) => typeof start === "number" && start > 0 && start < maxMarkerTime), diff --git a/browser/devtools/performance/test/unit/test_frame-utils-01.js b/browser/devtools/performance/test/unit/test_frame-utils-01.js index ff07320113b..5ec1855e3a1 100644 --- a/browser/devtools/performance/test/unit/test_frame-utils-01.js +++ b/browser/devtools/performance/test/unit/test_frame-utils-01.js @@ -40,7 +40,12 @@ function run_test() { } add_task(function () { - const { isContent, parseLocation } = devtools.require("devtools/performance/frame-utils"); + const { computeIsContentAndCategory, parseLocation } = devtools.require("devtools/performance/frame-utils"); + let isContent = (frame) => { + computeIsContentAndCategory(frame); + return frame.isContent; + }; + for (let frame of CONTENT_LOCATIONS) { ok(isContent.apply(null, frameify(frame)), `${frame[0]} should be considered a content frame.`); diff --git a/browser/devtools/performance/test/browser_profiler_content-check.js b/browser/devtools/performance/test/unit/test_frame-utils-02.js similarity index 53% rename from browser/devtools/performance/test/browser_profiler_content-check.js rename to browser/devtools/performance/test/unit/test_frame-utils-02.js index 0f2b1b304f8..10b6f0db960 100644 --- a/browser/devtools/performance/test/browser_profiler_content-check.js +++ b/browser/devtools/performance/test/unit/test_frame-utils-02.js @@ -6,46 +6,53 @@ * works properly. */ -function test() { +function run_test() { + run_next_test(); +} + +add_task(function () { let FrameUtils = devtools.require("devtools/performance/frame-utils"); - ok(FrameUtils.isContent({ location: "http://foo" }), + let isContent = (frame) => { + FrameUtils.computeIsContentAndCategory(frame); + return frame.isContent; + }; + + ok(isContent({ location: "http://foo" }), "Verifying content/chrome frames is working properly."); - ok(FrameUtils.isContent({ location: "https://foo" }), + ok(isContent({ location: "https://foo" }), "Verifying content/chrome frames is working properly."); - ok(FrameUtils.isContent({ location: "file://foo" }), + ok(isContent({ location: "file://foo" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ location: "chrome://foo" }), + ok(!isContent({ location: "chrome://foo" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ location: "resource://foo" }), + ok(!isContent({ location: "resource://foo" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ location: "chrome://foo -> http://bar" }), + ok(!isContent({ location: "chrome://foo -> http://bar" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ location: "chrome://foo -> https://bar" }), + ok(!isContent({ location: "chrome://foo -> https://bar" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ location: "chrome://foo -> file://bar" }), + ok(!isContent({ location: "chrome://foo -> file://bar" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ location: "resource://foo -> http://bar" }), + ok(!isContent({ location: "resource://foo -> http://bar" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ location: "resource://foo -> https://bar" }), + ok(!isContent({ location: "resource://foo -> https://bar" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ location: "resource://foo -> file://bar" }), + ok(!isContent({ location: "resource://foo -> file://bar" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ category: 1, location: "chrome://foo" }), + ok(!isContent({ category: 1, location: "chrome://foo" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ category: 1, location: "resource://foo" }), + ok(!isContent({ category: 1, location: "resource://foo" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ category: 1, location: "file://foo -> http://bar" }), + ok(!isContent({ category: 1, location: "file://foo -> http://bar" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ category: 1, location: "file://foo -> https://bar" }), + ok(!isContent({ category: 1, location: "file://foo -> https://bar" }), "Verifying content/chrome frames is working properly."); - ok(!FrameUtils.isContent({ category: 1, location: "file://foo -> file://bar" }), + ok(!isContent({ category: 1, location: "file://foo -> file://bar" }), "Verifying content/chrome frames is working properly."); - - finish(); -} +}); diff --git a/browser/devtools/performance/test/browser_profiler_categories.js b/browser/devtools/performance/test/unit/test_profiler-categories.js similarity index 56% rename from browser/devtools/performance/test/browser_profiler_categories.js rename to browser/devtools/performance/test/unit/test_profiler-categories.js index e17e7cd3b9a..b5757983ba3 100644 --- a/browser/devtools/performance/test/browser_profiler_categories.js +++ b/browser/devtools/performance/test/unit/test_profiler-categories.js @@ -5,7 +5,11 @@ * Tests if the profiler categories are mapped correctly. */ -function test() { +function run_test() { + run_next_test(); +} + +add_task(function () { let global = devtools.require("devtools/performance/global"); let l10n = global.L10N; let categories = global.CATEGORIES; @@ -15,20 +19,18 @@ function test() { ok(count, "Should have a non-empty list of categories available."); - ok(!categories.some(e => !e.color), + ok(categories.some(e => e.color), "All categories have an associated color."); - ok(!categories.some(e => !e.label), + ok(categories.every(e => e.label), "All categories have an associated label."); - ok(!categories.some(e => e.label != l10n.getStr("category." + e.abbrev)), + ok(categories.every(e => e.label === l10n.getStr("category." + e.abbrev)), "All categories have a correctly localized label."); - ok(!Object.keys(mappings).some(e => !Number.isInteger(Math.log2(e))), - "All bitmask mappings keys are powers of 2."); + ok(Object.keys(mappings).every(e => (Number(e) >= 9000 && Number(e) <= 9999) || Number.isInteger(Math.log2(e))), + "All bitmask mappings keys are powers of 2, or between 9000-9999 for special categories."); - ok(!Object.keys(mappings).some(e => categories.indexOf(mappings[e]) == -1), + ok(Object.keys(mappings).every(e => categories.indexOf(mappings[e]) !== -1), "All bitmask mappings point to a category."); - - finish(); -} +}); diff --git a/browser/devtools/performance/test/unit/test_tree-model-01.js b/browser/devtools/performance/test/unit/test_tree-model-01.js index 4f95c1ad2a9..63a4842d886 100644 --- a/browser/devtools/performance/test/unit/test_tree-model-01.js +++ b/browser/devtools/performance/test/unit/test_tree-model-01.js @@ -26,7 +26,7 @@ add_task(function test() { "The correct duration was calculated for the root node."); equal(root.getInfo().functionName, "(root)", "The correct function name was retrieved for the root node."); - equal(root.getInfo().categoryData.toSource(), "({})", + equal(root.getInfo().categoryData.abbrev, "other", "The correct empty category data was retrieved for the root node."); equal(root.calls.length, 1, diff --git a/browser/devtools/performance/test/unit/test_tree-model-08.js b/browser/devtools/performance/test/unit/test_tree-model-08.js index 8b326ead8c6..f5d5c432721 100644 --- a/browser/devtools/performance/test/unit/test_tree-model-08.js +++ b/browser/devtools/performance/test/unit/test_tree-model-08.js @@ -13,238 +13,82 @@ add_task(function test() { let FrameUtils = devtools.require("devtools/performance/frame-utils"); let { FrameNode } = devtools.require("devtools/performance/tree-model"); let { CATEGORY_OTHER } = devtools.require("devtools/performance/global"); + let compute = frame => { + FrameUtils.computeIsContentAndCategory(frame); + return frame; + }; - let frame1 = new FrameNode("hello/<.world (http://foo/bar.js:123:987)", { - location: "hello/<.world (http://foo/bar.js:123:987)", - line: 456, - isContent: FrameUtils.isContent({ - location: "hello/<.world (http://foo/bar.js:123:987)" - }) - }, false); - - equal(frame1.getInfo().nodeType, "Frame", - "The first frame node has the correct type."); - equal(frame1.getInfo().functionName, "hello/<.world", - "The first frame node has the correct function name."); - equal(frame1.getInfo().fileName, "bar.js", - "The first frame node has the correct file name."); - equal(frame1.getInfo().hostName, "foo", - "The first frame node has the correct host name."); - equal(frame1.getInfo().url, "http://foo/bar.js", - "The first frame node has the correct url."); - equal(frame1.getInfo().line, 123, - "The first frame node has the correct line."); - equal(frame1.getInfo().column, 987, - "The first frame node has the correct column."); - equal(frame1.getInfo().categoryData.toSource(), "({})", - "The first frame node has the correct category data."); - equal(frame1.getInfo().isContent, true, - "The first frame node has the correct content flag."); - - let frame2 = new FrameNode("hello/<.world (http://foo/bar.js#baz:123:987)", { - location: "hello/<.world (http://foo/bar.js#baz:123:987)", - line: 456, - isContent: FrameUtils.isContent({ - location: "hello/<.world (http://foo/bar.js#baz:123:987)" - }) - }, false); - - equal(frame2.getInfo().nodeType, "Frame", - "The second frame node has the correct type."); - equal(frame2.getInfo().functionName, "hello/<.world", - "The second frame node has the correct function name."); - equal(frame2.getInfo().fileName, "bar.js", - "The second frame node has the correct file name."); - equal(frame2.getInfo().hostName, "foo", - "The second frame node has the correct host name."); - equal(frame2.getInfo().url, "http://foo/bar.js#baz", - "The second frame node has the correct url."); - equal(frame2.getInfo().line, 123, - "The second frame node has the correct line."); - equal(frame2.getInfo().column, 987, - "The second frame node has the correct column."); - equal(frame2.getInfo().categoryData.toSource(), "({})", - "The second frame node has the correct category data."); - equal(frame2.getInfo().isContent, true, - "The second frame node has the correct content flag."); - - let frame3 = new FrameNode("hello/<.world (http://foo/#bar:123:987)", { - location: "hello/<.world (http://foo/#bar:123:987)", - line: 456, - isContent: FrameUtils.isContent({ - location: "hello/<.world (http://foo/#bar:123:987)" - }) - }, false); - - equal(frame3.getInfo().nodeType, "Frame", - "The third frame node has the correct type."); - equal(frame3.getInfo().functionName, "hello/<.world", - "The third frame node has the correct function name."); - equal(frame3.getInfo().fileName, "/", - "The third frame node has the correct file name."); - equal(frame3.getInfo().hostName, "foo", - "The third frame node has the correct host name."); - equal(frame3.getInfo().url, "http://foo/#bar", - "The third frame node has the correct url."); - equal(frame3.getInfo().line, 123, - "The third frame node has the correct line."); - equal(frame3.getInfo().column, 987, - "The third frame node has the correct column."); - equal(frame3.getInfo().categoryData.toSource(), "({})", - "The third frame node has the correct category data."); - equal(frame3.getInfo().isContent, true, - "The third frame node has the correct content flag."); - - let frame4 = new FrameNode("hello/<.world (http://foo/:123:987)", { - location: "hello/<.world (http://foo/:123:987)", - line: 456, - isContent: FrameUtils.isContent({ - location: "hello/<.world (http://foo/:123:987)" - }) - }, false); - - equal(frame4.getInfo().nodeType, "Frame", - "The fourth frame node has the correct type."); - equal(frame4.getInfo().functionName, "hello/<.world", - "The fourth frame node has the correct function name."); - equal(frame4.getInfo().fileName, "/", - "The fourth frame node has the correct file name."); - equal(frame4.getInfo().hostName, "foo", - "The fourth frame node has the correct host name."); - equal(frame4.getInfo().url, "http://foo/", - "The fourth frame node has the correct url."); - equal(frame4.getInfo().line, 123, - "The fourth frame node has the correct line."); - equal(frame4.getInfo().column, 987, - "The fourth frame node has the correct column."); - equal(frame4.getInfo().categoryData.toSource(), "({})", - "The fourth frame node has the correct category data."); - equal(frame4.getInfo().isContent, true, - "The fourth frame node has the correct content flag."); - - let frame5 = new FrameNode("hello/<.world (resource://foo.js -> http://bar/baz.js:123:987)", { - location: "hello/<.world (resource://foo.js -> http://bar/baz.js:123:987)", - line: 456, - isContent: FrameUtils.isContent({ - location: "hello/<.world (resource://foo.js -> http://bar/baz.js:123:987)" - }) - }, false); - - equal(frame5.getInfo().nodeType, "Frame", - "The fifth frame node has the correct type."); - equal(frame5.getInfo().functionName, "hello/<.world", - "The fifth frame node has the correct function name."); - equal(frame5.getInfo().fileName, "baz.js", - "The fifth frame node has the correct file name."); - equal(frame5.getInfo().hostName, "bar", - "The fifth frame node has the correct host name."); - equal(frame5.getInfo().url, "http://bar/baz.js", - "The fifth frame node has the correct url."); - equal(frame5.getInfo().line, 123, - "The fifth frame node has the correct line."); - equal(frame5.getInfo().column, 987, - "The fifth frame node has the correct column."); - equal(frame5.getInfo().categoryData.toSource(), "({})", - "The fifth frame node has the correct category data."); - equal(frame5.getInfo().isContent, false, - "The fifth frame node has the correct content flag."); - - let frame6 = new FrameNode("Foo::Bar::Baz", { - location: "Foo::Bar::Baz", - line: 456, - category: CATEGORY_OTHER, - isContent: FrameUtils.isContent({ + let frames = [ + new FrameNode("hello/<.world (http://foo/bar.js:123:987)", compute({ + location: "hello/<.world (http://foo/bar.js:123:987)", + line: 456, + }), false), + new FrameNode("hello/<.world (http://foo/bar.js#baz:123:987)", compute({ + location: "hello/<.world (http://foo/bar.js#baz:123:987)", + line: 456, + }), false), + new FrameNode("hello/<.world (http://foo/#bar:123:987)", compute({ + location: "hello/<.world (http://foo/#bar:123:987)", + line: 456, + }), false), + new FrameNode("hello/<.world (http://foo/:123:987)", compute({ + location: "hello/<.world (http://foo/:123:987)", + line: 456, + }), false), + new FrameNode("hello/<.world (resource://foo.js -> http://bar/baz.js:123:987)", compute({ + location: "hello/<.world (resource://foo.js -> http://bar/baz.js:123:987)", + line: 456, + }), false), + new FrameNode("Foo::Bar::Baz", compute({ location: "Foo::Bar::Baz", - category: CATEGORY_OTHER - }) - }, false); + line: 456, + category: CATEGORY_OTHER, + }), false), + new FrameNode("EnterJIT", compute({ + location: "EnterJIT", + }), false), + new FrameNode("chrome://browser/content/content.js", compute({ + location: "chrome://browser/content/content.js", + line: 456, + column: 123 + }), false), + new FrameNode("hello/<.world (resource://gre/foo.js:123:434)", compute({ + location: "hello/<.world (resource://gre/foo.js:123:434)", + line: 456 + }), false), + new FrameNode("main (http://localhost:8888/file.js:123:987)", compute({ + location: "main (http://localhost:8888/file.js:123:987)", + line: 123, + }), false), + new FrameNode("main (resource://gre/modules/devtools/timeline.js:123)", compute({ + location: "main (resource://gre/modules/devtools/timeline.js:123)", + }), false), + ]; - equal(frame6.getInfo().nodeType, "Frame", - "The sixth frame node has the correct type."); - equal(frame6.getInfo().functionName, "Foo::Bar::Baz", - "The sixth frame node has the correct function name."); - equal(frame6.getInfo().fileName, null, - "The sixth frame node has the correct file name."); - equal(frame6.getInfo().hostName, null, - "The sixth frame node has the correct host name."); - equal(frame6.getInfo().url, null, - "The sixth frame node has the correct url."); - equal(frame6.getInfo().line, 456, - "The sixth frame node has the correct line."); - equal(frame6.getInfo().categoryData.abbrev, "other", - "The sixth frame node has the correct category data."); - equal(frame6.getInfo().isContent, false, - "The sixth frame node has the correct content flag."); + let fields = ["nodeType", "functionName", "fileName", "hostName", "url", "line", "column", "categoryData.abbrev", "isContent", "port"] + let expected = [ + // nodeType, functionName, fileName, hostName, url, line, column, categoryData.abbrev, isContent, port + ["Frame", "hello/<.world", "bar.js", "foo", "http://foo/bar.js", 123, 987, void 0, true], + ["Frame", "hello/<.world", "bar.js", "foo", "http://foo/bar.js#baz", 123, 987, void 0, true], + ["Frame", "hello/<.world", "/", "foo", "http://foo/#bar", 123, 987, void 0, true], + ["Frame", "hello/<.world", "/", "foo", "http://foo/", 123, 987, void 0, true], + ["Frame", "hello/<.world", "baz.js", "bar", "http://bar/baz.js", 123, 987, "other", false], + ["Frame", "Foo::Bar::Baz", null, null, null, 456, void 0, "other", false], + ["Frame", "EnterJIT", null, null, null, null, null, "js", false], + ["Frame", "chrome://browser/content/content.js", null, null, null, 456, null, "other", false], + ["Frame", "hello/<.world", "foo.js", null, "resource://gre/foo.js", 123, 434, "other", false], + ["Frame", "main", "file.js", "localhost", "http://localhost:8888/file.js", 123, 987, null, true, 8888], + ["Frame", "main", "timeline.js", null, "resource://gre/modules/devtools/timeline.js", 123, null, "tools", false] + ]; - let frame7 = new FrameNode("EnterJIT", { - location: "EnterJIT", - isContent: FrameUtils.isContent({ - location: "EnterJIT" - }) - }, false); + for (let i = 0; i < frames.length; i++) { + let info = frames[i].getInfo(); + let expect = expected[i]; - equal(frame7.getInfo().nodeType, "Frame", - "The seventh frame node has the correct type."); - equal(frame7.getInfo().functionName, "EnterJIT", - "The seventh frame node has the correct function name."); - equal(frame7.getInfo().fileName, null, - "The seventh frame node has the correct file name."); - equal(frame7.getInfo().hostName, null, - "The seventh frame node has the correct host name."); - equal(frame7.getInfo().url, null, - "The seventh frame node has the correct url."); - equal(frame7.getInfo().line, null, - "The seventh frame node has the correct line."); - equal(frame7.getInfo().column, null, - "The seventh frame node has the correct column."); - equal(frame7.getInfo().categoryData.abbrev, "js", - "The seventh frame node has the correct category data."); - equal(frame7.getInfo().isContent, false, - "The seventh frame node has the correct content flag."); - - let frame8 = new FrameNode("chrome://browser/content/content.js", { - location: "chrome://browser/content/content.js", - line: 456, - column: 123 - }, false); - - equal(frame8.getInfo().hostName, null, - "The eighth frame node has the correct host name."); - - let frame9 = new FrameNode("hello/<.world (resource://gre/foo.js:123:434)", { - location: "hello/<.world (resource://gre/foo.js:123:434)", - line: 456 - }, false); - - equal(frame9.getInfo().hostName, null, - "The ninth frame node has the correct host name."); - - let frame10 = new FrameNode("main (http://localhost:8888/file.js:123:987)", { - location: "main (http://localhost:8888/file.js:123:987)", - line: 123, - isContent: FrameUtils.isContent({ - location: "main (http://localhost:8888/file.js:123:987)" - }) - }, false); - - equal(frame10.getInfo().nodeType, "Frame", - "The tenth frame node has the correct type."); - equal(frame10.getInfo().functionName, "main", - "The tenth frame node has the correct function name."); - equal(frame10.getInfo().fileName, "file.js", - "The tenth frame node has the correct file name."); - equal(frame10.getInfo().hostName, "localhost", - "The tenth frame node has the correct host name."); - equal(frame10.getInfo().url, "http://localhost:8888/file.js", - "The tenth frame node has the correct url."); - equal(frame10.getInfo().line, 123, - "The tenth frame node has the correct line."); - equal(frame10.getInfo().column, 987, - "The tenth frame node has the correct column."); - equal(frame10.getInfo().isContent, true, - "The tenth frame node has the correct content flag."); - equal(frame10.getInfo().host, "localhost:8888", - "The tenth frame node has the correct host."); - equal(frame10.getInfo().port, 8888, - "The tenth frame node has the correct port."); + for (let j = 0; j < fields.length; j++) { + let field = fields[j]; + let value = field === "categoryData.abbrev" ? info.categoryData.abbrev : info[field]; + equal(value, expect[j], `${field} for frame #${i} is correct: ${expect[j]}`); + } + } }); diff --git a/browser/devtools/performance/test/unit/test_tree-model-09.js b/browser/devtools/performance/test/unit/test_tree-model-09.js new file mode 100644 index 00000000000..70a411b6f1e --- /dev/null +++ b/browser/devtools/performance/test/unit/test_tree-model-09.js @@ -0,0 +1,82 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Tests that when displaying only content nodes, platform nodes are generalized. + */ + +let { CATEGORY_MASK } = devtools.require("devtools/performance/global"); + +function run_test() { + run_next_test(); +} + +add_task(function test() { + let { ThreadNode } = devtools.require("devtools/performance/tree-model"); + let url = (n) => `http://content/${n}`; + + // Create a root node from a given samples array. + + let root = getFrameNodePath(new ThreadNode(gThread, { contentOnly: true }), "(root)"); + + /* + * should have a tree like: + * root + * - (Tools) + * - A + * - B + * - C + * - D + * - E + * - F + * - (Tools) + */ + + // Test the root node. + + equal(root.calls.length, 2, "root has 2 children"); + ok(getFrameNodePath(root, url("A")), "root has content child"); + ok(getFrameNodePath(root, "9000"), "root has platform generalized child from Chrome JS"); + equal(getFrameNodePath(root, "9000").calls.length, 0, "platform generalized child is a leaf."); + + ok(getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 9000`), + "a second leaf of the generalized Chrome JS exists."); + + equal(getFrameNodePath(root, "9000").category, + getFrameNodePath(root, `${url("A")} > ${url("E")} > ${url("F")} > 9000`).category, + "generalized frames of same type are duplicated in top-down view"); +}); + +let gThread = synthesizeProfileForTest([{ + time: 5, + frames: [ + { location: "(root)" }, + { location: "http://content/A" }, + { location: "http://content/B" }, + { location: "http://content/C" } + ] +}, { + time: 5 + 6, + frames: [ + { location: "(root)" }, + { location: "http://content/A" }, + { location: "http://content/B" }, + { location: "fn (resource://loader.js -> resource:///modules/devtools/timeline.js)" }, + { location: "http://content/D" } + ] +}, { + time: 5 + 6 + 7, + frames: [ + { location: "(root)" }, + { location: "http://content/A" }, + { location: "http://content/E" }, + { location: "http://content/F" }, + { location: "fn (resource://loader.js -> resource://gre/modules/devtools/promise.js)" } + ] +}, { + time: 5 + 20, + frames: [ + { location: "(root)" }, + { location: "somefn (resource://loader.js -> resource:///modules/devtools/framerate.js)" } + ] +}]); diff --git a/browser/devtools/performance/test/unit/xpcshell.ini b/browser/devtools/performance/test/unit/xpcshell.ini index 2a63637b977..deaaa1fd707 100644 --- a/browser/devtools/performance/test/unit/xpcshell.ini +++ b/browser/devtools/performance/test/unit/xpcshell.ini @@ -5,7 +5,9 @@ tail = firefox-appdir = browser skip-if = toolkit == 'android' || toolkit == 'gonk' +[test_profiler-categories.js] [test_frame-utils-01.js] +[test_frame-utils-02.js] [test_tree-model-01.js] [test_tree-model-02.js] [test_tree-model-03.js] @@ -14,3 +16,4 @@ skip-if = toolkit == 'android' || toolkit == 'gonk' [test_tree-model-06.js] [test_tree-model-07.js] [test_tree-model-08.js] +[test_tree-model-09.js] diff --git a/browser/locales/en-US/chrome/browser/devtools/profiler.properties b/browser/locales/en-US/chrome/browser/devtools/profiler.properties index 5bb4a1c7979..dd0a16a8d72 100644 --- a/browser/locales/en-US/chrome/browser/devtools/profiler.properties +++ b/browser/locales/en-US/chrome/browser/devtools/profiler.properties @@ -82,6 +82,7 @@ category.network=Network category.graphics=Graphics category.storage=Storage category.events=Input & Events +category.tools=Tools # LOCALIZATION NOTE (graphs.ms): # This string is displayed in the call tree after units of time in milliseconds. diff --git a/docshell/base/TimelineMarker.cpp b/docshell/base/TimelineMarker.cpp index 2bae8e8e413..90f70f4b04e 100644 --- a/docshell/base/TimelineMarker.cpp +++ b/docshell/base/TimelineMarker.cpp @@ -15,7 +15,7 @@ TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName, MOZ_COUNT_CTOR(TimelineMarker); MOZ_ASSERT(aName); aDocShell->Now(&mTime); - if (aMetaData == TRACING_INTERVAL_START) { + if (aMetaData == TRACING_INTERVAL_START || aMetaData == TRACING_TIMESTAMP) { CaptureStack(); } } @@ -31,7 +31,9 @@ TimelineMarker::TimelineMarker(nsDocShell* aDocShell, const char* aName, MOZ_COUNT_CTOR(TimelineMarker); MOZ_ASSERT(aName); aDocShell->Now(&mTime); - if (aMetaData == TRACING_INTERVAL_START && aStackRequest != NO_STACK) { + if ((aMetaData == TRACING_INTERVAL_START || + aMetaData == TRACING_TIMESTAMP) && + aStackRequest != NO_STACK) { CaptureStack(); } } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index cfa0c8b1ae6..89cc87fd55b 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -2998,6 +2998,7 @@ nsDocShell::PopProfileTimelineMarkers( marker->mName = NS_ConvertUTF8toUTF16(startPayload->GetName()); marker->mStart = startPayload->GetTime(); marker->mEnd = startPayload->GetTime(); + marker->mStack = startPayload->GetStack(); startPayload->AddDetails(aCx, *marker); continue; } diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index c67423b89cc..6ead4e1d8a7 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -1065,7 +1065,6 @@ public: const nsAString& aCause) : TimelineMarker(aDocShell, "TimeStamp", aMetaData, aCause) { - CaptureStack(); MOZ_ASSERT(aMetaData == TRACING_TIMESTAMP); } @@ -1075,7 +1074,6 @@ public: if (!GetCause().IsEmpty()) { aMarker.mCauseName.Construct(GetCause()); } - aMarker.mEndStack = GetStack(); } }; diff --git a/mobile/android/base/DoorHangerPopup.java b/mobile/android/base/DoorHangerPopup.java index c1ef92f6cda..bf4ab4004e8 100644 --- a/mobile/android/base/DoorHangerPopup.java +++ b/mobile/android/base/DoorHangerPopup.java @@ -9,6 +9,7 @@ import java.util.HashSet; import org.json.JSONException; import org.json.JSONObject; +import org.json.JSONArray; import org.mozilla.gecko.AppConstants.Versions; import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.ThreadUtils; @@ -113,9 +114,21 @@ public class DoorHangerPopup extends AnchoredPopup final DoorhangerConfig config = new DoorhangerConfig(tabId, id, doorhangerType, this); config.setMessage(json.getString("message")); - config.appendButtonsFromJSON(json.getJSONArray("buttons")); config.setOptions(json.getJSONObject("options")); + final JSONArray buttonArray = json.getJSONArray("buttons"); + int numButtons = buttonArray.length(); + if (numButtons > 2) { + Log.e(LOGTAG, "Doorhanger can have a maximum of two buttons!"); + numButtons = 2; + } + + for (int i = 0; i < numButtons; i++) { + final JSONObject buttonJSON = buttonArray.getJSONObject(i); + final boolean isPositive = buttonJSON.optBoolean("positive", false); + config.setButton(buttonJSON.getString("label"), buttonJSON.getInt("callback"), isPositive); + } + return config; } diff --git a/mobile/android/base/Tabs.java b/mobile/android/base/Tabs.java index 7f0dc83bdad..628c541b9f1 100644 --- a/mobile/android/base/Tabs.java +++ b/mobile/android/base/Tabs.java @@ -22,6 +22,7 @@ import org.mozilla.gecko.mozglue.ContextUtils.SafeIntent; import org.mozilla.gecko.mozglue.JNITarget; import org.mozilla.gecko.mozglue.RobocopTarget; import org.mozilla.gecko.sync.setup.SyncAccounts; +import org.mozilla.gecko.preferences.GeckoPreferences; import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.ThreadUtils; @@ -853,7 +854,7 @@ public class Tabs implements GeckoEventListener { boolean external = (flags & LOADURL_EXTERNAL) != 0; final SharedPreferences sharedPrefs = GeckoSharedPrefs.forApp(mAppContext); - final boolean isPrivatePref = sharedPrefs.getBoolean("android.not_a_preference.openExternalURLsPrivately", false); + final boolean isPrivatePref = sharedPrefs.getBoolean(GeckoPreferences.PREFS_OPEN_URLS_IN_PRIVATE, false); if (isPrivatePref && external) { isPrivate = true; } diff --git a/mobile/android/base/home/BrowserSearch.java b/mobile/android/base/home/BrowserSearch.java index 2689c53e189..1020bfbf3a6 100644 --- a/mobile/android/base/home/BrowserSearch.java +++ b/mobile/android/base/home/BrowserSearch.java @@ -554,7 +554,7 @@ public class BrowserSearch extends HomeFragment ArrayList searchEngines = new ArrayList(); for (int i = 0; i < engines.length(); i++) { final JSONObject engineJSON = engines.getJSONObject(i); - final SearchEngine engine = new SearchEngine(engineJSON); + final SearchEngine engine = new SearchEngine((Context) getActivity(), engineJSON); if (engine.name.equals(suggestEngine) && suggestTemplate != null) { // Suggest engine should be at the front of the list. diff --git a/mobile/android/base/home/SearchEngine.java b/mobile/android/base/home/SearchEngine.java index 0ee241f5646..268381ae543 100644 --- a/mobile/android/base/home/SearchEngine.java +++ b/mobile/android/base/home/SearchEngine.java @@ -6,11 +6,14 @@ package org.mozilla.gecko.home; import org.mozilla.gecko.gfx.BitmapUtils; +import org.mozilla.gecko.R; import org.json.JSONException; import org.json.JSONObject; +import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.util.Log; import java.util.ArrayList; @@ -25,7 +28,7 @@ public class SearchEngine { private final Bitmap icon; private volatile List suggestions = new ArrayList(); // Never null. - public SearchEngine(JSONObject engineJSON) throws JSONException { + public SearchEngine(final Context context, final JSONObject engineJSON) throws JSONException { if (engineJSON == null) { throw new IllegalArgumentException("Can't instantiate SearchEngine from null JSON."); } @@ -40,10 +43,14 @@ public class SearchEngine { final String iconURI = getString(engineJSON, "iconURI"); if (iconURI == null) { Log.w(LOG_TAG, "iconURI is null for search engine " + this.name); - this.icon = null; - return; } - this.icon = BitmapUtils.getBitmapFromDataURI(iconURI); + final Bitmap tempIcon = BitmapUtils.getBitmapFromDataURI(iconURI); + + this.icon = (tempIcon != null) ? tempIcon : getDefaultFavicon(context); + } + + private Bitmap getDefaultFavicon(final Context context) { + return BitmapFactory.decodeResource(context.getResources(), R.drawable.favicon_search); } private static String getString(JSONObject data, String key) throws JSONException { diff --git a/mobile/android/base/home/SearchEngineBar.java b/mobile/android/base/home/SearchEngineBar.java index 93759bc76b4..128e80d22b8 100644 --- a/mobile/android/base/home/SearchEngineBar.java +++ b/mobile/android/base/home/SearchEngineBar.java @@ -15,6 +15,7 @@ import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.FrameLayout; +import android.widget.ImageView; import org.mozilla.gecko.R; import org.mozilla.gecko.widget.FaviconView; @@ -94,9 +95,9 @@ public class SearchEngineBar extends TwoWayView view = convertView; } - final FaviconView faviconView = (FaviconView) view.findViewById(R.id.search_engine_icon); + final ImageView faviconView = (ImageView) view.findViewById(R.id.search_engine_icon); final SearchEngine searchEngine = searchEngines.get(position); - faviconView.updateAndScaleImage(searchEngine.getIcon(), searchEngine.getEngineIdentifier()); + faviconView.setImageBitmap(searchEngine.getIcon()); final View container = view.findViewById(R.id.search_engine_icon_container); final String desc = getResources().getString(R.string.search_bar_item_desc, searchEngine.getEngineIdentifier()); diff --git a/mobile/android/base/preferences/GeckoPreferences.java b/mobile/android/base/preferences/GeckoPreferences.java index 8a05000850a..d8ac3578449 100644 --- a/mobile/android/base/preferences/GeckoPreferences.java +++ b/mobile/android/base/preferences/GeckoPreferences.java @@ -127,7 +127,7 @@ OnSharedPreferenceChangeListener private static final String PREFS_SYNC = NON_PREF_PREFIX + "sync"; private static final String PREFS_TRACKING_PROTECTION = "privacy.trackingprotection.enabled"; private static final String PREFS_TRACKING_PROTECTION_LEARN_MORE = NON_PREF_PREFIX + "trackingprotection.learn_more"; - private static final String PREFS_OPEN_URLS_IN_PRIVATE = NON_PREF_PREFIX + "openExternalURLsPrivately"; + public static final String PREFS_OPEN_URLS_IN_PRIVATE = NON_PREF_PREFIX + "openExternalURLsPrivately"; private static final String ACTION_STUMBLER_UPLOAD_PREF = AppConstants.ANDROID_PACKAGE_NAME + ".STUMBLER_PREF"; @@ -703,9 +703,9 @@ OnSharedPreferenceChangeListener preferences.removePreference(pref); i--; continue; - } else if (AppConstants.RELEASE_BUILD && + } else if (!AppConstants.NIGHTLY_BUILD && PREFS_OPEN_URLS_IN_PRIVATE.equals(key)) { - // Remove UI for opening external links in private borwsing onrelease builds. + // Remove UI for opening external links in private browsing on non-Nightly builds. preferences.removePreference(pref); i--; continue; diff --git a/mobile/android/base/resources/drawable/action_bar_button_negative.xml b/mobile/android/base/resources/drawable/action_bar_button_negative.xml new file mode 100644 index 00000000000..7611d70ba5f --- /dev/null +++ b/mobile/android/base/resources/drawable/action_bar_button_negative.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/base/resources/drawable/action_bar_button_positive.xml b/mobile/android/base/resources/drawable/action_bar_button_positive.xml new file mode 100644 index 00000000000..ac7020b97c6 --- /dev/null +++ b/mobile/android/base/resources/drawable/action_bar_button_positive.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + diff --git a/mobile/android/base/resources/layout/default_doorhanger.xml b/mobile/android/base/resources/layout/default_doorhanger.xml new file mode 100644 index 00000000000..d1e57c382a0 --- /dev/null +++ b/mobile/android/base/resources/layout/default_doorhanger.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/mobile/android/base/resources/layout/doorhanger.xml b/mobile/android/base/resources/layout/doorhanger.xml index be3c4ab88a3..777aad929e7 100644 --- a/mobile/android/base/resources/layout/doorhanger.xml +++ b/mobile/android/base/resources/layout/doorhanger.xml @@ -5,51 +5,41 @@ - - + android:layout_height="wrap_content"/> - - - - - - - + android:orientation="horizontal"> + +