merge fx-team to mozilla-central

This commit is contained in:
Carsten "Tomcat" Book 2013-11-29 10:13:09 +01:00
commit aa2c8950fa
87 changed files with 1040 additions and 653 deletions

View File

@ -11,9 +11,9 @@
#endif
oncommand="MultiplexHandler(event)"
#ifdef OMIT_ACCESSKEYS
onpopupshowing="CharsetMenu.build(event);"
#expand onpopupshowing="CharsetMenu.build(event, '__ID_PREFIX__');"
#else
onpopupshowing="CharsetMenu.build(event, true);"
#expand onpopupshowing="CharsetMenu.build(event, '__ID_PREFIX__', true);"
#endif
onpopupshown="UpdateMenus(event);">
<menupopup>

View File

@ -276,8 +276,8 @@
#endif
/>
<key id="key_devToolboxMenuItem" keycode="&devToolboxMenuItem.keycode;"
keytext="&devToolboxMenuItem.keytext;" command="Tools:DevToolbox" key="&devToolboxMenuItem.keytext;"
<key id="key_devToolboxMenuItem" keytext="&devToolboxMenuItem.keytext;"
command="Tools:DevToolbox" key="&devToolboxMenuItem.keytext;"
#ifdef XP_MACOSX
modifiers="accel,alt"
#else

View File

@ -9,6 +9,7 @@ let Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/NotificationDB.jsm");
Cu.import("resource:///modules/RecentWindow.jsm");
Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
@ -1151,14 +1152,10 @@ var gBrowserInit = {
Cu.reportError("Could not end startup crash tracking: " + ex);
}
#ifdef XP_WIN
#ifdef MOZ_METRO
gMetroPrefs.prefDomain.forEach(function(prefName) {
gMetroPrefs.pushDesktopControlledPrefToMetro(prefName);
Services.prefs.addObserver(prefName, gMetroPrefs, false);
}, this);
#endif
#endif
if (typeof WindowsPrefSync !== 'undefined') {
// Pulls in Metro controlled prefs and pushes out Desktop controlled prefs
WindowsPrefSync.init();
}
if (gMultiProcessBrowser) {
// Bug 862519 - Backspace doesn't work in electrolysis builds.
@ -1280,13 +1277,9 @@ var gBrowserInit = {
Cu.reportError(ex);
}
#ifdef XP_WIN
#ifdef MOZ_METRO
gMetroPrefs.prefDomain.forEach(function(prefName) {
Services.prefs.removeObserver(prefName, gMetroPrefs);
});
#endif
#endif
if (typeof WindowsPrefSync !== 'undefined') {
WindowsPrefSync.uninit();
}
BrowserOffline.uninit();
OfflineApps.uninit();
@ -2460,6 +2453,49 @@ function BrowserFullScreen()
window.fullScreen = !window.fullScreen;
}
function _checkDefaultAndSwitchToMetro() {
#ifdef HAVE_SHELL_SERVICE
#ifdef XP_WIN
#ifdef MOZ_METRO
let shell = Components.classes["@mozilla.org/browser/shell-service;1"].
getService(Components.interfaces.nsIShellService);
let isDefault = shell.isDefaultBrowser(false, false);
if (isDefault) {
let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
getService(Components.interfaces.nsIAppStartup);
Services.prefs.setBoolPref('browser.sessionstore.resume_session_once', true);
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
Components.interfaces.nsIAppStartup.eRestartTouchEnvironment);
return true;
}
return false;
#endif
#endif
#endif
}
function SwitchToMetro() {
#ifdef HAVE_SHELL_SERVICE
#ifdef XP_WIN
#ifdef MOZ_METRO
if (this._checkDefaultAndSwitchToMetro()) {
return;
}
let shell = Components.classes["@mozilla.org/browser/shell-service;1"].
getService(Components.interfaces.nsIShellService);
shell.setDefaultBrowser(false, false);
let intervalID = window.setInterval(this._checkDefaultAndSwitchToMetro, 1000);
window.setTimeout(function() { window.clearInterval(intervalID); }, 10000);
#endif
#endif
#endif
}
function onFullScreen(event) {
FullScreen.toggle(event);
}
@ -4149,6 +4185,14 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) {
}
}
let addToPanel = popup.querySelector(".customize-context-addToPanel");
let removeFromToolbar = popup.querySelector(".customize-context-removeFromToolbar");
// View -> Toolbars menu doesn't have the addToPanel or removeFromToolbar items.
if (!addToPanel || !removeFromToolbar) {
return;
}
// The explicitOriginalTarget can be a nested child element of a toolbaritem.
let toolbarItem = aEvent.explicitOriginalTarget;
@ -4167,17 +4211,10 @@ function onViewToolbarsPopupShowing(aEvent, aInsertPoint) {
// Right-clicking on an empty part of the tabstrip will exit
// the above loop with toolbarItem being the xul:document.
if (!toolbarItem.parentNode) {
return;
}
let addToPanel = popup.querySelector(".customize-context-addToPanel");
let removeFromToolbar = popup.querySelector(".customize-context-removeFromToolbar");
// View -> Toolbars menu doesn't have the addToPanel or removeFromToolbar items.
if (!addToPanel || !removeFromToolbar) {
return;
}
let movable = toolbarItem && CustomizableUI.isWidgetRemovable(toolbarItem);
// That has no parentNode, and we should disable the items in
// this case.
let movable = toolbarItem && toolbarItem.parentNode &&
CustomizableUI.isWidgetRemovable(toolbarItem);
if (movable) {
addToPanel.removeAttribute("disabled");
removeFromToolbar.removeAttribute("disabled");
@ -4639,60 +4676,6 @@ function fireSidebarFocusedEvent() {
sidebar.contentWindow.dispatchEvent(event);
}
#ifdef XP_WIN
#ifdef MOZ_METRO
/**
* Some prefs that have consequences in both Metro and Desktop such as
* app-update prefs, are automatically pushed from Desktop here for use
* in Metro.
*/
var gMetroPrefs = {
prefDomain: ["app.update.auto", "app.update.enabled",
"app.update.service.enabled",
"app.update.metro.enabled"],
observe: function (aSubject, aTopic, aPrefName)
{
if (aTopic != "nsPref:changed")
return;
this.pushDesktopControlledPrefToMetro(aPrefName);
},
/**
* Writes the pref to HKCU in the registry and adds a pref-observer to keep
* the registry in sync with changes to the value.
*/
pushDesktopControlledPrefToMetro: function(aPrefName) {
let registry = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
try {
var prefType = Services.prefs.getPrefType(aPrefName);
let prefFunc;
if (prefType == Components.interfaces.nsIPrefBranch.PREF_INT)
prefFunc = "getIntPref";
else if (prefType == Components.interfaces.nsIPrefBranch.PREF_BOOL)
prefFunc = "getBoolPref";
else if (prefType == Components.interfaces.nsIPrefBranch.PREF_STRING)
prefFunc = "getCharPref";
else
throw "Unsupported pref type";
let prefValue = Services.prefs[prefFunc](aPrefName);
registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
"Software\\Mozilla\\Firefox\\Metro\\Prefs\\" + prefType,
Ci.nsIWindowsRegKey.ACCESS_WRITE);
// Always write as string, but the registry subfolder will determine
// how Metro interprets that string value.
registry.writeStringValue(aPrefName, prefValue);
} catch (ex) {
Components.utils.reportError("Couldn't push pref " + aPrefName + ": " + ex);
} finally {
registry.close();
}
}
};
#endif
#endif
var gHomeButton = {
prefDomain: "browser.startup.homepage",
@ -5087,7 +5070,7 @@ function MultiplexHandler(event)
SelectDetector(event, false);
} else if (name == 'charsetGroup') {
var charset = node.getAttribute('id');
charset = charset.substring('charset.'.length, charset.length)
charset = charset.substring(charset.indexOf('charset.') + 'charset.'.length);
BrowserSetForcedCharacterSet(charset);
} else if (name == 'charsetCustomize') {
//do nothing - please remove this else statement, once the charset prefs moves to the pref window
@ -5100,7 +5083,7 @@ function MultiplexHandler(event)
function SelectDetector(event, doReload)
{
var uri = event.target.getAttribute("id");
var prefvalue = uri.substring('chardet.'.length, uri.length);
var prefvalue = uri.substring(uri.indexOf('chardet.') + 'chardet.'.length);
if ("off" == prefvalue) { // "off" is special value to turn off the detectors
prefvalue = "";
}

View File

@ -472,13 +472,6 @@ var gSyncSetup = {
Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase();
this._handleNoScript(false);
Weave.Svc.Prefs.set("firstSync", "newAccount");
#ifdef XP_WIN
#ifdef MOZ_METRO
if (document.getElementById("metroSetupCheckbox").checked) {
Services.metro.storeSyncInfo(email, password, Weave.Service.identity.syncKey);
}
#endif
#endif
this.wizardFinish();
return false;
}

View File

@ -172,20 +172,6 @@
<label class="status" value=" "/>
</hbox>
</row>
#ifdef XP_WIN
#ifdef MOZ_METRO
<row id="metroRow" align="center">
<spacer/>
<hbox align="center">
<checkbox label="&setup.setupMetro.label;"
accesskey="&setup.setupMetro.accesskey;"
control="weavePasswordConfirm"
id="metroSetupCheckbox"
checked="true"/>
</hbox>
</row>
#endif
#endif
<row id="TOSRow" align="center">
<spacer/>
<hbox align="center">

View File

@ -220,8 +220,11 @@ const PanelUI = {
CustomizableUI.registerMenuPanel(this.contents);
} else {
this.beginBatchUpdate();
CustomizableUI.registerMenuPanel(this.contents);
this.endBatchUpdate();
try {
CustomizableUI.registerMenuPanel(this.contents);
} finally {
this.endBatchUpdate();
}
}
this.panel.hidden = false;
}.bind(this)).then(null, Cu.reportError);

View File

@ -193,29 +193,32 @@
// Get a list of items only in the new list
let newIds = [id for (id of newVal) if (oldIds.indexOf(id) == -1)];
CustomizableUI.beginBatchUpdate();
for (let newId of newIds) {
oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
let nextId = newId;
let pos;
do {
// Get the next item
nextId = newVal[newVal.indexOf(nextId) + 1];
// Figure out where it is in the old list
pos = oldIds.indexOf(nextId);
// If it's not in the old list, repeat:
} while (pos == -1 && nextId);
if (pos == -1) {
pos = null; // We didn't find anything, insert at the end
try {
for (let newId of newIds) {
oldIds = CustomizableUI.getWidgetIdsInArea(this.id);
let nextId = newId;
let pos;
do {
// Get the next item
nextId = newVal[newVal.indexOf(nextId) + 1];
// Figure out where it is in the old list
pos = oldIds.indexOf(nextId);
// If it's not in the old list, repeat:
} while (pos == -1 && nextId);
if (pos == -1) {
pos = null; // We didn't find anything, insert at the end
}
CustomizableUI.addWidgetToArea(newId, this.id, pos);
}
CustomizableUI.addWidgetToArea(newId, this.id, pos);
}
let currentIds = this.currentSet.split(',');
let removedIds = [id for (id of currentIds) if (newIds.indexOf(id) == -1 && newVal.indexOf(id) == -1)];
for (let removedId of removedIds) {
CustomizableUI.removeWidgetFromArea(removedId);
let currentIds = this.currentSet.split(',');
let removedIds = [id for (id of currentIds) if (newIds.indexOf(id) == -1 && newVal.indexOf(id) == -1)];
for (let removedId of removedIds) {
CustomizableUI.removeWidgetFromArea(removedId);
}
} finally {
CustomizableUI.endBatchUpdate();
}
CustomizableUI.endBatchUpdate();
]]></setter>
</property>

View File

@ -141,8 +141,28 @@ let CustomizableUIInternal = {
"fullscreen-button",
"find-button",
"preferences-button",
"add-ons-button",
"add-ons-button"
];
#ifdef XP_WIN
#ifdef MOZ_METRO
// Show switch-to-metro-button if in Windows 8.
let isMetroCapable = false;
try {
// Windows 8 is version 6.2.
let version = Cc["@mozilla.org/system-info;1"]
.getService(Ci.nsIPropertyBag2)
.getProperty("version");
isMetroCapable = (parseFloat(version) >= 6.2);
} catch (ex) { }
if (isMetroCapable) {
// TODO: Bug 942915 - Place 'Metro Mode' button as a default
// for Windows 8 in the customization panel.
}
#endif
#endif
let showCharacterEncoding = Services.prefs.getComplexValue(
"browser.menu.showCharacterEncoding",
Ci.nsIPrefLocalizedString
@ -279,15 +299,18 @@ let CustomizableUIInternal = {
// Move all the widgets out
this.beginBatchUpdate();
let placements = gPlacements.get(aName);
placements.forEach(this.removeWidgetFromArea, this);
try {
let placements = gPlacements.get(aName);
placements.forEach(this.removeWidgetFromArea, this);
// Delete all remaining traces.
gAreas.delete(aName);
gPlacements.delete(aName);
gFuturePlacements.delete(aName);
gBuildAreas.delete(aName);
this.endBatchUpdate(true);
// Delete all remaining traces.
gAreas.delete(aName);
gPlacements.delete(aName);
gFuturePlacements.delete(aName);
gBuildAreas.delete(aName);
} finally {
this.endBatchUpdate(true);
}
},
registerToolbarNode: function(aToolbar, aExistingChildren) {
@ -295,7 +318,6 @@ let CustomizableUIInternal = {
if (gBuildAreas.has(area) && gBuildAreas.get(area).has(aToolbar)) {
return;
}
this.beginBatchUpdate();
let document = aToolbar.ownerDocument;
let areaProperties = gAreas.get(area);
@ -303,44 +325,48 @@ let CustomizableUIInternal = {
throw new Error("Unknown customization area: " + area);
}
let placements = gPlacements.get(area);
if (!placements && areaProperties.has("legacy")) {
let legacyState = aToolbar.getAttribute("currentset");
if (legacyState) {
legacyState = legacyState.split(",").filter(s => s);
this.beginBatchUpdate();
try {
let placements = gPlacements.get(area);
if (!placements && areaProperties.has("legacy")) {
let legacyState = aToolbar.getAttribute("currentset");
if (legacyState) {
legacyState = legacyState.split(",").filter(s => s);
}
// Manually restore the state here, so the legacy state can be converted.
this.restoreStateForArea(area, legacyState);
placements = gPlacements.get(area);
}
// Manually restore the state here, so the legacy state can be converted.
this.restoreStateForArea(area, legacyState);
placements = gPlacements.get(area);
}
// Check that the current children and the current placements match. If
// not, mark it as dirty:
if (aExistingChildren.length != placements.length ||
aExistingChildren.every((id, i) => id == placements[i])) {
gDirtyAreaCache.add(area);
}
// Check that the current children and the current placements match. If
// not, mark it as dirty:
if (aExistingChildren.length != placements.length ||
aExistingChildren.every((id, i) => id == placements[i])) {
gDirtyAreaCache.add(area);
}
if (areaProperties.has("overflowable")) {
aToolbar.overflowable = new OverflowableToolbar(aToolbar);
}
if (areaProperties.has("overflowable")) {
aToolbar.overflowable = new OverflowableToolbar(aToolbar);
}
this.registerBuildArea(area, aToolbar);
this.registerBuildArea(area, aToolbar);
// We only build the toolbar if it's been marked as "dirty". Dirty means
// one of the following things:
// 1) Items have been added, moved or removed from this toolbar before.
// 2) The number of children of the toolbar does not match the length of
// the placements array for that area.
//
// This notion of being "dirty" is stored in a cache which is persisted
// in the saved state.
if (gDirtyAreaCache.has(area)) {
this.buildArea(area, placements, aToolbar);
// We only build the toolbar if it's been marked as "dirty". Dirty means
// one of the following things:
// 1) Items have been added, moved or removed from this toolbar before.
// 2) The number of children of the toolbar does not match the length of
// the placements array for that area.
//
// This notion of being "dirty" is stored in a cache which is persisted
// in the saved state.
if (gDirtyAreaCache.has(area)) {
this.buildArea(area, placements, aToolbar);
}
aToolbar.setAttribute("currentset", placements.join(","));
} finally {
this.endBatchUpdate();
}
aToolbar.setAttribute("currentset", placements.join(","));
this.endBatchUpdate();
},
buildArea: function(aArea, aPlacements, aAreaNode) {
@ -354,110 +380,112 @@ let CustomizableUIInternal = {
+ " to have a customizationTarget attribute.");
}
this.beginBatchUpdate();
// Restore nav-bar visibility since it may have been hidden
// through a migration path (bug 938980) or an add-on.
if (aArea == CustomizableUI.AREA_NAVBAR) {
aAreaNode.collapsed = false;
}
let currentNode = container.firstChild;
let placementsToRemove = new Set();
for (let id of aPlacements) {
while (currentNode && currentNode.getAttribute("skipintoolbarset") == "true") {
currentNode = currentNode.nextSibling;
}
this.beginBatchUpdate();
if (currentNode && currentNode.id == id) {
currentNode = currentNode.nextSibling;
continue;
}
try {
let currentNode = container.firstChild;
let placementsToRemove = new Set();
for (let id of aPlacements) {
while (currentNode && currentNode.getAttribute("skipintoolbarset") == "true") {
currentNode = currentNode.nextSibling;
}
let [provider, node] = this.getWidgetNode(id, window);
if (!node) {
LOG("Unknown widget: " + id);
continue;
}
// If the placements have items in them which are (now) no longer removable,
// we shouldn't be moving them:
if (node.parentNode != container && !this.isWidgetRemovable(node)) {
placementsToRemove.add(id);
continue;
}
if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) {
let widget = gPalette.get(id);
if (!widget.showInPrivateBrowsing && inPrivateWindow) {
if (currentNode && currentNode.id == id) {
currentNode = currentNode.nextSibling;
continue;
}
}
this.ensureButtonContextMenu(node, aAreaNode);
if (node.localName == "toolbarbutton" && aArea == CustomizableUI.AREA_PANEL) {
node.setAttribute("tabindex", "0");
if (!node.hasAttribute("type")) {
node.setAttribute("type", "wrap");
let [provider, node] = this.getWidgetNode(id, window);
if (!node) {
LOG("Unknown widget: " + id);
continue;
}
}
this.insertWidgetBefore(node, currentNode, container, aArea);
if (gResetting) {
this.notifyListeners("onWidgetReset", id, aArea);
}
}
// If the placements have items in them which are (now) no longer removable,
// we shouldn't be moving them:
if (node.parentNode != container && !this.isWidgetRemovable(node)) {
placementsToRemove.add(id);
continue;
}
if (currentNode) {
let palette = aAreaNode.toolbox ? aAreaNode.toolbox.palette : null;
let limit = currentNode.previousSibling;
let node = container.lastChild;
while (node && node != limit) {
let previousSibling = node.previousSibling;
// Nodes opt-in to removability. If they're removable, and we haven't
// seen them in the placements array, then we toss them into the palette
// if one exists. If no palette exists, we just remove the node. If the
// node is not removable, we leave it where it is. However, we can only
// safely touch elements that have an ID - both because we depend on
// IDs, and because such elements are not intended to be widgets
// (eg, titlebar-placeholder elements).
if (node.id && node.getAttribute("skipintoolbarset") != "true") {
if (this.isWidgetRemovable(node)) {
if (palette && !this.isSpecialWidget(node.id)) {
palette.appendChild(node);
this.removeLocationAttributes(node);
} else {
container.removeChild(node);
}
} else {
this.setLocationAttributes(currentNode, aArea);
node.setAttribute("removable", false);
LOG("Adding non-removable widget to placements of " + aArea + ": " +
node.id);
gPlacements.get(aArea).push(node.id);
gDirty = true;
if (inPrivateWindow && provider == CustomizableUI.PROVIDER_API) {
let widget = gPalette.get(id);
if (!widget.showInPrivateBrowsing && inPrivateWindow) {
continue;
}
}
node = previousSibling;
this.ensureButtonContextMenu(node, aAreaNode);
if (node.localName == "toolbarbutton" && aArea == CustomizableUI.AREA_PANEL) {
node.setAttribute("tabindex", "0");
if (!node.hasAttribute("type")) {
node.setAttribute("type", "wrap");
}
}
this.insertWidgetBefore(node, currentNode, container, aArea);
if (gResetting) {
this.notifyListeners("onWidgetReset", id, aArea);
}
}
}
// If there are placements in here which aren't removable from their original area,
// we remove them from this area's placement array. They will (have) be(en) added
// to their original area's placements array in the block above this one.
if (placementsToRemove.size) {
let placementAry = gPlacements.get(aArea);
for (let id of placementsToRemove) {
let index = placementAry.indexOf(id);
placementAry.splice(index, 1);
if (currentNode) {
let palette = aAreaNode.toolbox ? aAreaNode.toolbox.palette : null;
let limit = currentNode.previousSibling;
let node = container.lastChild;
while (node && node != limit) {
let previousSibling = node.previousSibling;
// Nodes opt-in to removability. If they're removable, and we haven't
// seen them in the placements array, then we toss them into the palette
// if one exists. If no palette exists, we just remove the node. If the
// node is not removable, we leave it where it is. However, we can only
// safely touch elements that have an ID - both because we depend on
// IDs, and because such elements are not intended to be widgets
// (eg, titlebar-placeholder elements).
if (node.id && node.getAttribute("skipintoolbarset") != "true") {
if (this.isWidgetRemovable(node)) {
if (palette && !this.isSpecialWidget(node.id)) {
palette.appendChild(node);
this.removeLocationAttributes(node);
} else {
container.removeChild(node);
}
} else {
this.setLocationAttributes(currentNode, aArea);
node.setAttribute("removable", false);
LOG("Adding non-removable widget to placements of " + aArea + ": " +
node.id);
gPlacements.get(aArea).push(node.id);
gDirty = true;
}
}
node = previousSibling;
}
}
}
if (gResetting) {
this.notifyListeners("onAreaReset", aArea);
}
// If there are placements in here which aren't removable from their original area,
// we remove them from this area's placement array. They will (have) be(en) added
// to their original area's placements array in the block above this one.
if (placementsToRemove.size) {
let placementAry = gPlacements.get(aArea);
for (let id of placementsToRemove) {
let index = placementAry.indexOf(id);
placementAry.splice(index, 1);
}
}
this.endBatchUpdate();
if (gResetting) {
this.notifyListeners("onAreaReset", aArea);
}
} finally {
this.endBatchUpdate();
}
},
addPanelCloseListeners: function(aPanel) {
@ -958,6 +986,12 @@ let CustomizableUIInternal = {
"' not found!");
}
}
if (aWidget.id == "switch-to-metro-button") {
let brandBundle = aDocument.getElementById("bundle_brand");
let brandShortName = brandBundle.getString("brandShortName");
additionalTooltipArguments = [brandShortName];
}
let tooltip = this.getLocalizedProperty(aWidget, "tooltiptext", additionalTooltipArguments);
node.setAttribute("tooltiptext", tooltip);
node.setAttribute("class", "toolbarbutton-1 chromeclass-toolbar-additional");
@ -1382,51 +1416,54 @@ let CustomizableUIInternal = {
}
this.beginBatchUpdate();
gRestoring = true;
try {
gRestoring = true;
let restored = false;
gPlacements.set(aArea, []);
let restored = false;
gPlacements.set(aArea, []);
if (gSavedState && aArea in gSavedState.placements) {
LOG("Restoring " + aArea + " from saved state");
let placements = gSavedState.placements[aArea];
for (let id of placements)
this.addWidgetToArea(id, aArea);
gDirty = false;
restored = true;
}
if (!restored && aLegacyState) {
LOG("Restoring " + aArea + " from legacy state");
for (let id of aLegacyState)
this.addWidgetToArea(id, aArea);
// Don't override dirty state, to ensure legacy state is saved here and
// therefore only used once.
restored = true;
}
if (!restored) {
LOG("Restoring " + aArea + " from default state");
let defaults = gAreas.get(aArea).get("defaultPlacements");
if (defaults) {
for (let id of defaults)
this.addWidgetToArea(id, aArea, null, true);
if (gSavedState && aArea in gSavedState.placements) {
LOG("Restoring " + aArea + " from saved state");
let placements = gSavedState.placements[aArea];
for (let id of placements)
this.addWidgetToArea(id, aArea);
gDirty = false;
restored = true;
}
gDirty = false;
if (!restored && aLegacyState) {
LOG("Restoring " + aArea + " from legacy state");
for (let id of aLegacyState)
this.addWidgetToArea(id, aArea);
// Don't override dirty state, to ensure legacy state is saved here and
// therefore only used once.
restored = true;
}
if (!restored) {
LOG("Restoring " + aArea + " from default state");
let defaults = gAreas.get(aArea).get("defaultPlacements");
if (defaults) {
for (let id of defaults)
this.addWidgetToArea(id, aArea, null, true);
}
gDirty = false;
}
// Finally, add widgets to the area that were added before the it was able
// to be restored. This can occur when add-ons register widgets for a
// lazily-restored area before it's been restored.
if (gFuturePlacements.has(aArea)) {
for (let id of gFuturePlacements.get(aArea))
this.addWidgetToArea(id, aArea);
}
LOG("Placements for " + aArea + ":\n\t" + gPlacements.get(aArea).join("\n\t"));
gRestoring = false;
} finally {
this.endBatchUpdate();
}
// Finally, add widgets to the area that were added before the it was able
// to be restored. This can occur when add-ons register widgets for a
// lazily-restored area before it's been restored.
if (gFuturePlacements.has(aArea)) {
for (let id of gFuturePlacements.get(aArea))
this.addWidgetToArea(id, aArea);
}
LOG("Placements for " + aArea + ":\n\t" + gPlacements.get(aArea).join("\n\t"));
gRestoring = false;
this.endBatchUpdate();
},
saveState: function() {
@ -1581,17 +1618,19 @@ let CustomizableUIInternal = {
// seen before, then add it to its default area so it can be used.
if (autoAdd && !widget.currentArea && !gSeenWidgets.has(widget.id)) {
this.beginBatchUpdate();
gSeenWidgets.add(widget.id);
try {
gSeenWidgets.add(widget.id);
if (widget.defaultArea) {
if (this.isAreaLazy(widget.defaultArea)) {
gFuturePlacements.get(widget.defaultArea).add(widget.id);
} else {
this.addWidgetToArea(widget.id, widget.defaultArea);
if (widget.defaultArea) {
if (this.isAreaLazy(widget.defaultArea)) {
gFuturePlacements.get(widget.defaultArea).add(widget.id);
} else {
this.addWidgetToArea(widget.id, widget.defaultArea);
}
}
} finally {
this.endBatchUpdate(true);
}
this.endBatchUpdate(true);
}
}
@ -1642,6 +1681,10 @@ let CustomizableUIInternal = {
return null;
}
if (aData.id == "switch-to-metro-button") {
widget.showInPrivateBrowsing = false;
}
delete widget.implementation.currentArea;
widget.implementation.__defineGetter__("currentArea", function() widget.currentArea);

View File

@ -259,6 +259,18 @@ const CustomizableWidgets = [{
aEvent.target.removeEventListener("command",
win.PanelUI.onCommandHandler);
}
}, {
id: "switch-to-metro-button",
removable: true,
defaultArea: CustomizableUI.AREA_PANEL,
onCommand: function(aEvent) {
let win = aEvent.target &&
aEvent.target.ownerDocument &&
aEvent.target.ownerDocument.defaultView;
if (win && typeof win.SwitchToMetro == "function") {
win.SwitchToMetro();
}
}
}, {
id: "add-ons-button",
removable: true,

View File

@ -93,6 +93,9 @@ CustomizeMode.prototype = {
return;
}
let window = this.window;
let document = this.document;
Task.spawn(function() {
// We shouldn't start customize mode until after browser-delayed-startup has finished:
if (!this.window.gBrowserInit.delayedStartupFinished) {
@ -115,9 +118,6 @@ CustomizeMode.prototype = {
this.dispatchToolboxEvent("beforecustomization");
CustomizableUI.notifyStartCustomizing(this.window);
let window = this.window;
let document = this.document;
// Add a keypress listener to the document so that we can quickly exit
// customization mode when pressing ESC.
document.addEventListener("keypress", this);
@ -159,7 +159,6 @@ CustomizeMode.prototype = {
}
this._showPanelCustomizationPlaceholders();
CustomizableUI.addListener(this);
yield this._wrapToolbarItems();
yield this.populatePalette();
@ -184,11 +183,16 @@ CustomizeMode.prototype = {
for (let toolbar of customizableToolbars)
toolbar.setAttribute("customizing", true);
CustomizableUI.addListener(this);
window.PanelUI.endBatchUpdate();
this._customizing = true;
this._transitioning = false;
this.dispatchToolboxEvent("customizationready");
}.bind(this)).then(null, ERROR);
}.bind(this)).then(null, function(e) {
ERROR(e);
// We should ensure this has been called, and calling it again doesn't hurt:
window.PanelUI.endBatchUpdate();
});
},
exit: function() {
@ -298,7 +302,11 @@ CustomizeMode.prototype = {
this._transitioning = false;
this.dispatchToolboxEvent("aftercustomization");
CustomizableUI.notifyEndCustomizing(this.window);
}.bind(this)).then(null, ERROR);
}.bind(this)).then(null, function(e) {
ERROR(e);
// We should ensure this has been called, and calling it again doesn't hurt:
window.PanelUI.endBatchUpdate();
});
},
/**

View File

@ -1591,7 +1591,7 @@ BrowserGlue.prototype = {
// be set to the version it has been added in, we will compare its value
// to users' smartBookmarksVersion and add new smart bookmarks without
// recreating old deleted ones.
const SMART_BOOKMARKS_VERSION = 4;
const SMART_BOOKMARKS_VERSION = 5;
const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion";
@ -1652,7 +1652,21 @@ BrowserGlue.prototype = {
parent: PlacesUtils.bookmarksMenuFolderId,
position: menuIndex++,
newInVersion: 1
}
},
FirefoxTouch: {
title: bundle.GetStringFromName("firefoxTouchTitle"),
uri: NetUtil.newURI("place:folder=" +
PlacesUtils.annotations.getItemsWithAnnotation('metro/bookmarksRoot', {})[0] +
"&queryType=" +
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS +
"&sort=" +
Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING +
"&maxResults=" + MAX_RESULTS +
"&excludeQueries=1"),
parent: PlacesUtils.bookmarksMenuFolderId,
position: menuIndex++,
newInVersion: 5
},
};
// Set current itemId, parent and position if Smart Bookmark exists,

View File

@ -63,9 +63,9 @@ let (XULAppInfo = {
}
// Smart bookmarks constants.
const SMART_BOOKMARKS_VERSION = 4;
const SMART_BOOKMARKS_VERSION = 5;
const SMART_BOOKMARKS_ON_TOOLBAR = 1;
const SMART_BOOKMARKS_ON_MENU = 3; // Takes in count the additional separator.
const SMART_BOOKMARKS_ON_MENU = 4; // Takes in count the additional separator.
// Default bookmarks constants.
const DEFAULT_BOOKMARKS_ON_TOOLBAR = 1;

View File

@ -650,6 +650,16 @@ let SessionStoreInternal = {
TabState.onBrowserContentsSwapped(browser, otherBrowser);
TabStateCache.onBrowserContentsSwapped(browser, otherBrowser);
break;
case "UserTypedValueChanged":
browser = aEvent.currentTarget;
if (browser.userTypedValue) {
TabStateCache.updateField(browser, "userTypedValue", browser.userTypedValue);
TabStateCache.updateField(browser, "userTypedClear", browser.userTypedClear);
} else {
TabStateCache.removeField(browser, "userTypedValue");
TabStateCache.removeField(browser, "userTypedClear");
}
break;
case "TabOpen":
this.onTabAdd(win, aEvent.originalTarget);
break;
@ -1235,6 +1245,7 @@ let SessionStoreInternal = {
let browser = aTab.linkedBrowser;
browser.addEventListener("load", this, true);
browser.addEventListener("SwapDocShells", this, true);
browser.addEventListener("UserTypedValueChanged", this, true);
let mm = browser.messageManager;
MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
@ -1262,6 +1273,7 @@ let SessionStoreInternal = {
let browser = aTab.linkedBrowser;
browser.removeEventListener("load", this, true);
browser.removeEventListener("SwapDocShells", this, true);
browser.removeEventListener("UserTypedValueChanged", this, true);
let mm = browser.messageManager;
MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));

View File

@ -236,7 +236,6 @@ let TabStateCacheInternal = {
if (data) {
data[aField] = aValue;
}
TabStateCacheTelemetry.recordAccess(!!data);
},
/**
@ -252,7 +251,6 @@ let TabStateCacheInternal = {
if (data && aField in data) {
delete data[aField];
}
TabStateCacheTelemetry.recordAccess(!!data);
},
/**

View File

@ -189,14 +189,17 @@ let DebuggerView = {
dumpn("Initializing the DebuggerView editor");
let extraKeys = {};
let tokenSearch = document.getElementById("tokenSearchKey").getAttribute("key");
let globalSearch = document.getElementById("globalSearchKey").getAttribute("key");
let tokenSearchShortcut = Editor.accel(tokenSearch);
let globalSearchShortcut = Editor.accel(globalSearch, { alt: true });
extraKeys[tokenSearchShortcut] = () => this.Filtering._doTokenSearch();
extraKeys[globalSearchShortcut] = () => this.Filtering._doGlobalSearch();
bindKey("_doTokenSearch", "tokenSearchKey");
bindKey("_doGlobalSearch", "globalSearchKey", { alt: true });
bindKey("_doFunctionSearch", "functionSearchKey");
extraKeys[Editor.keyFor("jumpToLine")] = false;
function bindKey(func, key, modifiers = {}) {
let key = document.getElementById(key).getAttribute("key");
let shortcut = Editor.accel(key, modifiers);
extraKeys[shortcut] = () => DebuggerView.Filtering[func]();
}
this.editor = new Editor({
mode: Editor.modes.text,
readOnly: true,

View File

@ -258,7 +258,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY devToolbar.keytext "F2">
<!ENTITY devToolboxMenuItem.label "Toggle Tools">
<!ENTITY devToolboxMenuItem.accesskey "T">
<!ENTITY devToolboxMenuItem.keycode "I">
<!ENTITY devToolboxMenuItem.keytext "I">
<!ENTITY devToolbarToolsButton.tooltip "Toggle developer tools">
@ -434,6 +433,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY bookmarkThisFrameCmd.accesskey "m">
<!ENTITY emailPageCmd.label "Email Link…">
<!ENTITY emailPageCmd.accesskey "E">
<!ENTITY switchToMetroCmd.label "Relaunch in Windows 8 style &brandShortName;">
<!ENTITY savePageCmd.label "Save Page As…">
<!ENTITY savePageCmd.accesskey "A">
<!-- alternate for content area context menu -->

View File

@ -31,6 +31,10 @@ add-ons-button.label = Add-ons
# LOCALIZATION NOTE(add-ons-button.tooltiptext): %S is the keyboard shortcut
add-ons-button.tooltiptext = Add-ons Manager (%S)
switch-to-metro-button.label = Metro Mode
# LOCALIZATION NOTE(switch-to-metro-button.tooltiptext): %S is the brand short name
switch-to-metro-button.tooltiptext = Relaunch in Windows 8 style %S
preferences-button.label = Preferences
# LOCALIZATION NOTE (preferences-button.tooltiptext): Use the unicode ellipsis char,
# \u2026, or use "..." if \u2026 doesn't suit traditions in your locale.

View File

@ -70,6 +70,7 @@ detailsPane.itemsCountLabel=One item;#1 items
mostVisitedTitle=Most Visited
recentlyBookmarkedTitle=Recently Bookmarked
recentTagsTitle=Recent Tags
firefoxTouchTitle=Firefox Touch
OrganizerQueryHistory=History
OrganizerQueryDownloads=Downloads

View File

@ -33,8 +33,6 @@
<!ENTITY setup.choosePassword.accesskey "P">
<!ENTITY setup.confirmPassword.label "Confirm Password">
<!ENTITY setup.confirmPassword.accesskey "m">
<!ENTITY setup.setupMetro.label "Sync with Windows 8 style &brandShortName;">
<!ENTITY setup.setupMetro.accesskey "S">
<!-- LOCALIZATION NOTE: tosAgree1, tosLink, tosAgree2, ppLink, tosAgree3 are
joined with implicit white space, so spaces in the strings aren't necessary -->

View File

@ -8,7 +8,7 @@ include $(topsrcdir)/config/rules.mk
# application.ini
GRE_BUILDID := $(shell cat $(DEPTH)/config/buildid)
DEFINES += -DGRE_BUILDID=$(GRE_BUILDID)
DEFINES += -DGRE_BUILDID=$(GRE_BUILDID) -DMOZ_APP_BASENAME=$(MOZ_APP_BASENAME)
# 'application.ini' breaks firefox build config. So we use something different.
metroapp.ini: metroapp.ini.in $(DEPTH)/config/buildid $(topsrcdir)/config/milestone.txt

View File

@ -126,16 +126,7 @@ var Appbar = {
if (!Services.metro.immersive)
typesArray.push("open-jsshell");
try {
// If we have a valid http or https URI then show the view on desktop
// menu item.
let uri = Services.io.newURI(Browser.selectedBrowser.currentURI.spec,
null, null);
if (uri.schemeIs('http') || uri.schemeIs('https')) {
typesArray.push("view-on-desktop");
}
} catch(ex) {
}
typesArray.push("view-on-desktop");
var x = this.menuButton.getBoundingClientRect().left;
var y = Elements.toolbar.getBoundingClientRect().top;
@ -153,16 +144,12 @@ var Appbar = {
},
onViewOnDesktop: function() {
try {
// Make sure we have a valid URI so Windows doesn't prompt
// with an unrecognized command, select default program window
var uri = Services.io.newURI(Browser.selectedBrowser.currentURI.spec,
null, null);
if (uri.schemeIs('http') || uri.schemeIs('https')) {
Services.metro.launchInDesktop(Browser.selectedBrowser.currentURI.spec, "");
}
} catch(ex) {
}
let appStartup = Components.classes["@mozilla.org/toolkit/app-startup;1"].
getService(Components.interfaces.nsIAppStartup);
Services.prefs.setBoolPref('browser.sessionstore.resume_session_once', true);
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
Components.interfaces.nsIAppStartup.eRestart);
},
onAutocompleteCloseButton: function () {

View File

@ -5,6 +5,7 @@
"use strict";
Cu.import("resource://gre/modules/devtools/dbg-server.jsm")
Cu.import("resource://gre/modules/WindowsPrefSync.jsm");
/**
* Constants
@ -153,7 +154,10 @@ var BrowserUI = {
Util.dumpLn("Exception in delay load module:", ex.message);
}
BrowserUI._pullDesktopControlledPrefs();
if (WindowsPrefSync) {
// Pulls in Desktop controlled prefs and pushes out Metro controlled prefs
WindowsPrefSync.init();
}
// check for left over crash reports and submit them if found.
BrowserUI.startupCrashCheck();
@ -189,6 +193,9 @@ var BrowserUI = {
MetroDownloadsView.uninit();
SettingsCharm.uninit();
PageThumbs.uninit();
if (WindowsPrefSync) {
WindowsPrefSync.uninit();
}
this.stopDebugServer();
},
@ -638,37 +645,6 @@ var BrowserUI = {
* Internal utils
*/
/**
* Some prefs that have consequences in both Metro and Desktop such as
* app-update prefs, are automatically pulled from Desktop here.
*/
_pullDesktopControlledPrefs: function() {
function pullDesktopControlledPrefType(prefType, prefFunc) {
try {
registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
"Software\\Mozilla\\Firefox\\Metro\\Prefs\\" + prefType,
Ci.nsIWindowsRegKey.ACCESS_ALL);
for (let i = 0; i < registry.valueCount; i++) {
let prefName = registry.getValueName(i);
let prefValue = registry.readStringValue(prefName);
if (prefType == Ci.nsIPrefBranch.PREF_BOOL) {
prefValue = prefValue == "true";
}
Services.prefs[prefFunc](prefName, prefValue);
}
} catch (ex) {
Util.dumpLn("Could not pull for prefType " + prefType + ": " + ex);
} finally {
registry.close();
}
}
let registry = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
pullDesktopControlledPrefType(Ci.nsIPrefBranch.PREF_INT, "setIntPref");
pullDesktopControlledPrefType(Ci.nsIPrefBranch.PREF_BOOL, "setBoolPref");
pullDesktopControlledPrefType(Ci.nsIPrefBranch.PREF_STRING, "setCharPref");
},
_titleChanged: function(aBrowser) {
let url = this.getDisplayURI(aBrowser);
@ -1327,11 +1303,15 @@ var SettingsCharm = {
label: Strings.browser.GetStringFromName("optionsCharm"),
onselected: function() FlyoutPanelsUI.show('PrefsFlyoutPanel')
});
/*
* Temporarily disabled until we can have sync prefs together with the
* Desktop browser's sync prefs.
// Sync
this.addEntry({
label: Strings.brand.GetStringFromName("syncBrandShortName"),
onselected: function() FlyoutPanelsUI.show('SyncFlyoutPanel')
});
*/
// About
this.addEntry({
label: Strings.browser.GetStringFromName("aboutCharm1"),

View File

@ -142,10 +142,14 @@
<!-- development/testing -->
<key id="key_console" key="&jsConsole.key;" modifiers="accel,shift" oncommand="PanelUI.show('console-container')"/>
<key id="key_options" key="&optionsFlyout.key;" modifiers="accel,shift" oncommand="FlyoutPanelsUI.show('PrefsFlyoutPanel')" />
<key id="key_options" key="&aboutFlyout.key;" modifiers="accel,shift" oncommand="FlyoutPanelsUI.show('AboutFlyoutPanel')" />
<!--
Temporarily disabled until we can have sync prefs together with the
Desktop browser's sync prefs.
#ifdef MOZ_SERVICES_SYNC
<key id="key_options" key="&syncFlyout.key;" modifiers="accel,shift" oncommand="FlyoutPanelsUI.show('SyncFlyoutPanel')" />
#endif
<key id="key_options" key="&aboutFlyout.key;" modifiers="accel,shift" oncommand="FlyoutPanelsUI.show('AboutFlyoutPanel')" />
-->
<!-- manage tabs -->
<key id="key_newTab" key="&newTab.key;" modifiers="accel" command="cmd_newTab"/>
@ -784,7 +788,7 @@
<label value="&appbarFindInPage2.label;"/>
</richlistitem>
<richlistitem id="context-viewondesktop" type="view-on-desktop" onclick="ContextCommands.viewOnDesktop();">
<label value="&appbarViewOnDesktop2.label;"/>
<label value="&appbarRelaunchInDesktop.label;"/>
</richlistitem>
<richlistitem id="context-msmetadata" type="ms-meta-data" onclick="ContextCommands.openWindowsStoreLink();">
<label value="&appbarMSMetaData2.label;"/>

View File

@ -279,7 +279,7 @@ appUpdater.prototype =
}
appStartup.quit(Components.interfaces.nsIAppStartup.eAttemptQuit |
Components.interfaces.nsIAppStartup.eRestart);
Components.interfaces.nsIAppStartup.eRestartTouchEnvironment);
return;
}

View File

@ -13,12 +13,12 @@
<!ENTITY autocompleteResultsHeader.label "Your Results">
<!ENTITY appbarErrorConsole.label "Open error console">
<!ENTITY appbarJSShell.label "Open JavaScript shell">
<!ENTITY appbarFindInPage2.label "Find in page">
<!ENTITY appbarViewOnDesktop2.label "View on desktop">
<!ENTITY appbarMSMetaData2.label "Get app for this site">
<!ENTITY appbarViewPageSource.label "View page source">
<!ENTITY appbarErrorConsole.label "Open error console">
<!ENTITY appbarJSShell.label "Open JavaScript shell">
<!ENTITY appbarFindInPage2.label "Find in page">
<!ENTITY appbarRelaunchInDesktop.label "Relaunch in Desktop">
<!ENTITY appbarMSMetaData2.label "Get app for this site">
<!ENTITY appbarViewPageSource.label "View page source">
<!ENTITY topSitesHeader.label "Top Sites">
<!ENTITY bookmarksHeader.label "Bookmarks">

View File

@ -1,7 +1,7 @@
#filter substitution
[App]
Vendor=Mozilla
Name=MetroFirefox
Name=@MOZ_APP_BASENAME@
UAName=Firefox
Version=@GRE_MILESTONE@
BuildID=@GRE_BUILDID@

View File

@ -81,7 +81,7 @@ IsImmersiveProcessDynamic(HANDLE process)
}
bool
IsImmersiveProcessRunning(const wchar_t *processName)
IsProcessRunning(const wchar_t *processName, bool bCheckIfMetro)
{
bool exists = false;
PROCESSENTRY32W entry;
@ -93,7 +93,9 @@ IsImmersiveProcessRunning(const wchar_t *processName)
while (!exists && Process32Next(snapshot, &entry)) {
if (!_wcsicmp(entry.szExeFile, processName)) {
HANDLE process = OpenProcess(GENERIC_READ, FALSE, entry.th32ProcessID);
if (IsImmersiveProcessDynamic(process)) {
bool isImmersiveProcess = IsImmersiveProcessDynamic(process);
if ((bCheckIfMetro && isImmersiveProcess) ||
(!bCheckIfMetro && !isImmersiveProcess)) {
exists = true;
}
CloseHandle(process);

View File

@ -28,4 +28,4 @@ bool IsDX10Available();
bool GetDWORDRegKey(LPCWSTR name, DWORD &value);
bool SetDWORDRegKey(LPCWSTR name, DWORD value);
bool IsImmersiveProcessDynamic(HANDLE process);
bool IsImmersiveProcessRunning(const wchar_t *processName);
bool IsProcessRunning(const wchar_t *processName, bool bCheckIfMetro);

View File

@ -44,6 +44,7 @@ static const WCHAR* kFirefoxExe = L"firefox.exe";
static const WCHAR* kMetroFirefoxExe = L"firefox.exe";
static const WCHAR* kDefaultMetroBrowserIDPathKey = L"FirefoxURL";
static const WCHAR* kMetroRestartCmdLine = L"--metro-restart";
static const WCHAR* kDesktopRestartCmdLine = L"--desktop-restart";
static bool GetDefaultBrowserPath(CStringW& aPathBuffer);
@ -104,7 +105,9 @@ public:
mTargetIsBrowser(false),
mIsDesktopRequest(true),
mIsRestartMetroRequest(false),
mRequestMet(false)
mIsRestartDesktopRequest(false),
mRequestMet(false),
mVerb(L"open")
{
}
@ -152,6 +155,8 @@ public:
if (_wcsicmp(aParameters, kMetroRestartCmdLine) == 0) {
mIsRestartMetroRequest = true;
} else if (_wcsicmp(aParameters, kDesktopRestartCmdLine) == 0) {
mIsRestartDesktopRequest = true;
} else {
mParameters = aParameters;
}
@ -260,11 +265,24 @@ public:
*aLaunchType = AHE_DESKTOP;
mIsDesktopRequest = true;
if (!mIsRestartMetroRequest && IsProcessRunning(kFirefoxExe, false)) {
return S_OK;
} else if (!mIsRestartDesktopRequest && IsProcessRunning(kMetroFirefoxExe, true)) {
*aLaunchType = AHE_IMMERSIVE;
mIsDesktopRequest = false;
return S_OK;
}
if (!mUnkSite) {
Log(L"No mUnkSite.");
return S_OK;
}
if (mIsRestartDesktopRequest) {
Log(L"Restarting in desktop host environment.");
return S_OK;
}
HRESULT hr;
IServiceProvider* pSvcProvider = nullptr;
hr = mUnkSite->QueryInterface(IID_IServiceProvider, (void**)&pSvcProvider);
@ -416,6 +434,7 @@ private:
DWORD mKeyState;
bool mIsDesktopRequest;
bool mIsRestartMetroRequest;
bool mIsRestartDesktopRequest;
bool mRequestMet;
};
@ -574,6 +593,48 @@ bool CExecuteCommandVerb::SetTargetPath(IShellItem* aItem)
* Desktop launch - Launch the destop browser to display the current
* target using shellexecute.
*/
void LaunchDesktopBrowserWithParams(CStringW& aBrowserPath, CStringW& aVerb, CStringW& aTarget, CStringW& aParameters,
bool aTargetIsDefaultBrowser, bool aTargetIsBrowser)
{
// If a taskbar shortcut, link or local file is clicked, the target will
// be the browser exe or file. Don't pass in -url for the target if the
// target is known to be a browser. Otherwise, one instance of Firefox
// will try to open another instance.
CStringW params;
if (!aTargetIsDefaultBrowser && !aTargetIsBrowser && !aTarget.IsEmpty()) {
// Fallback to the module path if it failed to get the default browser.
GetDefaultBrowserPath(aBrowserPath);
params += "-url ";
params += "\"";
params += aTarget;
params += "\"";
}
// Tack on any extra parameters we received (for example -profilemanager)
if (!aParameters.IsEmpty()) {
params += " ";
params += aParameters;
}
Log(L"Desktop Launch: verb:%s exe:%s params:%s", aVerb, aBrowserPath, params);
SHELLEXECUTEINFOW seinfo;
memset(&seinfo, 0, sizeof(seinfo));
seinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
seinfo.fMask = SEE_MASK_FLAG_LOG_USAGE;
seinfo.lpVerb = aVerb;
seinfo.lpFile = aBrowserPath;
seinfo.nShow = SW_SHOWNORMAL;
// Relaunch in Desktop mode uses a special URL to trick Windows into
// switching environments. We shouldn't actually try to open this URL
if (_wcsicmp(aTarget, L"http://-desktop/") != 0) {
seinfo.lpParameters = params;
}
ShellExecuteEx(&seinfo);
}
void CExecuteCommandVerb::LaunchDesktopBrowser()
{
CStringW browserPath;
@ -581,40 +642,7 @@ void CExecuteCommandVerb::LaunchDesktopBrowser()
return;
}
// If a taskbar shortcut, link or local file is clicked, the target will
// be the browser exe or file. Don't pass in -url for the target if the
// target is known to be a browser. Otherwise, one instance of Firefox
// will try to open another instance.
CStringW params;
if (!mTargetIsDefaultBrowser && !mTargetIsBrowser && !mTarget.IsEmpty()) {
// Fallback to the module path if it failed to get the default browser.
GetDefaultBrowserPath(browserPath);
params += "-url ";
params += "\"";
params += mTarget;
params += "\"";
}
// Tack on any extra parameters we received (for example -profilemanager)
if (!mParameters.IsEmpty()) {
params += " ";
params += mParameters;
}
Log(L"Desktop Launch: verb:%s exe:%s params:%s", mVerb, browserPath, params);
SHELLEXECUTEINFOW seinfo;
memset(&seinfo, 0, sizeof(seinfo));
seinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
seinfo.fMask = 0;
seinfo.hwnd = nullptr;
seinfo.lpVerb = nullptr;
seinfo.lpFile = browserPath;
seinfo.lpParameters = params;
seinfo.lpDirectory = nullptr;
seinfo.nShow = SW_SHOWNORMAL;
ShellExecuteExW(&seinfo);
LaunchDesktopBrowserWithParams(browserPath, mVerb, mTarget, mParameters, mTargetIsDefaultBrowser, mTargetIsBrowser);
}
class AutoSetRequestMet
@ -664,7 +692,7 @@ DelayedExecuteThread(LPVOID param)
size_t currentWaitTime = 0;
while(currentWaitTime < RESTART_WAIT_TIMEOUT) {
if (!IsImmersiveProcessRunning(kMetroFirefoxExe))
if (!IsProcessRunning(kMetroFirefoxExe, true))
break;
currentWaitTime += RESTART_WAIT_PER_RETRY;
Sleep(RESTART_WAIT_PER_RETRY);
@ -705,6 +733,21 @@ IFACEMETHODIMP CExecuteCommandVerb::Execute()
return S_OK;
}
if (mIsRestartDesktopRequest) {
CStringW browserPath;
if (!GetDesktopBrowserPath(browserPath)) {
return E_FAIL;
}
LaunchDesktopBrowserWithParams(browserPath,
mVerb,
mTarget,
mParameters,
mTargetIsDefaultBrowser,
mTargetIsBrowser);
return S_OK;
}
// We shut down when this flips to true
AutoSetRequestMet asrm(&mRequestMet);
@ -728,8 +771,7 @@ IFACEMETHODIMP CExecuteCommandVerb::Execute()
return S_OK;
}
Log(L"Metro Launch: verb:%s appid:%s params:%s", mVerb, appModelID, mTarget);
Log(L"Metro Launch: verb:%s appid:%s params:%s", mVerb, appModelID, mTarget);
// shortcuts to the application
DWORD processID;

View File

@ -82,7 +82,7 @@ const kPinned = [
];
this.CharsetMenu = Object.freeze({
build: function BuildCharsetMenu(event, showAccessKeys) {
build: function BuildCharsetMenu(event, idPrefix="", showAccessKeys=false) {
let parent = event.target;
if (parent.lastChild.localName != "menuseparator") {
// Detector menu or charset menu already built
@ -108,7 +108,7 @@ this.CharsetMenu = Object.freeze({
// Some items intentionally don't have an accesskey
}
}
menuItem.setAttribute("id", "charset." + encoding);
menuItem.setAttribute("id", idPrefix + "charset." + encoding);
return menuItem;
}

View File

@ -1,4 +1,4 @@
%filter substitution
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-reset-button, #zoom-in-button, #sync-button, #feed-button, #tabview-button, #webrtc-status-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #cut-button, #copy-button, #paste-button, #fullscreen-button, #zoom-out-button, #zoom-reset-button, #zoom-in-button, #sync-button, #feed-button, #tabview-button, #webrtc-status-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #switch-to-metro-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button
%define inAnyPanel :-moz-any(:not([cui-areatype="toolbar"]),.overflowedItem)

View File

@ -30,6 +30,11 @@ toolbarpaletteitem[place="palette"] > #downloads-button {
-moz-image-region: rect(0px, 256px, 32px, 224px);
}
#switch-to-metro-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #switch-to-metro-button {
-moz-image-region: rect(0px, 800px, 32px, 768px);
}
#add-ons-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #add-ons-button {
-moz-image-region: rect(0px, 288px, 32px, 256px);

View File

@ -49,6 +49,10 @@
-moz-image-region: rect(0, 216px, 18px, 198px);
}
#switch-to-metro-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 648px, 18px, 630px);
}
#open-file-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 234px, 18px, 216px);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -50,7 +50,6 @@ public class FennecNativeDriver implements Driver {
private ClassLoader mClassLoader;
private Class mApiClass;
private Class mEventListenerClass;
private Class mPanningPerfClass;
private Method mRegisterEventListener;
private Method mGetPixels;
private Method mStartFrameRecording;
@ -91,14 +90,13 @@ public class FennecNativeDriver implements Driver {
mApiClass = mClassLoader.loadClass("org.mozilla.gecko.RobocopAPI");
mEventListenerClass = mClassLoader.loadClass("org.mozilla.gecko.util.GeckoEventListener");
mPanningPerfClass = mClassLoader.loadClass("org.mozilla.gecko.gfx.PanningPerfAPI");
mRegisterEventListener = mApiClass.getMethod("registerEventListener", String.class, mEventListenerClass);
mGetPixels = mApiClass.getMethod("getViewPixels", View.class);
mStartFrameRecording = mPanningPerfClass.getDeclaredMethod("startFrameTimeRecording");
mStopFrameRecording = mPanningPerfClass.getDeclaredMethod("stopFrameTimeRecording");
mStartCheckerboardRecording = mPanningPerfClass.getDeclaredMethod("startCheckerboardRecording");
mStopCheckerboardRecording = mPanningPerfClass.getDeclaredMethod("stopCheckerboardRecording");
mStartFrameRecording = mApiClass.getDeclaredMethod("startFrameTimeRecording");
mStopFrameRecording = mApiClass.getDeclaredMethod("stopFrameTimeRecording");
mStartCheckerboardRecording = mApiClass.getDeclaredMethod("startCheckerboardRecording");
mStopCheckerboardRecording = mApiClass.getDeclaredMethod("stopCheckerboardRecording");
mRobocopApi = mApiClass.getConstructor(Activity.class).newInstance(activity);
} catch (Exception e) {

View File

@ -21,6 +21,9 @@ import android.util.Log;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
@WebRTCJNITarget
class AudioManagerAndroid {
// Most of Google lead devices use 44.1K as the default sampling rate, 44.1K
// is also widely used on other android devices.

View File

@ -20,10 +20,13 @@ import android.media.AudioRecord;
import android.media.AudioTrack;
import android.util.Log;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
class WebRTCAudioDevice {
private AudioTrack _audioTrack = null;
private AudioRecord _audioRecord = null;
@WebRTCJNITarget
private Context _context;
private AudioManager _audioManager;
@ -44,6 +47,7 @@ class WebRTCAudioDevice {
private int _bufferedPlaySamples = 0;
private int _playPosition = 0;
@WebRTCJNITarget
WebRTCAudioDevice() {
try {
_playBuffer = ByteBuffer.allocateDirect(2 * 480); // Max 10 ms @ 48
@ -59,6 +63,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int InitRecording(int audioSource, int sampleRate) {
// get the minimum buffer size that can be used
int minRecBufSize = AudioRecord.getMinBufferSize(
@ -104,6 +109,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int StartRecording() {
if (_isPlaying == false) {
SetAudioMode(true);
@ -123,6 +129,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int InitPlayback(int sampleRate) {
// get the minimum buffer size that can be used
int minPlayBufSize = AudioTrack.getMinBufferSize(
@ -180,6 +187,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int StartPlayback() {
if (_isRecording == false) {
SetAudioMode(true);
@ -199,6 +207,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int StopRecording() {
_recLock.lock();
try {
@ -234,6 +243,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int StopPlayback() {
_playLock.lock();
try {
@ -271,6 +281,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int PlayAudio(int lengthInBytes) {
int bufferedSamples = 0;
@ -331,6 +342,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int RecordAudio(int lengthInBytes) {
_recLock.lock();
@ -376,6 +388,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int SetPlayoutSpeaker(boolean loudspeakerOn) {
// create audio manager if needed
if (_audioManager == null && _context != null) {
@ -425,6 +438,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int SetPlayoutVolume(int level) {
// create audio manager if needed
@ -445,6 +459,7 @@ class WebRTCAudioDevice {
}
@SuppressWarnings("unused")
@WebRTCJNITarget
private int GetPlayoutVolume() {
// create audio manager if needed

View File

@ -10,6 +10,9 @@
package org.webrtc.videoengine;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
@WebRTCJNITarget
public class CaptureCapabilityAndroid {
public int width = 0;
public int height = 0;

View File

@ -37,6 +37,7 @@ import org.mozilla.gecko.GeckoApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoAppShell.AppStateListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
public class VideoCaptureAndroid implements PreviewCallback, Callback {
@ -107,6 +108,8 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
// Invoked every time there's a new Camera preview frame
}
}
@WebRTCJNITarget
public static
void DeleteVideoCaptureAndroid(VideoCaptureAndroid captureAndroid) {
Log.d(TAG, "DeleteVideoCaptureAndroid");
@ -313,6 +316,7 @@ public class VideoCaptureAndroid implements PreviewCallback, Callback {
return 0;
}
@WebRTCJNITarget
public int StartCapture(int width, int height, int frameRate) {
Log.d(TAG, "StartCapture width " + width +
" height " + height +" frame rate " + frameRate);

View File

@ -24,6 +24,8 @@ import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.util.Log;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
public class VideoCaptureDeviceInfoAndroid {
//Context
@ -34,6 +36,7 @@ public class VideoCaptureDeviceInfoAndroid {
private final static String TAG = "WEBRTC";
// Private class with info about all available cameras and the capabilities
@WebRTCJNITarget
public class AndroidVideoCaptureDevice {
AndroidVideoCaptureDevice() {
frontCameraType = FrontFacingCameraType.None;
@ -62,6 +65,7 @@ public class VideoCaptureDeviceInfoAndroid {
int id;
List<AndroidVideoCaptureDevice> deviceList;
@WebRTCJNITarget
public static VideoCaptureDeviceInfoAndroid
CreateVideoCaptureDeviceInfoAndroid(int in_id, Context in_context) {
Log.d(TAG,
@ -213,10 +217,12 @@ public class VideoCaptureDeviceInfoAndroid {
}
// Returns the number of Capture devices that is supported
@WebRTCJNITarget
public int NumberOfDevices() {
return deviceList.size();
}
@WebRTCJNITarget
public String GetDeviceUniqueName(int deviceNumber) {
if(deviceNumber < 0 || deviceNumber >= deviceList.size()) {
return null;
@ -224,6 +230,7 @@ public class VideoCaptureDeviceInfoAndroid {
return deviceList.get(deviceNumber).deviceUniqueName;
}
@WebRTCJNITarget
public CaptureCapabilityAndroid[] GetCapabilityArray (String deviceUniqueId)
{
for (AndroidVideoCaptureDevice device: deviceList) {
@ -236,6 +243,7 @@ public class VideoCaptureDeviceInfoAndroid {
// Returns the camera orientation as described by
// android.hardware.Camera.CameraInfo.orientation
@WebRTCJNITarget
public int GetOrientation(String deviceUniqueId) {
for (AndroidVideoCaptureDevice device: deviceList) {
if(device.deviceUniqueName.equals(deviceUniqueId)) {
@ -246,6 +254,7 @@ public class VideoCaptureDeviceInfoAndroid {
}
// Returns an instance of VideoCaptureAndroid.
@WebRTCJNITarget
public VideoCaptureAndroid AllocateCamera(int id, long context,
String deviceUniqueId) {
try {
@ -296,6 +305,7 @@ public class VideoCaptureDeviceInfoAndroid {
}
// Searches for a front facing camera device. This is device specific code.
@WebRTCJNITarget
private Camera.Parameters
SearchOldFrontFacingCameras(AndroidVideoCaptureDevice newDevice)
throws SecurityException, IllegalArgumentException,

View File

@ -25,6 +25,8 @@ import android.graphics.PixelFormat;
import android.opengl.GLSurfaceView;
import android.util.Log;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
public class ViEAndroidGLES20 extends GLSurfaceView
implements GLSurfaceView.Renderer {
private static String TAG = "WEBRTC-JR";
@ -40,6 +42,7 @@ public class ViEAndroidGLES20 extends GLSurfaceView
private int viewWidth = 0;
private int viewHeight = 0;
@WebRTCJNITarget
public static boolean UseOpenGL2(Object renderWindow) {
return ViEAndroidGLES20.class.isInstance(renderWindow);
}
@ -49,6 +52,7 @@ public class ViEAndroidGLES20 extends GLSurfaceView
init(false, 0, 0);
}
@WebRTCJNITarget
public ViEAndroidGLES20(Context context, boolean translucent,
int depth, int stencil) {
super(context);
@ -341,6 +345,7 @@ public class ViEAndroidGLES20 extends GLSurfaceView
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}
@WebRTCJNITarget
public void RegisterNativeObject(long nativeObject) {
nativeFunctionLock.lock();
this.nativeObject = nativeObject;
@ -348,6 +353,7 @@ public class ViEAndroidGLES20 extends GLSurfaceView
nativeFunctionLock.unlock();
}
@WebRTCJNITarget
public void DeRegisterNativeObject() {
nativeFunctionLock.lock();
nativeFunctionsRegisted = false;
@ -356,6 +362,7 @@ public class ViEAndroidGLES20 extends GLSurfaceView
nativeFunctionLock.unlock();
}
@WebRTCJNITarget
public void ReDraw() {
if(surfaceCreated) {
// Request the renderer to redraw using the render thread context.

View File

@ -26,6 +26,8 @@ import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
public class ViESurfaceRenderer implements Callback {
private final static String TAG = "WEBRTC";
@ -43,6 +45,7 @@ public class ViESurfaceRenderer implements Callback {
private float dstLeftScale = 0;
private float dstRightScale = 1;
@WebRTCJNITarget
public ViESurfaceRenderer(SurfaceView view) {
surfaceHolder = view.getHolder();
if(surfaceHolder == null)
@ -122,6 +125,7 @@ public class ViESurfaceRenderer implements Callback {
return bitmap;
}
@WebRTCJNITarget
public ByteBuffer CreateByteBuffer(int width, int height) {
Log.d(TAG, "CreateByteBuffer " + width + ":" + height);
if (bitmap == null) {
@ -131,6 +135,7 @@ public class ViESurfaceRenderer implements Callback {
return byteBuffer;
}
@WebRTCJNITarget
public void SetCoordinates(float left, float top,
float right, float bottom) {
Log.d(TAG, "SetCoordinates " + left + "," + top + ":" +
@ -142,6 +147,7 @@ public class ViESurfaceRenderer implements Callback {
}
// It saves bitmap data to a JPEG picture, this function is for debug only.
@WebRTCJNITarget
private void saveBitmapToJPEG(int width, int height) {
ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, byteOutStream);
@ -159,6 +165,7 @@ public class ViESurfaceRenderer implements Callback {
}
}
@WebRTCJNITarget
public void DrawByteBuffer() {
if(byteBuffer == null)
return;

View File

@ -23,6 +23,8 @@ import android.view.SurfaceView;
import java.nio.ByteBuffer;
import java.util.LinkedList;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
class CodecState {
private static final String TAG = "CodecState";
@ -41,6 +43,7 @@ class CodecState {
private long mLastMediaTimeUs;
@WebRTCJNITarget
public CodecState(
ViEMediaCodecDecoder view,
MediaFormat format,
@ -245,6 +248,7 @@ class ViEMediaCodecDecoder {
private Thread mLooperThread;
@WebRTCJNITarget
public void configure(SurfaceView surfaceView, int width, int height) {
mSurfaceView = surfaceView;
Log.d(TAG, "configure " + "width" + width + "height" + height + mSurfaceView.toString());
@ -267,6 +271,7 @@ class ViEMediaCodecDecoder {
initMediaCodecView();
}
@WebRTCJNITarget
public void setEncodedImage(ByteBuffer buffer, long renderTimeMs) {
// TODO(dwkang): figure out why exceptions just make this thread finish.
try {
@ -354,6 +359,7 @@ class ViEMediaCodecDecoder {
Log.d(TAG, "initMediaCodecView end");
}
@WebRTCJNITarget
public void start() {
Log.d(TAG, "start");

View File

@ -59,6 +59,7 @@ import android.widget.TabHost.TabSpec;
import android.widget.TextView;
import org.webrtc.videoengine.ViERenderer;
import org.mozilla.gecko.mozglue.WebRTCJNITarget;
import java.io.File;
import java.io.IOException;
@ -1046,6 +1047,7 @@ public class WebRTCDemo extends TabActivity implements IViEAndroidCallback,
Log.d(TAG, "No setting selected");
}
@WebRTCJNITarget
public int updateStats(int inFrameRateI, int inBitRateI,
int inPacketLoss, int inFrameRateO, int inBitRateO) {
frameRateI = inFrameRateI;

View File

@ -6,6 +6,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.mozglue.RobocopTarget;
/**
* A collection of constants that pertain to the build and runtime state of the
* application. Typically these are sourced from build-time definitions (see
@ -15,6 +16,7 @@ package org.mozilla.gecko;
* See also SysInfo.java, which includes some of the values available from
* nsSystemInfo inside Gecko.
*/
@RobocopTarget
public class AppConstants {
public static final String ANDROID_PACKAGE_NAME = "@ANDROID_PACKAGE_NAME@";
public static final String BROWSER_INTENT_CLASS = ANDROID_PACKAGE_NAME + ".App";

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONArray;
@ -87,6 +88,7 @@ public final class Distribution {
*
* @param packagePath where to look for the distribution directory.
*/
@RobocopTarget
public static void init(final Context context, final String packagePath, final String prefsPath) {
// Read/write preferences and files on the background thread.
ThreadUtils.postToBackgroundThread(new Runnable() {

View File

@ -10,6 +10,7 @@ import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanZoomController;
import org.mozilla.gecko.mozglue.JNITarget;
import org.mozilla.gecko.mozglue.generatorannotations.OptionalGeneratedParameter;
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
import org.mozilla.gecko.prompts.PromptService;
@ -391,7 +392,6 @@ public class GeckoAppShell
} catch (NoSuchElementException e) {}
}
/* This method is referenced by Robocop via reflection. */
public static void sendEventToGecko(GeckoEvent e) {
if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
notifyGeckoOfEvent(e);
@ -859,6 +859,7 @@ public class GeckoAppShell
});
}
@JNITarget
static public int getPreferredIconSize() {
if (android.os.Build.VERSION.SDK_INT >= 11) {
ActivityManager am = (ActivityManager)getContext().getSystemService(Context.ACTIVITY_SERVICE);
@ -2320,8 +2321,6 @@ public class GeckoAppShell
* with an event that is currently being processed has the properly-defined behaviour that
* any added listeners will not be invoked on the event currently being processed, but
* will be invoked on future events of that type.
*
* This method is referenced by Robocop via reflection.
*/
public static void registerEventListener(String event, GeckoEventListener listener) {
sEventDispatcher.registerEventListener(event, listener);
@ -2337,8 +2336,6 @@ public class GeckoAppShell
* with an event that is currently being processed has the properly-defined behaviour that
* any removed listeners will still be invoked on the event currently being processed, but
* will not be invoked on future events of that type.
*
* This method is referenced by Robocop via reflection.
*/
public static void unregisterEventListener(String event, GeckoEventListener listener) {
sEventDispatcher.unregisterEventListener(event, listener);

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.gfx.DisplayPortMetrics;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.mozglue.JNITarget;
import org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions;
import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
@ -36,11 +37,13 @@ import java.nio.ByteBuffer;
/* This class is referenced by Robocop via reflection; use care when
* modifying the signature.
*/
@JNITarget
public class GeckoEvent {
private static final String LOGTAG = "GeckoEvent";
// Make sure to keep these values in sync with the enum in
// AndroidGeckoEvent in widget/android/AndroidJavaWrapper.h
@JNITarget
private enum NativeGeckoEvent {
NATIVE_POKE(0),
KEY_EVENT(1),
@ -103,6 +106,7 @@ public class GeckoEvent {
}
// Encapsulation of common IME actions.
@JNITarget
public enum ImeAction {
IME_SYNCHRONIZE(0),
IME_REPLACE_TEXT(1),

View File

@ -6,12 +6,12 @@
package org.mozilla.gecko;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONObject;
import android.content.Intent;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@ -28,6 +28,7 @@ import java.util.Locale;
public class GeckoThread extends Thread implements GeckoEventListener {
private static final String LOGTAG = "GeckoThread";
@RobocopTarget
public enum LaunchState {
Launching,
WaitForDebugger,
@ -187,6 +188,7 @@ public class GeckoThread extends Thread implements GeckoEventListener {
}
}
@RobocopTarget
public static boolean checkLaunchState(LaunchState checkState) {
synchronized (sLock) {
return sLaunchState == checkState;

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko;
import org.mozilla.gecko.mozglue.GeckoLoader;
import android.content.Context;
import org.mozilla.gecko.mozglue.RobocopTarget;
public class NSSBridge {
private static final String LOGTAG = "NSSBridge";
@ -14,6 +15,7 @@ public class NSSBridge {
private static native String nativeEncrypt(String aDb, String aValue);
private static native String nativeDecrypt(String aDb, String aValue);
@RobocopTarget
static public String encrypt(Context context, String aValue)
throws Exception {
String resourcePath = context.getPackageResourcePath();
@ -23,6 +25,7 @@ public class NSSBridge {
return nativeEncrypt(path, aValue);
}
@RobocopTarget
static public String encrypt(Context context, String profilePath, String aValue)
throws Exception {
String resourcePath = context.getPackageResourcePath();
@ -31,6 +34,7 @@ public class NSSBridge {
return nativeEncrypt(profilePath, aValue);
}
@RobocopTarget
static public String decrypt(Context context, String aValue)
throws Exception {
String resourcePath = context.getPackageResourcePath();
@ -40,6 +44,7 @@ public class NSSBridge {
return nativeDecrypt(path, aValue);
}
@RobocopTarget
static public String decrypt(Context context, String profilePath, String aValue)
throws Exception {
String resourcePath = context.getPackageResourcePath();

View File

@ -6,7 +6,9 @@ package org.mozilla.gecko;
import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanningPerfAPI;
import org.mozilla.gecko.mozglue.GeckoLoader;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.sqlite.SQLiteBridge;
import org.mozilla.gecko.util.GeckoEventListener;
@ -15,7 +17,27 @@ import android.database.Cursor;
import android.view.View;
import java.nio.IntBuffer;
import java.util.List;
/**
* Class to provide wrapper methods around methods wanted by Robocop.
*
* This class provides fixed entry points into code that is liable to be optimised by Proguard without
* needing to prevent Proguard from optimising the wrapped methods.
* Wrapping in this way still slightly hinders Proguard's ability to optimise.
*
* If you find yourself wanting to add a method to this class - proceed with caution. If you're writing
* a test that's not about manipulating the UI, you might be better off using JUnit (Or similar)
* instead of Robocop.
*
* Alternatively, you might be able to get what you want by reflecting on a method annotated for the
* benefit of the C++ wrapper generator - these methods are sure to not disappear at compile-time.
*
* Finally, you might be able to get what you want via Reflection on Android's libraries. Those are
* also not prone to vanishing at compile-time, but doing this might substantially complicate your
* work, ultimately not proving worth the extra effort to avoid making a slight mess here.
*/
@RobocopTarget
public class RobocopAPI {
private final GeckoApp mGeckoApp;
@ -59,4 +81,21 @@ public class RobocopAPI {
public IntBuffer getViewPixels(View view) {
return ((LayerView)view).getPixels();
}
// PanningPerfAPI.
public static void startFrameTimeRecording() {
PanningPerfAPI.startFrameTimeRecording();
}
public static List<Long> stopFrameTimeRecording() {
return PanningPerfAPI.stopFrameTimeRecording();
}
public static void startCheckerboardRecording() {
PanningPerfAPI.startCheckerboardRecording();
}
public static List<Float> stopCheckerboardRecording() {
return PanningPerfAPI.stopCheckerboardRecording();
}
}

View File

@ -8,6 +8,8 @@ package org.mozilla.gecko;
import org.mozilla.gecko.db.BrowserDB;
import org.mozilla.gecko.favicons.Favicons;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.mozglue.JNITarget;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.sync.setup.SyncAccounts;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils;
@ -374,6 +376,7 @@ public class Tabs implements GeckoEventListener {
private static final Tabs INSTANCE = new Tabs();
}
@RobocopTarget
public static Tabs getInstance() {
return Tabs.TabsInstanceHolder.INSTANCE;
}
@ -666,6 +669,7 @@ public class Tabs implements GeckoEventListener {
*
* @param url URL of page to load, or search term used if searchEngine is given
*/
@RobocopTarget
public Tab loadUrl(String url) {
return loadUrl(url, LOADURL_NONE);
}
@ -797,9 +801,8 @@ public class Tabs implements GeckoEventListener {
/**
* Gets the next tab ID.
*
* This method is invoked via JNI.
*/
@JNITarget
public static int getNextTabId() {
return sTabId.getAndIncrement();
}

View File

@ -8,7 +8,9 @@ package org.mozilla.gecko.db;
import org.mozilla.gecko.AppConstants;
import android.net.Uri;
import org.mozilla.gecko.mozglue.RobocopTarget;
@RobocopTarget
public class BrowserContract {
public static final String AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.browser";
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
@ -50,31 +52,37 @@ public class BrowserContract {
return order.toString();
}
@RobocopTarget
public interface CommonColumns {
public static final String _ID = "_id";
}
@RobocopTarget
public interface DateSyncColumns {
public static final String DATE_CREATED = "created";
public static final String DATE_MODIFIED = "modified";
}
@RobocopTarget
public interface SyncColumns extends DateSyncColumns {
public static final String GUID = "guid";
public static final String IS_DELETED = "deleted";
}
@RobocopTarget
public interface URLColumns {
public static final String URL = "url";
public static final String TITLE = "title";
}
@RobocopTarget
public interface FaviconColumns {
public static final String FAVICON = "favicon";
public static final String FAVICON_ID = "favicon_id";
public static final String FAVICON_URL = "favicon_url";
}
@RobocopTarget
public interface HistoryColumns {
public static final String DATE_LAST_VISITED = "date";
public static final String VISITS = "visits";
@ -86,6 +94,7 @@ public class BrowserContract {
public static final String TIME_DELETED = "timeDeleted";
}
@RobocopTarget
public static final class Favicons implements CommonColumns, DateSyncColumns {
private Favicons() {}
@ -96,6 +105,7 @@ public class BrowserContract {
public static final String PAGE_URL = "page_url";
}
@RobocopTarget
public static final class Thumbnails implements CommonColumns {
private Thumbnails() {}
@ -105,6 +115,7 @@ public class BrowserContract {
public static final String DATA = "data";
}
@RobocopTarget
public static final class Bookmarks implements CommonColumns, URLColumns, FaviconColumns, SyncColumns {
private Bookmarks() {}
@ -145,6 +156,7 @@ public class BrowserContract {
public static final String KEYWORD = "keyword";
}
@RobocopTarget
public static final class History implements CommonColumns, URLColumns, HistoryColumns, FaviconColumns, SyncColumns {
private History() {}
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "history");
@ -154,6 +166,7 @@ public class BrowserContract {
}
// Combined bookmarks and history
@RobocopTarget
public static final class Combined implements CommonColumns, URLColumns, HistoryColumns, FaviconColumns {
private Combined() {}
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "combined");

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko.db;
import org.mozilla.gecko.db.BrowserContract.Bookmarks;
import org.mozilla.gecko.db.BrowserContract.ExpirePriority;
import org.mozilla.gecko.mozglue.RobocopTarget;
import android.content.ContentResolver;
import android.database.ContentObserver;
@ -36,6 +37,7 @@ public class BrowserDB {
public interface BrowserDBIface {
public void invalidateCachedState();
@RobocopTarget
public Cursor filter(ContentResolver cr, CharSequence constraint, int limit);
// This should onlyl return frecent sites, BrowserDB.getTopSites will do the
@ -49,6 +51,7 @@ public class BrowserDB {
public void updateHistoryEntry(ContentResolver cr, String uri, String title,
long date, int visits);
@RobocopTarget
public Cursor getAllVisitedHistory(ContentResolver cr);
public Cursor getRecentHistory(ContentResolver cr, int limit);
@ -57,28 +60,34 @@ public class BrowserDB {
public void removeHistoryEntry(ContentResolver cr, int id);
@RobocopTarget
public void removeHistoryEntry(ContentResolver cr, String url);
public void clearHistory(ContentResolver cr);
@RobocopTarget
public Cursor getBookmarksInFolder(ContentResolver cr, long folderId);
public boolean isVisited(ContentResolver cr, String uri);
public int getReadingListCount(ContentResolver cr);
@RobocopTarget
public boolean isBookmark(ContentResolver cr, String uri);
public boolean isReadingListItem(ContentResolver cr, String uri);
public String getUrlForKeyword(ContentResolver cr, String keyword);
@RobocopTarget
public void addBookmark(ContentResolver cr, String title, String uri);
public void removeBookmark(ContentResolver cr, int id);
@RobocopTarget
public void removeBookmarksWithURL(ContentResolver cr, String uri);
@RobocopTarget
public void updateBookmark(ContentResolver cr, int id, String uri, String title, String keyword);
public void addReadingListItem(ContentResolver cr, String title, String uri);
@ -93,10 +102,12 @@ public class BrowserDB {
public void updateThumbnailForUrl(ContentResolver cr, String uri, BitmapDrawable thumbnail);
@RobocopTarget
public byte[] getThumbnailForUrl(ContentResolver cr, String uri);
public Cursor getThumbnailsForUrls(ContentResolver cr, List<String> urls);
@RobocopTarget
public void removeThumbnails(ContentResolver cr);
public void registerBookmarkObserver(ContentResolver cr, ContentObserver observer);
@ -113,6 +124,7 @@ public class BrowserDB {
public Cursor getPinnedSites(ContentResolver cr, int limit);
@RobocopTarget
public Cursor getBookmarkForUrl(ContentResolver cr, String url);
}
@ -129,6 +141,7 @@ public class BrowserDB {
sDb.invalidateCachedState();
}
@RobocopTarget
public static Cursor filter(ContentResolver cr, CharSequence constraint, int limit) {
return sDb.filter(cr, constraint, limit);
}
@ -160,6 +173,7 @@ public class BrowserDB {
}
}
@RobocopTarget
public static Cursor getAllVisitedHistory(ContentResolver cr) {
return (sAreContentProvidersEnabled ? sDb.getAllVisitedHistory(cr) : null);
}
@ -181,14 +195,17 @@ public class BrowserDB {
sDb.removeHistoryEntry(cr, id);
}
@RobocopTarget
public static void removeHistoryEntry(ContentResolver cr, String url) {
sDb.removeHistoryEntry(cr, url);
}
@RobocopTarget
public static void clearHistory(ContentResolver cr) {
sDb.clearHistory(cr);
}
@RobocopTarget
public static Cursor getBookmarksInFolder(ContentResolver cr, long folderId) {
return sDb.getBookmarksInFolder(cr, folderId);
}
@ -205,6 +222,7 @@ public class BrowserDB {
return sDb.getReadingListCount(cr);
}
@RobocopTarget
public static boolean isBookmark(ContentResolver cr, String uri) {
return (sAreContentProvidersEnabled && sDb.isBookmark(cr, uri));
}
@ -221,10 +239,12 @@ public class BrowserDB {
sDb.removeBookmark(cr, id);
}
@RobocopTarget
public static void removeBookmarksWithURL(ContentResolver cr, String uri) {
sDb.removeBookmarksWithURL(cr, uri);
}
@RobocopTarget
public static void updateBookmark(ContentResolver cr, int id, String uri, String title, String keyword) {
sDb.updateBookmark(cr, id, uri, title, keyword);
}
@ -253,6 +273,7 @@ public class BrowserDB {
sDb.updateThumbnailForUrl(cr, uri, thumbnail);
}
@RobocopTarget
public static byte[] getThumbnailForUrl(ContentResolver cr, String uri) {
return sDb.getThumbnailForUrl(cr, uri);
}
@ -261,6 +282,7 @@ public class BrowserDB {
return sDb.getThumbnailsForUrls(cr, urls);
}
@RobocopTarget
public static void removeThumbnails(ContentResolver cr) {
sDb.removeThumbnails(cr);
}
@ -297,6 +319,7 @@ public class BrowserDB {
return sDb.getPinnedSites(cr, limit);
}
@RobocopTarget
public static Cursor getBookmarkForUrl(ContentResolver cr, String url) {
return sDb.getBookmarkForUrl(cr, url);
}

View File

@ -20,6 +20,7 @@ import org.mozilla.gecko.db.BrowserContract.SyncColumns;
import org.mozilla.gecko.db.BrowserContract.Thumbnails;
import org.mozilla.gecko.db.BrowserContract.URLColumns;
import org.mozilla.gecko.gfx.BitmapUtils;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.sync.Utils;
import org.mozilla.gecko.util.GeckoJarReader;
import org.mozilla.gecko.util.ThreadUtils;
@ -1991,6 +1992,7 @@ public class BrowserProvider extends ContentProvider {
return dbHelper;
}
@RobocopTarget
public String getDatabasePath(String profile, boolean isTest) {
trace("Getting database path for profile: " + profile);

View File

@ -12,9 +12,7 @@ import java.util.Map;
import org.mozilla.gecko.GeckoProfile;
import org.mozilla.gecko.db.BrowserContract.Clients;
import org.mozilla.gecko.db.BrowserContract.Tabs;
import org.mozilla.gecko.db.BrowserContract;
import org.mozilla.gecko.db.DBUtils;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.mozglue.RobocopTarget;
import android.content.ContentProvider;
import android.content.ContentUris;
@ -248,6 +246,7 @@ public class TabsProvider extends ContentProvider {
return dbHelper;
}
@RobocopTarget
private String getDatabasePath(String profile) {
trace("Getting database path for profile: " + profile);

View File

@ -5,16 +5,15 @@
package org.mozilla.gecko.gfx;
import org.mozilla.gecko.BrowserApp;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.ZoomConstraints;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI;
import org.mozilla.gecko.util.EventDispatcher;
import org.mozilla.gecko.util.FloatUtils;
import org.mozilla.gecko.util.ThreadUtils;
import android.content.Context;
import android.graphics.PointF;
@ -56,7 +55,6 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
*/
private ImmutableViewportMetrics mFrameMetrics;
/* Used by robocop for testing purposes */
private DrawListener mDrawListener;
/* Used as temporaries by syncViewportInfo */
@ -975,11 +973,13 @@ public class GeckoLayerClient implements LayerView.Listener, PanZoomTarget
}
/** Used by robocop for testing purposes. Not for production use! */
@RobocopTarget
public void setDrawListener(DrawListener listener) {
mDrawListener = listener;
}
/** Used by robocop for testing purposes. Not for production use! */
@RobocopTarget
public static interface DrawListener {
public void drawFinished();
}

View File

@ -25,6 +25,7 @@ import android.graphics.RectF;
import android.opengl.GLES20;
import android.os.SystemClock;
import android.util.Log;
import org.mozilla.gecko.mozglue.JNITarget;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@ -81,7 +82,6 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
private boolean mProfileRender;
private long mProfileOutputTime;
/* Used by robocop for testing purposes */
private IntBuffer mPixelBuffer;
// Used by GLES 2.0
@ -489,6 +489,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
}
/** This function is invoked via JNI; be careful when modifying signature. */
@JNITarget
public void beginDrawing() {
mFrameStartTime = System.nanoTime();
@ -578,6 +579,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
}
/** This function is invoked via JNI; be careful when modifying signature. */
@JNITarget
public void drawBackground() {
// Any GL state which is changed here must be restored in
// CompositorOGL::RestoreState
@ -612,7 +614,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
rootLayer.draw(mPageContext);
}
/** This function is invoked via JNI; be careful when modifying signature. */
@JNITarget
public void drawForeground() {
// Any GL state which is changed here must be restored in
// CompositorOGL::RestoreState
@ -666,6 +668,7 @@ public class LayerRenderer implements Tabs.OnTabsChangedListener {
}
/** This function is invoked via JNI; be careful when modifying signature. */
@JNITarget
public void endDrawing() {
// If a layer update requires further work, schedule another redraw
if (!mUpdated)

View File

@ -15,6 +15,7 @@ import org.mozilla.gecko.db.BrowserDB.URLColumns;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.home.SearchEngine;
import org.mozilla.gecko.home.SearchLoader.SearchCursorLoader;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.toolbar.AutocompleteHandler;
import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.StringUtils;
@ -27,10 +28,8 @@ import org.json.JSONObject;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
@ -96,6 +95,7 @@ public class BrowserSearch extends HomeFragment
private HomeListView mList;
// Client that performs search suggestion queries
@RobocopTarget
private volatile SuggestClient mSuggestClient;
// List of search engines from gecko

View File

@ -13,6 +13,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.text.TextUtils;
import android.util.Log;
import org.mozilla.gecko.mozglue.RobocopTarget;
import java.io.BufferedInputStream;
import java.io.IOException;
@ -53,8 +54,13 @@ class SuggestClient {
mCheckNetwork = true;
}
/**
* This constructor is used exclusively by Robocop.
*/
@RobocopTarget
public SuggestClient(Context context, String suggestTemplate, int timeout) {
this(context, suggestTemplate, timeout, Integer.MAX_VALUE);
mCheckNetwork = false;
}
/**

View File

@ -18,8 +18,11 @@ mgjar.sources += [
'mozglue/generatorannotations/OptionalGeneratedParameter.java',
'mozglue/generatorannotations/WrapElementForJNI.java',
'mozglue/generatorannotations/WrapEntireClassForJNI.java',
'mozglue/JNITarget.java',
'mozglue/NativeReference.java',
'mozglue/NativeZip.java',
'mozglue/RobocopTarget.java',
'mozglue/WebRTCJNITarget.java',
]
mgjar.generated_sources += [
'org/mozilla/gecko/mozglue/GeckoLoader.java',

View File

@ -0,0 +1,11 @@
/* 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.mozglue;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.CLASS)
public @interface JNITarget {}

View File

@ -0,0 +1,12 @@
/* 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.mozglue;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.CLASS)
public @interface RobocopTarget {}

View File

@ -0,0 +1,11 @@
/* 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.mozglue;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.CLASS)
public @interface WebRTCJNITarget {}

View File

@ -10,6 +10,7 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.text.TextUtils;
import android.util.Log;
import org.mozilla.gecko.mozglue.RobocopTarget;
import java.util.ArrayList;
import java.util.Map.Entry;
@ -120,7 +121,7 @@ public class SQLiteBridge {
return rawQuery(sb.toString(), selectionArgs);
}
/* This method is referenced by Robocop via reflection. */
@RobocopTarget
public Cursor rawQuery(String sql, String[] selectionArgs)
throws SQLiteBridgeException {
return internalQuery(sql, selectionArgs);

View File

@ -106,14 +106,10 @@ public class testSearchSuggestions extends BaseTest {
ClassLoader classLoader = getActivity().getApplicationContext().getClassLoader();
Class suggestClass = classLoader.loadClass("org.mozilla.gecko.home.SuggestClient");
Constructor suggestConstructor = suggestClass.getConstructor(
new Class[] { Context.class, String.class, int.class, int.class });
new Class[] { Context.class, String.class, int.class });
String suggestTemplate = getAbsoluteRawUrl(SUGGESTION_TEMPLATE);
Object client = suggestConstructor.newInstance(activity, suggestTemplate, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
// enable offline HTTP requests for testing
final Field checkNetworkField = suggestClass.getDeclaredField("mCheckNetwork");
checkNetworkField.setAccessible(true);
checkNetworkField.setBoolean(client, false);
Object client = suggestConstructor.newInstance(activity, suggestTemplate, SUGGESTION_TIMEOUT);
// replace mSuggestClient with test client
final Class browserSearchClass = classLoader.loadClass("org.mozilla.gecko.home.BrowserSearch");

View File

@ -6,10 +6,9 @@
package org.mozilla.gecko.util;
import org.json.JSONObject;
import org.mozilla.gecko.mozglue.RobocopTarget;
/* This class is referenced by Robocop via reflection; use care when
* modifying the signature.
*/
@RobocopTarget
public interface GeckoEventListener {
void handleMessage(String event, JSONObject message);
}

View File

@ -10,6 +10,7 @@ import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.util.Log;
import org.mozilla.gecko.mozglue.RobocopTarget;
import java.io.BufferedReader;
import java.io.IOException;
@ -98,7 +99,7 @@ public final class GeckoJarReader {
return new NativeZip(fileUrl.getPath());
}
// Public for testing only.
@RobocopTarget
public static InputStream getStream(String url) {
Stack<String> jarUrls = parseUrl(url);
try {

View File

@ -141,7 +141,8 @@ nsAppStartup::nsAppStartup() :
mRestart(false),
mInterrupted(false),
mIsSafeModeNecessary(false),
mStartupCrashTrackingEnded(false)
mStartupCrashTrackingEnded(false),
mRestartTouchEnvironment(false)
{ }
@ -269,7 +270,14 @@ nsAppStartup::Run(void)
return rv;
}
return mRestart ? NS_SUCCESS_RESTART_APP : NS_OK;
nsresult retval = NS_OK;
if (mRestartTouchEnvironment) {
retval = NS_SUCCESS_RESTART_METRO_APP;
} else if (mRestart) {
retval = NS_SUCCESS_RESTART_APP;
}
return retval;
}
@ -360,7 +368,12 @@ nsAppStartup::Quit(uint32_t aMode)
gRestartMode = (aMode & 0xF0);
}
if (mRestart) {
if (!mRestartTouchEnvironment) {
mRestartTouchEnvironment = (aMode & eRestartTouchEnvironment) != 0;
gRestartMode = (aMode & 0xF0);
}
if (mRestart || mRestartTouchEnvironment) {
// Mark the next startup as a restart.
PR_SetEnv("MOZ_APP_RESTART=1");
@ -430,7 +443,8 @@ nsAppStartup::Quit(uint32_t aMode)
NS_NAMED_LITERAL_STRING(shutdownStr, "shutdown");
NS_NAMED_LITERAL_STRING(restartStr, "restart");
obsService->NotifyObservers(nullptr, "quit-application",
mRestart ? restartStr.get() : shutdownStr.get());
(mRestart || mRestartTouchEnvironment) ?
restartStr.get() : shutdownStr.get());
}
if (!mRunning) {
@ -553,6 +567,14 @@ nsAppStartup::GetWasRestarted(bool *aResult)
return NS_OK;
}
NS_IMETHODIMP
nsAppStartup::GetRestartingTouchEnvironment(bool *aResult)
{
NS_ENSURE_ARG_POINTER(aResult);
*aResult = mRestartTouchEnvironment;
return NS_OK;
}
NS_IMETHODIMP
nsAppStartup::SetInterrupted(bool aInterrupted)
{

View File

@ -62,6 +62,7 @@ private:
bool mInterrupted; // Was startup interrupted by an interactive prompt?
bool mIsSafeModeNecessary; // Whether safe mode is necessary
bool mStartupCrashTrackingEnded; // Whether startup crash tracking has already ended
bool mRestartTouchEnvironment; // Quit (eRestartTouchEnvironment)
#if defined(XP_WIN)
//Interaction with OS-provided profiling probes

View File

@ -7,7 +7,8 @@
interface nsICmdLineService;
[scriptable, uuid(9edef217-e664-4938-85a7-2fe84baa1755)]
[scriptable, uuid(bc0cb41f-4924-4c69-a65b-e35225a8650f)]
interface nsIAppStartup : nsISupports
{
/**
@ -30,6 +31,11 @@ interface nsIAppStartup : nsISupports
* @returnCode NS_SUCCESS_RESTART_APP
* This return code indicates that the application should be
* restarted because quit was called with the eRestart flag.
* @returnCode NS_SUCCESS_RESTART_METRO_APP
* This return code indicates that the application should be
* restarted in metro because quit was called with the
* eRestartTouchEnviroment flag.
*/
void run();
@ -121,6 +127,13 @@ interface nsIAppStartup : nsISupports
*/
const uint32_t eRestartx86_64 = 0x40;
/**
* Restart the application in a touch-optimized environment (such as Metro)
* after quitting. The application will be restarted with the same profile
* and an empty command line.
*/
const uint32_t eRestartTouchEnvironment = 0x80;
/**
* Exit the event loop, and shut down the app.
*
@ -160,6 +173,12 @@ interface nsIAppStartup : nsISupports
*/
readonly attribute boolean wasRestarted;
/**
* True if the application is being restarted in a touch-optimized
* environment (such as Metro).
*/
readonly attribute boolean restartingTouchEnvironment;
/**
* Returns an object with main, process, firstPaint, sessionRestored properties.
* Properties may not be available depending on platform or application

View File

@ -673,8 +673,17 @@
</field>
<property name="userTypedValue"
onget="return this._userTypedValue;"
onset="this.userTypedClear = 0; return this._userTypedValue = val;"/>
onget="return this._userTypedValue;">
<setter><![CDATA[
this.userTypedClear = 0;
this._userTypedValue = val;
let event = new CustomEvent("UserTypedValueChanged");
this.dispatchEvent(event);
return val;
]]></setter>
</property>
<field name="mFormFillAttached">
false

View File

@ -0,0 +1,161 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
'use strict';
this.EXPORTED_SYMBOLS = [];
#ifdef XP_WIN
#ifdef MOZ_METRO
const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} =
Components;
const PREF_BASE_KEY = "Software\\Mozilla\\Firefox\\Metro\\Prefs\\";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
this.EXPORTED_SYMBOLS = [ "WindowsPrefSync" ];
/**
* Manages preferences that need to be pulled and pushed between Metro
* and desktop.
*/
this.WindowsPrefSync = {
init: function() {
this.pullSharedPrefs();
this.prefListToPush.forEach(function(prefName) {
this.pushSharedPref(prefName);
Services.prefs.addObserver(prefName, this, false);
}, this);
},
uninit: function() {
this.prefListToPush.forEach(function(prefName) {
Services.prefs.removeObserver(prefName, this);
}, this);
},
/**
* Returns the list of prefs that should be pushed for the current
* environment.
*/
get prefListToPush() {
return !Services.metro.immersive ? this.desktopControlledPrefs :
this.metroControlledPrefs;
},
/**
* Returns the list of prefs that should be pulled for the current
* environment.
*/
get prefListToPull() {
return Services.metro.immersive ? this.desktopControlledPrefs :
this.metroControlledPrefs;
},
/**
* The following preferences will be pushed to registry from Desktop
* Firefox and pulled in from Metro Firefox.
*
* app.update.* prefs are because Metro shares an installation directory with
* Firefox, and the options for these are only present in the Desktop options.
*
* browser.sessionstore.resume_session_once is mainly for the switch to Metro
* and switch to Desktop feature.
*/
desktopControlledPrefs: ["app.update.auto",
"app.update.enabled",
"app.update.service.enabled",
"app.update.metro.enabled",
"browser.sessionstore.resume_session_once"],
/**
* The following preferences will be pushed to registry from Metro
* Firefox and pulled in from Desktop Firefox.
*
* browser.sessionstore.resume_session_once is mainly for the switch to Metro
* and switch to Desktop feature.
*/
metroControlledPrefs: ["browser.sessionstore.resume_session_once"],
/**
* Observes preference changes and writes them to the registry, only
* the list of preferences initialized will be observed
*/
observe: function (aSubject, aTopic, aPrefName) {
if (aTopic != "nsPref:changed")
return;
this.pushSharedPref(aPrefName);
},
/**
* Writes the pref to HKCU in the registry and adds a pref-observer to keep
* the registry in sync with changes to the value.
*/
pushSharedPref : function(aPrefName) {
let registry = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
try {
var prefType = Services.prefs.getPrefType(aPrefName);
let prefFunc;
if (prefType == Ci.nsIPrefBranch.PREF_INT)
prefFunc = "getIntPref";
else if (prefType == Ci.nsIPrefBranch.PREF_BOOL)
prefFunc = "getBoolPref";
else if (prefType == Ci.nsIPrefBranch.PREF_STRING)
prefFunc = "getCharPref";
else
throw "Unsupported pref type";
let prefValue = Services.prefs[prefFunc](aPrefName);
registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
PREF_BASE_KEY + prefType,
Ci.nsIWindowsRegKey.ACCESS_WRITE);
// Always write as string, but the registry subfolder will determine
// how Metro interprets that string value.
registry.writeStringValue(aPrefName, prefValue);
} catch (ex) {
Cu.reportError("Couldn't push pref " + aPrefName + ": " + ex);
} finally {
registry.close();
}
},
/**
* Pulls in all shared prefs from the registry
*/
pullSharedPrefs: function() {
function pullSharedPrefType(prefType, prefFunc) {
try {
registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
PREF_BASE_KEY + prefType,
Ci.nsIWindowsRegKey.ACCESS_ALL);
for (let i = 0; i < registry.valueCount; i++) {
let prefName = registry.getValueName(i);
let prefValue = registry.readStringValue(prefName);
if (prefType == Ci.nsIPrefBranch.PREF_BOOL) {
prefValue = prefValue == "true";
}
if (self.prefListToPull.indexOf(prefName) != -1) {
Services.prefs[prefFunc](prefName, prefValue);
}
}
} catch (ex) {
dump("Could not pull for prefType " + prefType + ": " + ex + "\n");
} finally {
registry.close();
}
}
let self = this;
let registry = Cc["@mozilla.org/windows-registry-key;1"].
createInstance(Ci.nsIWindowsRegKey);
pullSharedPrefType(Ci.nsIPrefBranch.PREF_INT, "setIntPref");
pullSharedPrefType(Ci.nsIPrefBranch.PREF_BOOL, "setBoolPref");
pullSharedPrefType(Ci.nsIPrefBranch.PREF_STRING, "setCharPref");
}
};
#endif
#endif

View File

@ -52,6 +52,7 @@ EXTRA_PP_JS_MODULES += [
'Troubleshoot.jsm',
'UpdateChannel.jsm',
'WindowDraggingUtils.jsm',
'WindowsPrefSync.jsm',
]
if 'Android' != CONFIG['OS_TARGET']:

View File

@ -127,6 +127,10 @@
#include "nsXREDirProvider.h"
#include "nsToolkitCompsCID.h"
#if defined(XP_WIN) && defined(MOZ_METRO)
#include "updatehelper.h"
#endif
#include "nsINIParser.h"
#include "mozilla/Omnijar.h"
#include "mozilla/StartupTimeline.h"
@ -4047,12 +4051,18 @@ XREMain::XRE_main(int argc, char* argv[], const nsXREAppData* aAppData)
// Check for an application initiated restart. This is one that
// corresponds to nsIAppStartup.quit(eRestart)
if (rv == NS_SUCCESS_RESTART_APP) {
if (rv == NS_SUCCESS_RESTART_APP || rv == NS_SUCCESS_RESTART_METRO_APP) {
appInitiatedRestart = true;
// We have an application restart don't do any shutdown checks here
// In particular we don't want to poison IO for checking late-writes.
gShutdownChecks = SCM_NOTHING;
#if defined(MOZ_METRO) && defined(XP_WIN)
if (rv == NS_SUCCESS_RESTART_METRO_APP) {
LaunchDefaultMetroBrowser();
}
#endif
}
if (!mShuttingDown) {

View File

@ -12,7 +12,7 @@
* implementation of this interface for non-Windows systems, for testing and
* development purposes only.
*/
[scriptable, uuid(496b4450-5757-40f7-aeb9-a958ae86dbd1)]
[scriptable, uuid(d30daa27-ce2b-4503-80cc-b162f4c24e93)]
interface nsIWinMetroUtils : nsISupports
{
/**
@ -84,29 +84,6 @@ interface nsIWinMetroUtils : nsISupports
*/
bool isTilePinned(in AString aTileID);
/**
* Stores the sync info securely
*
* @param aEmail The sync account email
* @param aPassword The sync account password
* @param aKey The sync account key
*/
void storeSyncInfo(in AString aEmail, in AString aPassword, in AString aKey);
/**
* Loads the sync info
*
* @param aEmail The sync account email
* @param aPassword The sync account password
* @param aKey The sync account key
*/
void loadSyncInfo(out AString aEmail, out AString aPassword, out AString aKey);
/**
* Clears the stored sync info if any.
*/
void clearSyncInfo();
/**
* Soft keyboard attributes. Used in unison with shown/hidden observer
* events sent via FrameworkView.

View File

@ -125,6 +125,8 @@
#include "nsIWidgetListener.h"
#include "mozilla/dom/Touch.h"
#include "mozilla/gfx/2D.h"
#include "nsToolkitCompsCID.h"
#include "nsIAppStartup.h"
#include "mozilla/WindowsVersion.h"
#ifdef MOZ_ENABLE_D3D9_LAYER
@ -174,6 +176,10 @@
#include "npapi.h"
#if !defined(SM_CONVERTIBLESLATEMODE)
#define SM_CONVERTIBLESLATEMODE 0x2003
#endif
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::layers;
@ -5462,6 +5468,21 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
}
}
break;
case WM_SETTINGCHANGE:
if (IsWin8OrLater() && lParam &&
!wcsicmp(L"ConvertibleSlateMode", (wchar_t*)lParam)) {
// If we're switching into slate mode, switch to Metro for hardware
// that supports this feature.
if (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0) {
nsCOMPtr<nsIAppStartup> appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID));
if (appStartup) {
appStartup->Quit(nsIAppStartup::eForceQuit |
nsIAppStartup::eRestartTouchEnvironment);
}
}
}
break;
}
//*aRetValue = result;

View File

@ -15,6 +15,7 @@
#include "WinUtils.h"
#include "nsIAppStartup.h"
#include "nsToolkitCompsCID.h"
#include <shellapi.h>
using namespace mozilla;
using namespace mozilla::widget;
@ -113,7 +114,7 @@ HRESULT SHCreateShellItemArrayFromShellItemDynamic(IShellItem *psi, REFIID riid,
}
BOOL
WinLaunchDeferredMetroFirefox()
WinLaunchDeferredMetroFirefox(bool aInMetro)
{
// Create an instance of the Firefox Metro DEH which is used to launch the browser
const CLSID CLSID_FirefoxMetroDEH = {0x5100FEC1,0x212B, 0x4BF5 ,{0x9B,0xF8, 0x3E,0x65, 0x0F,0xD7,0x94,0xA3}};
@ -159,7 +160,11 @@ WinLaunchDeferredMetroFirefox()
if (FAILED(hr))
return FALSE;
hr = executeCommand->SetParameters(L"--metro-restart");
if (aInMetro) {
hr = executeCommand->SetParameters(L"--metro-restart");
} else {
hr = executeCommand->SetParameters(L"--desktop-restart");
}
if (FAILED(hr))
return FALSE;
@ -195,17 +200,36 @@ MetroAppShell::Run(void)
mozilla::widget::StopAudioSession();
nsCOMPtr<nsIAppStartup> appStartup (do_GetService(NS_APPSTARTUP_CONTRACTID));
bool restarting;
if (appStartup && NS_SUCCEEDED(appStartup->GetRestarting(&restarting)) && restarting) {
if (!WinLaunchDeferredMetroFirefox()) {
NS_WARNING("Couldn't deferred launch Metro Firefox.");
}
bool restartingInMetro = false, restarting = false;
if (appStartup && NS_SUCCEEDED(appStartup->GetRestartingTouchEnvironment(&restartingInMetro)) &&
restartingInMetro) {
WinLaunchDeferredMetroFirefox(true);
}
if (!appStartup || NS_FAILED(appStartup->GetRestarting(&restarting))) {
WinUtils::Log("appStartup->GetRestarting() unsuccessful");
}
// This calls XRE_metroShutdown() in xre. This will also destroy
// MessagePump.
sMetroApp->ShutdownXPCOM();
if (restarting) {
SHELLEXECUTEINFOW sinfo;
memset(&sinfo, 0, sizeof(SHELLEXECUTEINFOW));
sinfo.cbSize = sizeof(SHELLEXECUTEINFOW);
// Per the Metro style enabled desktop browser, for some reason,
// SEE_MASK_FLAG_LOG_USAGE is needed to change from immersive mode
// to desktop.
sinfo.fMask = SEE_MASK_FLAG_LOG_USAGE;
sinfo.lpFile = L"http://-desktop";
sinfo.lpVerb = L"open";
sinfo.lpParameters = L"--desktop-restart";
sinfo.nShow = SW_SHOWNORMAL;
ShellExecuteEx(&sinfo);
}
// This will free the real main thread in CoreApplication::Run()
// once winrt cleans up this thread.
sMetroApp->CoreExit();

View File

@ -60,6 +60,10 @@ using namespace ABI::Windows::Graphics::Display;
extern PRLogModuleInfo* gWindowsLog;
#endif
#if !defined(SM_CONVERTIBLESLATEMODE)
#define SM_CONVERTIBLESLATEMODE 0x2003
#endif
static uint32_t gInstanceCount = 0;
const PRUnichar* kMetroSubclassThisProp = L"MetroSubclassThisProp";
HWND MetroWidget::sICoreHwnd = nullptr;
@ -710,6 +714,17 @@ MetroWidget::WindowProcedure(HWND aWnd, UINT aMsg, WPARAM aWParam, LPARAM aLPara
{
if(sDefaultBrowserMsgId == aMsg) {
CloseGesture();
} else if (WM_SETTINGCHANGE == aMsg) {
if (aLParam && !wcsicmp(L"ConvertibleSlateMode", (wchar_t*)aLParam)) {
// If we're switching away from slate mode, switch to Desktop for
// hardware that supports this feature.
if (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) != 0) {
nsCOMPtr<nsIAppStartup> appStartup(do_GetService(NS_APPSTARTUP_CONTRACTID));
if (appStartup) {
appStartup->Quit(nsIAppStartup::eForceQuit | nsIAppStartup::eRestart);
}
}
}
}
// Indicates if we should hand messages to the default windows

View File

@ -8,14 +8,12 @@
#include "nsXULAppAPI.h"
#include "FrameworkView.h"
#include "MetroApp.h"
#include "nsIWindowsRegKey.h"
#include "ToastNotificationHandler.h"
#include <shldisp.h>
#include <shellapi.h>
#include <windows.ui.viewmanagement.h>
#include <windows.ui.startscreen.h>
#include <Wincrypt.h>
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::UI::StartScreen;
@ -35,11 +33,6 @@ extern ComPtr<FrameworkView> sFrameworkView;
namespace mozilla {
namespace widget {
static LPCWSTR sSyncEmailField = L"sync-e";
static LPCWSTR sSyncPasswordField = L"sync-p";
static LPCWSTR sSyncKeyField = L"sync-k";
static LPCSTR sRegPath = "Software\\Mozilla\\Firefox";
NS_IMPL_ISUPPORTS1(nsWinMetroUtils, nsIWinMetroUtils)
nsWinMetroUtils::nsWinMetroUtils()
@ -176,147 +169,6 @@ nsWinMetroUtils::IsTilePinned(const nsAString &aTileID, bool *aIsPinned)
return NS_OK;
}
/**
* Stores the sync info securely in Windows
*
* @param aEmail The sync account email
* @param aPassword The sync account password
* @param aKey The sync account key
*/
NS_IMETHODIMP
nsWinMetroUtils::StoreSyncInfo(const nsAString &aEmail,
const nsAString &aPassword,
const nsAString &aKey)
{
DATA_BLOB emailIn = {
(aEmail.Length() + 1) * 2,
(BYTE *)aEmail.BeginReading()},
passwordIn = {
(aPassword.Length() + 1) * 2,
(BYTE *)aPassword.BeginReading()},
keyIn = {
(aKey.Length() + 1) * 2,
(BYTE *)aKey.BeginReading()};
DATA_BLOB emailOut = { 0, nullptr }, passwordOut = {0, nullptr }, keyOut = { 0, nullptr };
bool succeeded = CryptProtectData(&emailIn, nullptr, nullptr, nullptr,
nullptr, 0, &emailOut) &&
CryptProtectData(&passwordIn, nullptr, nullptr, nullptr,
nullptr, 0, &passwordOut) &&
CryptProtectData(&keyIn, nullptr, nullptr, nullptr,
nullptr, 0, &keyOut);
if (succeeded) {
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> regKey
(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
NS_ConvertUTF8toUTF16(sRegPath),
nsIWindowsRegKey::ACCESS_SET_VALUE);
if (NS_FAILED(regKey->WriteBinaryValue(nsDependentString(sSyncEmailField),
nsAutoCString((const char *)emailOut.pbData,
emailOut.cbData)))) {
succeeded = false;
}
if (succeeded &&
NS_FAILED(regKey->WriteBinaryValue(nsDependentString(sSyncPasswordField),
nsAutoCString((const char *)passwordOut.pbData,
passwordOut.cbData)))) {
succeeded = false;
}
if (succeeded &&
NS_FAILED(regKey->WriteBinaryValue(nsDependentString(sSyncKeyField),
nsAutoCString((const char *)keyOut.pbData,
keyOut.cbData)))) {
succeeded = false;
}
regKey->Close();
}
LocalFree(emailOut.pbData);
LocalFree(passwordOut.pbData);
LocalFree(keyOut.pbData);
return succeeded ? NS_OK : NS_ERROR_FAILURE;
}
/**
* Loads the sync info securely in Windows
*
* @param aEmail The sync account email
* @param aPassword The sync account password
* @param aKey The sync account key
*/
NS_IMETHODIMP
nsWinMetroUtils::LoadSyncInfo(nsAString &aEmail, nsAString &aPassword,
nsAString &aKey)
{
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> regKey
(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
NS_ConvertUTF8toUTF16(sRegPath),
nsIWindowsRegKey::ACCESS_QUERY_VALUE);
nsAutoCString email, password, key;
if (NS_FAILED(regKey->ReadBinaryValue(nsDependentString(sSyncEmailField), email)) ||
NS_FAILED(regKey->ReadBinaryValue(nsDependentString(sSyncPasswordField), password)) ||
NS_FAILED(regKey->ReadBinaryValue(nsDependentString(sSyncKeyField), key))) {
return NS_ERROR_FAILURE;
}
regKey->Close();
DATA_BLOB emailIn = { email.Length(), (BYTE*)email.BeginReading() },
passwordIn = { password.Length(), (BYTE*)password.BeginReading() },
keyIn = { key.Length(), (BYTE*)key.BeginReading() };
DATA_BLOB emailOut = { 0, nullptr }, passwordOut = { 0, nullptr }, keyOut = { 0, nullptr };
bool succeeded = CryptUnprotectData(&emailIn, nullptr, nullptr, nullptr,
nullptr, 0, &emailOut) &&
CryptUnprotectData(&passwordIn, nullptr, nullptr, nullptr,
nullptr, 0, &passwordOut) &&
CryptUnprotectData(&keyIn, nullptr, nullptr, nullptr,
nullptr, 0, &keyOut);
if (succeeded) {
aEmail = reinterpret_cast<wchar_t*>(emailOut.pbData);
aPassword = reinterpret_cast<wchar_t*>(passwordOut.pbData);
aKey = reinterpret_cast<wchar_t*>(keyOut.pbData);
}
LocalFree(emailOut.pbData);
LocalFree(passwordOut.pbData);
LocalFree(keyOut.pbData);
return succeeded ? NS_OK : NS_ERROR_FAILURE;
}
/**
* Clears the stored sync info if any.
*/
NS_IMETHODIMP
nsWinMetroUtils::ClearSyncInfo()
{
nsresult rv;
nsCOMPtr<nsIWindowsRegKey> regKey
(do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
NS_ConvertUTF8toUTF16(sRegPath),
nsIWindowsRegKey::ACCESS_WRITE);
nsresult rv1 = regKey->RemoveValue(nsDependentString(sSyncEmailField));
nsresult rv2 = regKey->RemoveValue(nsDependentString(sSyncPasswordField));
nsresult rv3 = regKey->RemoveValue(nsDependentString(sSyncKeyField));
regKey->Close();
if (NS_FAILED(rv1) || NS_FAILED(rv2) || NS_FAILED(rv3)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
/**
* Launches the specified application with the specified arguments and
* switches to Desktop mode if in metro mode.

View File

@ -856,6 +856,7 @@
* the application should be restarted. This condition corresponds to the
* case in which nsIAppStartup::Quit was called with the eRestart flag. */
ERROR(NS_SUCCESS_RESTART_APP, SUCCESS(1)),
ERROR(NS_SUCCESS_RESTART_METRO_APP, SUCCESS(1)),
ERROR(NS_SUCCESS_UNORM_NOTFOUND, SUCCESS(17)),