Merge mozilla-central and b2g-inbound

This commit is contained in:
Ed Morley 2014-08-19 15:19:13 +01:00
commit b2932bde56
30 changed files with 861 additions and 706 deletions

View File

@ -992,8 +992,8 @@ pref("browser.autofocus", false);
// Enable wakelock
pref("dom.wakelock.enabled", true);
// Disable touch caret by default
pref("touchcaret.enabled", false);
// Enable touch caret by default
pref("touchcaret.enabled", true);
// Disable selection caret by default
pref("selectioncaret.enabled", false);

View File

@ -0,0 +1,251 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* 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 file is only loaded on Gonk to manage ADB state
let AdbController = {
DEBUG: false,
locked: undefined,
remoteDebuggerEnabled: undefined,
lockEnabled: undefined,
disableAdbTimer: null,
disableAdbTimeoutHours: 12,
umsActive: false,
debug: function(str) {
dump("AdbController: " + str + "\n");
},
setLockscreenEnabled: function(value) {
this.lockEnabled = value;
if (this.DEBUG) {
this.debug("setLockscreenEnabled = " + this.lockEnabled);
}
this.updateState();
},
setLockscreenState: function(value) {
this.locked = value;
if (this.DEBUG) {
this.debug("setLockscreenState = " + this.locked);
}
this.updateState();
},
setRemoteDebuggerState: function(value) {
this.remoteDebuggerEnabled = value;
if (this.DEBUG) {
this.debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled);
}
this.updateState();
},
startDisableAdbTimer: function() {
if (this.disableAdbTimer) {
this.disableAdbTimer.cancel();
} else {
this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
try {
this.disableAdbTimeoutHours =
Services.prefs.getIntPref("b2g.adb.timeout-hours");
} catch (e) {
// This happens if the pref doesn't exist, in which case
// disableAdbTimeoutHours will still be set to the default.
}
}
if (this.disableAdbTimeoutHours <= 0) {
if (this.DEBUG) {
this.debug("Timer to disable ADB not started due to zero timeout");
}
return;
}
if (this.DEBUG) {
this.debug("Starting timer to disable ADB in " +
this.disableAdbTimeoutHours + " hours");
}
let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000;
this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds,
Ci.nsITimer.TYPE_ONE_SHOT);
},
stopDisableAdbTimer: function() {
if (this.DEBUG) {
this.debug("Stopping timer to disable ADB");
}
if (this.disableAdbTimer) {
this.disableAdbTimer.cancel();
this.disableAdbTimer = null;
}
},
notify: function(aTimer) {
if (aTimer == this.disableAdbTimer) {
this.disableAdbTimer = null;
// The following dump will be the last thing that shows up in logcat,
// and will at least give the user a clue about why logcat was
// disconnected, if the user happens to be using logcat.
dump("AdbController: ADB timer expired - disabling ADB\n");
navigator.mozSettings.createLock().set(
{'debugger.remote-mode': 'disabled'});
}
},
updateState: function() {
this.umsActive = false;
this.storages = navigator.getDeviceStorages('sdcard');
this.updateStorageState(0);
},
updateStorageState: function(storageIndex) {
if (storageIndex >= this.storages.length) {
// We've iterated through all of the storage objects, now we can
// really do updateStateInternal.
this.updateStateInternal();
return;
}
let storage = this.storages[storageIndex];
if (this.DEBUG) {
this.debug("Checking availability of storage: '" +
storage.storageName);
}
let req = storage.available();
req.onsuccess = function(e) {
if (this.DEBUG) {
this.debug("Storage: '" + storage.storageName + "' is '" +
e.target.result);
}
if (e.target.result == 'shared') {
// We've found a storage area that's being shared with the PC.
// We can stop looking now.
this.umsActive = true;
this.updateStateInternal();
return;
}
this.updateStorageState(storageIndex + 1);
}.bind(this);
req.onerror = function(e) {
dump("AdbController: error querying storage availability for '" +
this.storages[storageIndex].storageName + "' (ignoring)\n");
this.updateStorageState(storageIndex + 1);
}.bind(this);
},
updateStateInternal: function() {
if (this.DEBUG) {
this.debug("updateStateInternal: called");
}
if (this.remoteDebuggerEnabled === undefined ||
this.lockEnabled === undefined ||
this.locked === undefined) {
// Part of initializing the settings database will cause the observers
// to trigger. We want to wait until both have been initialized before
// we start changing ther adb state. Without this then we can wind up
// toggling adb off and back on again (or on and back off again).
//
// For completeness, one scenario which toggles adb is using the unagi.
// The unagi has adb enabled by default (prior to b2g starting). If you
// have the phone lock disabled and remote debugging enabled, then we'll
// receive an unlock event and an rde event. However at the time we
// receive the unlock event we haven't yet received the rde event, so
// we turn adb off momentarily, which disconnects a logcat that might
// be running. Changing the defaults (in AdbController) just moves the
// problem to a different phone, which has adb disabled by default and
// we wind up turning on adb for a short period when we shouldn't.
//
// By waiting until both values are properly initialized, we avoid
// turning adb on or off accidentally.
if (this.DEBUG) {
this.debug("updateState: Waiting for all vars to be initialized");
}
return;
}
// Check if we have a remote debugging session going on. If so, we won't
// disable adb even if the screen is locked.
let isDebugging = USBRemoteDebugger.isDebugging;
if (this.DEBUG) {
this.debug("isDebugging=" + isDebugging);
}
// If USB Mass Storage, USB tethering, or a debug session is active,
// then we don't want to disable adb in an automatic fashion (i.e.
// when the screen locks or due to timeout).
let sysUsbConfig = libcutils.property_get("sys.usb.config");
let rndisActive = (sysUsbConfig.split(",").indexOf("rndis") >= 0);
let usbFuncActive = rndisActive || this.umsActive || isDebugging;
let enableAdb = this.remoteDebuggerEnabled &&
(!(this.lockEnabled && this.locked) || usbFuncActive);
let useDisableAdbTimer = true;
try {
if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) {
// Marionette is enabled. Marionette requires that adb be on (and also
// requires that remote debugging be off). The fact that marionette
// is enabled also implies that we're doing a non-production build, so
// we want adb enabled all of the time.
enableAdb = true;
useDisableAdbTimer = false;
}
} catch (e) {
// This means that the pref doesn't exist. Which is fine. We just leave
// enableAdb alone.
}
if (this.DEBUG) {
this.debug("updateState: enableAdb = " + enableAdb +
" remoteDebuggerEnabled = " + this.remoteDebuggerEnabled +
" lockEnabled = " + this.lockEnabled +
" locked = " + this.locked +
" usbFuncActive = " + usbFuncActive);
}
// Configure adb.
let currentConfig = libcutils.property_get("persist.sys.usb.config");
let configFuncs = currentConfig.split(",");
let adbIndex = configFuncs.indexOf("adb");
if (enableAdb) {
// Add adb to the list of functions, if not already present
if (adbIndex < 0) {
configFuncs.push("adb");
}
} else {
// Remove adb from the list of functions, if present
if (adbIndex >= 0) {
configFuncs.splice(adbIndex, 1);
}
}
let newConfig = configFuncs.join(",");
if (newConfig != currentConfig) {
if (this.DEBUG) {
this.debug("updateState: currentConfig = " + currentConfig);
this.debug("updateState: newConfig = " + newConfig);
}
try {
libcutils.property_set("persist.sys.usb.config", newConfig);
} catch(e) {
dump("Error configuring adb: " + e);
}
}
if (useDisableAdbTimer) {
if (enableAdb && !usbFuncActive) {
this.startDisableAdbTimer();
} else {
this.stopDisableAdbTimer();
}
}
}
};
SettingsListener.observe("lockscreen.locked", false,
AdbController.setLockscreenState.bind(AdbController));
SettingsListener.observe("lockscreen.enabled", false,
AdbController.setLockscreenEnabled.bind(AdbController));

View File

@ -0,0 +1,275 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
/* 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";
XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function() {
Cu.import("resource://gre/modules/devtools/dbg-server.jsm");
return DebuggerServer;
});
XPCOMUtils.defineLazyGetter(this, "devtools", function() {
const { devtools } =
Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
return devtools;
});
XPCOMUtils.defineLazyGetter(this, "discovery", function() {
return devtools.require("devtools/toolkit/discovery/discovery");
});
let RemoteDebugger = {
_promptDone: false,
_promptAnswer: false,
_listening: false,
prompt: function() {
this._listen();
this._promptDone = false;
shell.sendChromeEvent({
"type": "remote-debugger-prompt"
});
while(!this._promptDone) {
Services.tm.currentThread.processNextEvent(true);
}
return this._promptAnswer;
},
_listen: function() {
if (this._listening) {
return;
}
this.handleEvent = this.handleEvent.bind(this);
let content = shell.contentBrowser.contentWindow;
content.addEventListener("mozContentEvent", this, false, true);
this._listening = true;
},
handleEvent: function(event) {
let detail = event.detail;
if (detail.type !== "remote-debugger-prompt") {
return;
}
this._promptAnswer = detail.value;
this._promptDone = true;
},
initServer: function() {
if (DebuggerServer.initialized) {
return;
}
// Ask for remote connections.
DebuggerServer.init(this.prompt.bind(this));
// /!\ Be careful when adding a new actor, especially global actors.
// Any new global actor will be exposed and returned by the root actor.
// Add Firefox-specific actors, but prevent tab actors to be loaded in
// the parent process, unless we enable certified apps debugging.
let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges);
/**
* Construct a root actor appropriate for use in a server running in B2G.
* The returned root actor respects the factories registered with
* DebuggerServer.addGlobalActor only if certified apps debugging is on,
* otherwise we used an explicit limited list of global actors
*
* * @param connection DebuggerServerConnection
* The conection to the client.
*/
DebuggerServer.createRootActor = function createRootActor(connection)
{
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
let parameters = {
// We do not expose browser tab actors yet,
// but we still have to define tabList.getList(),
// otherwise, client won't be able to fetch global actors
// from listTabs request!
tabList: {
getList: function() {
return promise.resolve([]);
}
},
// Use an explicit global actor list to prevent exposing
// unexpected actors
globalActorFactories: restrictPrivileges ? {
webappsActor: DebuggerServer.globalActorFactories.webappsActor,
deviceActor: DebuggerServer.globalActorFactories.deviceActor,
} : DebuggerServer.globalActorFactories
};
let { RootActor } = devtools.require("devtools/server/actors/root");
let root = new RootActor(connection, parameters);
root.applicationType = "operating-system";
return root;
};
#ifdef MOZ_WIDGET_GONK
DebuggerServer.on("connectionchange", function() {
AdbController.updateState();
});
#endif
}
};
let USBRemoteDebugger = {
get isDebugging() {
if (!this._listener) {
return false;
}
return DebuggerServer._connections &&
Object.keys(DebuggerServer._connections).length > 0;
},
start: function() {
if (this._listener) {
return;
}
RemoteDebugger.initServer();
let portOrPath =
Services.prefs.getCharPref("devtools.debugger.unix-domain-socket") ||
"/data/local/debugger-socket";
try {
debug("Starting USB debugger on " + portOrPath);
this._listener = DebuggerServer.openListener(portOrPath);
// Temporary event, until bug 942756 lands and offers a way to know
// when the server is up and running.
Services.obs.notifyObservers(null, "debugger-server-started", null);
} catch (e) {
debug("Unable to start USB debugger server: " + e);
}
},
stop: function() {
if (!this._listener) {
return;
}
try {
this._listener.close();
this._listener = null;
} catch (e) {
debug("Unable to stop USB debugger server: " + e);
}
}
};
let WiFiRemoteDebugger = {
start: function() {
if (this._listener) {
return;
}
RemoteDebugger.initServer();
try {
debug("Starting WiFi debugger");
this._listener = DebuggerServer.openListener(-1);
let port = this._listener.port;
debug("Started WiFi debugger on " + port);
discovery.addService("devtools", { port: port });
} catch (e) {
debug("Unable to start WiFi debugger server: " + e);
}
},
stop: function() {
if (!this._listener) {
return;
}
try {
discovery.removeService("devtools");
this._listener.close();
this._listener = null;
} catch (e) {
debug("Unable to stop WiFi debugger server: " + e);
}
}
};
(function() {
// Track these separately here so we can determine the correct value for the
// pref "devtools.debugger.remote-enabled", which is true when either mode of
// using DevTools is enabled.
let devtoolsUSB = false;
let devtoolsWiFi = false;
// Keep the old setting to not break people that won't have updated
// gaia and gecko.
SettingsListener.observe("devtools.debugger.remote-enabled", false,
function(value) {
devtoolsUSB = value;
Services.prefs.setBoolPref("devtools.debugger.remote-enabled",
devtoolsUSB || devtoolsWiFi);
// This preference is consulted during startup
Services.prefs.savePrefFile(null);
try {
value ? USBRemoteDebugger.start() : USBRemoteDebugger.stop();
} catch(e) {
dump("Error while initializing USB devtools: " +
e + "\n" + e.stack + "\n");
}
});
SettingsListener.observe("debugger.remote-mode", "disabled", function(value) {
if (["disabled", "adb-only", "adb-devtools"].indexOf(value) == -1) {
dump("Illegal value for debugger.remote-mode: " + value + "\n");
return;
}
devtoolsUSB = value == "adb-devtools";
Services.prefs.setBoolPref("devtools.debugger.remote-enabled",
devtoolsUSB || devtoolsWiFi);
// This preference is consulted during startup
Services.prefs.savePrefFile(null);
try {
(value == "adb-devtools") ? USBRemoteDebugger.start()
: USBRemoteDebugger.stop();
} catch(e) {
dump("Error while initializing USB devtools: " +
e + "\n" + e.stack + "\n");
}
#ifdef MOZ_WIDGET_GONK
AdbController.setRemoteDebuggerState(value != "disabled");
#endif
});
SettingsListener.observe("devtools.remote.wifi.enabled", false,
function(value) {
devtoolsWiFi = value;
Services.prefs.setBoolPref("devtools.debugger.remote-enabled",
devtoolsUSB || devtoolsWiFi);
// Allow remote debugging on non-local interfaces when WiFi debug is enabled
// TODO: Bug 1034411: Lock down to WiFi interface, instead of all interfaces
Services.prefs.setBoolPref("devtools.debugger.force-local", !value);
// This preference is consulted during startup
Services.prefs.savePrefFile(null);
try {
value ? WiFiRemoteDebugger.start() : WiFiRemoteDebugger.stop();
} catch(e) {
dump("Error while initializing WiFi devtools: " +
e + "\n" + e.stack + "\n");
}
});
})();

View File

@ -4,6 +4,8 @@
'use strict';
// settings.js loads this file when the HUD setting is enabled.
const DEVELOPER_HUD_LOG_PREFIX = 'DeveloperHUD';
XPCOMUtils.defineLazyGetter(this, 'devtools', function() {

View File

@ -4,7 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict;"
"use strict";
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -176,14 +176,14 @@ Components.utils.import('resource://gre/modules/ctypes.jsm');
}
})();
// =================== DevTools ====================
// =================== DevTools HUD ====================
let developerHUD;
SettingsListener.observe('devtools.overlay', false, (value) => {
if (value) {
if (!developerHUD) {
let scope = {};
Services.scriptloader.loadSubScript('chrome://b2g/content/devtools.js', scope);
Services.scriptloader.loadSubScript('chrome://b2g/content/devtools/hud.js', scope);
developerHUD = scope.developerHUD;
}
developerHUD.init();
@ -194,321 +194,6 @@ SettingsListener.observe('devtools.overlay', false, (value) => {
}
});
// =================== Debugger / ADB ====================
#ifdef MOZ_WIDGET_GONK
let AdbController = {
DEBUG: false,
locked: undefined,
remoteDebuggerEnabled: undefined,
lockEnabled: undefined,
disableAdbTimer: null,
disableAdbTimeoutHours: 12,
umsActive: false,
debug: function(str) {
dump("AdbController: " + str + "\n");
},
setLockscreenEnabled: function(value) {
this.lockEnabled = value;
if (this.DEBUG) {
this.debug("setLockscreenEnabled = " + this.lockEnabled);
}
this.updateState();
},
setLockscreenState: function(value) {
this.locked = value;
if (this.DEBUG) {
this.debug("setLockscreenState = " + this.locked);
}
this.updateState();
},
setRemoteDebuggerState: function(value) {
this.remoteDebuggerEnabled = value;
if (this.DEBUG) {
this.debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled);
}
this.updateState();
},
startDisableAdbTimer: function() {
if (this.disableAdbTimer) {
this.disableAdbTimer.cancel();
} else {
this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
try {
this.disableAdbTimeoutHours =
Services.prefs.getIntPref("b2g.adb.timeout-hours");
} catch (e) {
// This happens if the pref doesn't exist, in which case
// disableAdbTimeoutHours will still be set to the default.
}
}
if (this.disableAdbTimeoutHours <= 0) {
if (this.DEBUG) {
this.debug("Timer to disable ADB not started due to zero timeout");
}
return;
}
if (this.DEBUG) {
this.debug("Starting timer to disable ADB in " +
this.disableAdbTimeoutHours + " hours");
}
let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000;
this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds,
Ci.nsITimer.TYPE_ONE_SHOT);
},
stopDisableAdbTimer: function() {
if (this.DEBUG) {
this.debug("Stopping timer to disable ADB");
}
if (this.disableAdbTimer) {
this.disableAdbTimer.cancel();
this.disableAdbTimer = null;
}
},
notify: function(aTimer) {
if (aTimer == this.disableAdbTimer) {
this.disableAdbTimer = null;
// The following dump will be the last thing that shows up in logcat,
// and will at least give the user a clue about why logcat was
// disconnected, if the user happens to be using logcat.
dump("AdbController: ADB timer expired - disabling ADB\n");
navigator.mozSettings.createLock().set(
{'debugger.remote-mode': 'disabled'});
}
},
updateState: function() {
this.umsActive = false;
this.storages = navigator.getDeviceStorages('sdcard');
this.updateStorageState(0);
},
updateStorageState: function(storageIndex) {
if (storageIndex >= this.storages.length) {
// We've iterated through all of the storage objects, now we can
// really do updateStateInternal.
this.updateStateInternal();
return;
}
let storage = this.storages[storageIndex];
if (this.DEBUG) {
this.debug("Checking availability of storage: '" +
storage.storageName);
}
let req = storage.available();
req.onsuccess = function(e) {
if (this.DEBUG) {
this.debug("Storage: '" + storage.storageName + "' is '" +
e.target.result);
}
if (e.target.result == 'shared') {
// We've found a storage area that's being shared with the PC.
// We can stop looking now.
this.umsActive = true;
this.updateStateInternal();
return;
}
this.updateStorageState(storageIndex + 1);
}.bind(this);
req.onerror = function(e) {
dump("AdbController: error querying storage availability for '" +
this.storages[storageIndex].storageName + "' (ignoring)\n");
this.updateStorageState(storageIndex + 1);
}.bind(this);
},
updateStateInternal: function() {
if (this.DEBUG) {
this.debug("updateStateInternal: called");
}
if (this.remoteDebuggerEnabled === undefined ||
this.lockEnabled === undefined ||
this.locked === undefined) {
// Part of initializing the settings database will cause the observers
// to trigger. We want to wait until both have been initialized before
// we start changing ther adb state. Without this then we can wind up
// toggling adb off and back on again (or on and back off again).
//
// For completeness, one scenario which toggles adb is using the unagi.
// The unagi has adb enabled by default (prior to b2g starting). If you
// have the phone lock disabled and remote debugging enabled, then we'll
// receive an unlock event and an rde event. However at the time we
// receive the unlock event we haven't yet received the rde event, so
// we turn adb off momentarily, which disconnects a logcat that might
// be running. Changing the defaults (in AdbController) just moves the
// problem to a different phone, which has adb disabled by default and
// we wind up turning on adb for a short period when we shouldn't.
//
// By waiting until both values are properly initialized, we avoid
// turning adb on or off accidentally.
if (this.DEBUG) {
this.debug("updateState: Waiting for all vars to be initialized");
}
return;
}
// Check if we have a remote debugging session going on. If so, we won't
// disable adb even if the screen is locked.
let isDebugging = USBRemoteDebugger.isDebugging;
if (this.DEBUG) {
this.debug("isDebugging=" + isDebugging);
}
// If USB Mass Storage, USB tethering, or a debug session is active,
// then we don't want to disable adb in an automatic fashion (i.e.
// when the screen locks or due to timeout).
let sysUsbConfig = libcutils.property_get("sys.usb.config");
let rndisActive = (sysUsbConfig.split(",").indexOf("rndis") >= 0);
let usbFuncActive = rndisActive || this.umsActive || isDebugging;
let enableAdb = this.remoteDebuggerEnabled &&
(!(this.lockEnabled && this.locked) || usbFuncActive);
let useDisableAdbTimer = true;
try {
if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) {
// Marionette is enabled. Marionette requires that adb be on (and also
// requires that remote debugging be off). The fact that marionette
// is enabled also implies that we're doing a non-production build, so
// we want adb enabled all of the time.
enableAdb = true;
useDisableAdbTimer = false;
}
} catch (e) {
// This means that the pref doesn't exist. Which is fine. We just leave
// enableAdb alone.
}
if (this.DEBUG) {
this.debug("updateState: enableAdb = " + enableAdb +
" remoteDebuggerEnabled = " + this.remoteDebuggerEnabled +
" lockEnabled = " + this.lockEnabled +
" locked = " + this.locked +
" usbFuncActive = " + usbFuncActive);
}
// Configure adb.
let currentConfig = libcutils.property_get("persist.sys.usb.config");
let configFuncs = currentConfig.split(",");
let adbIndex = configFuncs.indexOf("adb");
if (enableAdb) {
// Add adb to the list of functions, if not already present
if (adbIndex < 0) {
configFuncs.push("adb");
}
} else {
// Remove adb from the list of functions, if present
if (adbIndex >= 0) {
configFuncs.splice(adbIndex, 1);
}
}
let newConfig = configFuncs.join(",");
if (newConfig != currentConfig) {
if (this.DEBUG) {
this.debug("updateState: currentConfig = " + currentConfig);
this.debug("updateState: newConfig = " + newConfig);
}
try {
libcutils.property_set("persist.sys.usb.config", newConfig);
} catch(e) {
dump("Error configuring adb: " + e);
}
}
if (useDisableAdbTimer) {
if (enableAdb && !usbFuncActive) {
this.startDisableAdbTimer();
} else {
this.stopDisableAdbTimer();
}
}
}
};
SettingsListener.observe("lockscreen.locked", false,
AdbController.setLockscreenState.bind(AdbController));
SettingsListener.observe("lockscreen.enabled", false,
AdbController.setLockscreenEnabled.bind(AdbController));
#endif
(function() {
// Track these separately here so we can determine the correct value for the
// pref "devtools.debugger.remote-enabled", which is true when either mode of
// using DevTools is enabled.
let devtoolsUSB = false;
let devtoolsWiFi = false;
// Keep the old setting to not break people that won't have updated
// gaia and gecko.
SettingsListener.observe('devtools.debugger.remote-enabled', false,
function(value) {
devtoolsUSB = value;
Services.prefs.setBoolPref('devtools.debugger.remote-enabled',
devtoolsUSB || devtoolsWiFi);
// This preference is consulted during startup
Services.prefs.savePrefFile(null);
try {
value ? USBRemoteDebugger.start() : USBRemoteDebugger.stop();
} catch(e) {
dump("Error while initializing USB devtools: "
+ e + "\n" + e.stack + "\n");
}
});
SettingsListener.observe('debugger.remote-mode', 'disabled', function(value) {
if (['disabled', 'adb-only', 'adb-devtools'].indexOf(value) == -1) {
dump('Illegal value for debugger.remote-mode: ' + value + '\n');
return;
}
devtoolsUSB = value == 'adb-devtools';
Services.prefs.setBoolPref('devtools.debugger.remote-enabled',
devtoolsUSB || devtoolsWiFi);
// This preference is consulted during startup
Services.prefs.savePrefFile(null);
try {
(value == 'adb-devtools') ? USBRemoteDebugger.start()
: USBRemoteDebugger.stop();
} catch(e) {
dump("Error while initializing USB devtools: "
+ e + "\n" + e.stack + "\n");
}
#ifdef MOZ_WIDGET_GONK
AdbController.setRemoteDebuggerState(value != 'disabled');
#endif
});
SettingsListener.observe('devtools.remote.wifi.enabled', false,
function(value) {
devtoolsWiFi = value;
Services.prefs.setBoolPref('devtools.debugger.remote-enabled',
devtoolsUSB || devtoolsWiFi);
// Allow remote debugging on non-local interfaces when WiFi debug is enabled
// TODO: Bug 1034411: Lock down to WiFi interface, instead of all interfaces
Services.prefs.setBoolPref('devtools.debugger.force-local', !value);
// This preference is consulted during startup
Services.prefs.savePrefFile(null);
try {
value ? WiFiRemoteDebugger.start() : WiFiRemoteDebugger.stop();
} catch(e) {
dump("Error while initializing WiFi devtools: "
+ e + "\n" + e.stack + "\n");
}
});
})();
// =================== Device Storage ====================
SettingsListener.observe('device.storage.writable.name', 'sdcard', function(value) {
if (Services.prefs.getPrefType('device.storage.writable.name') != Ci.nsIPrefBranch.PREF_STRING) {

View File

@ -32,7 +32,14 @@
<!-- this script handles the "runapp" argument for desktop builds -->
<script type="application/javascript;version=1.8"
src="chrome://b2g/content/runapp.js"> </script>
#else
<!-- this file is only loaded on Gonk to manage ADB state -->
<script type="application/javascript;version=1.8"
src="chrome://b2g/content/devtools/adb.js"> </script>
#endif
<!-- manages DevTools server state -->
<script type="application/javascript;version=1.8"
src="chrome://b2g/content/devtools/debugger.js"> </script>
</head>
<body id="container">
#ifdef FXOS_SIMULATOR

View File

@ -51,21 +51,6 @@ XPCOMUtils.defineLazyServiceGetter(Services, 'fm',
'@mozilla.org/focus-manager;1',
'nsIFocusManager');
XPCOMUtils.defineLazyGetter(this, 'DebuggerServer', function() {
Cu.import('resource://gre/modules/devtools/dbg-server.jsm');
return DebuggerServer;
});
XPCOMUtils.defineLazyGetter(this, 'devtools', function() {
const { devtools } =
Cu.import('resource://gre/modules/devtools/Loader.jsm', {});
return devtools;
});
XPCOMUtils.defineLazyGetter(this, 'discovery', function() {
return devtools.require('devtools/toolkit/discovery/discovery');
});
XPCOMUtils.defineLazyGetter(this, "ppmm", function() {
return Cc["@mozilla.org/parentprocessmessagemanager;1"]
.getService(Ci.nsIMessageListenerManager);
@ -730,9 +715,6 @@ var CustomEventManager = {
case 'system-message-listener-ready':
Services.obs.notifyObservers(null, 'system-message-listener-ready', null);
break;
case 'remote-debugger-prompt':
RemoteDebugger.handleEvent(detail);
break;
case 'captive-portal-login-cancel':
CaptivePortalLoginHelper.handleEvent(detail);
break;
@ -860,172 +842,6 @@ let IndexedDBPromptHelper = {
}
}
let RemoteDebugger = {
_promptDone: false,
_promptAnswer: false,
prompt: function debugger_prompt() {
this._promptDone = false;
shell.sendChromeEvent({
"type": "remote-debugger-prompt"
});
while(!this._promptDone) {
Services.tm.currentThread.processNextEvent(true);
}
return this._promptAnswer;
},
handleEvent: function debugger_handleEvent(detail) {
this._promptAnswer = detail.value;
this._promptDone = true;
},
initServer: function() {
if (DebuggerServer.initialized) {
return;
}
// Ask for remote connections.
DebuggerServer.init(this.prompt.bind(this));
// /!\ Be careful when adding a new actor, especially global actors.
// Any new global actor will be exposed and returned by the root actor.
// Add Firefox-specific actors, but prevent tab actors to be loaded in
// the parent process, unless we enable certified apps debugging.
let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps");
DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges);
/**
* Construct a root actor appropriate for use in a server running in B2G.
* The returned root actor respects the factories registered with
* DebuggerServer.addGlobalActor only if certified apps debugging is on,
* otherwise we used an explicit limited list of global actors
*
* * @param connection DebuggerServerConnection
* The conection to the client.
*/
DebuggerServer.createRootActor = function createRootActor(connection)
{
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
let parameters = {
// We do not expose browser tab actors yet,
// but we still have to define tabList.getList(),
// otherwise, client won't be able to fetch global actors
// from listTabs request!
tabList: {
getList: function() {
return promise.resolve([]);
}
},
// Use an explicit global actor list to prevent exposing
// unexpected actors
globalActorFactories: restrictPrivileges ? {
webappsActor: DebuggerServer.globalActorFactories.webappsActor,
deviceActor: DebuggerServer.globalActorFactories.deviceActor,
} : DebuggerServer.globalActorFactories
};
let { RootActor } = devtools.require("devtools/server/actors/root");
let root = new RootActor(connection, parameters);
root.applicationType = "operating-system";
return root;
};
#ifdef MOZ_WIDGET_GONK
DebuggerServer.on("connectionchange", function() {
AdbController.updateState();
});
#endif
}
};
let USBRemoteDebugger = {
get isDebugging() {
if (!this._listener) {
return false;
}
return DebuggerServer._connections &&
Object.keys(DebuggerServer._connections).length > 0;
},
start: function() {
if (this._listener) {
return;
}
RemoteDebugger.initServer();
let portOrPath =
Services.prefs.getCharPref("devtools.debugger.unix-domain-socket") ||
"/data/local/debugger-socket";
try {
debug("Starting USB debugger on " + portOrPath);
this._listener = DebuggerServer.openListener(portOrPath);
// Temporary event, until bug 942756 lands and offers a way to know
// when the server is up and running.
Services.obs.notifyObservers(null, 'debugger-server-started', null);
} catch (e) {
debug('Unable to start USB debugger server: ' + e);
}
},
stop: function() {
if (!this._listener) {
return;
}
try {
this._listener.close();
this._listener = null;
} catch (e) {
debug('Unable to stop USB debugger server: ' + e);
}
}
};
let WiFiRemoteDebugger = {
start: function() {
if (this._listener) {
return;
}
RemoteDebugger.initServer();
try {
debug("Starting WiFi debugger");
this._listener = DebuggerServer.openListener(-1);
let port = this._listener.port;
debug("Started WiFi debugger on " + port);
discovery.addService("devtools", { port: port });
} catch (e) {
debug('Unable to start WiFi debugger server: ' + e);
}
},
stop: function() {
if (!this._listener) {
return;
}
try {
discovery.removeService("devtools");
this._listener.close();
this._listener = null;
} catch (e) {
debug('Unable to stop WiFi debugger server: ' + e);
}
}
};
let KeyboardHelper = {
handleEvent: function keyboard_handleEvent(detail) {
Keyboard.setLayouts(detail.layouts);

View File

@ -13,7 +13,11 @@ chrome.jar:
* content/shell.html (content/shell.html)
* content/shell.js (content/shell.js)
content/shell.css (content/shell.css)
content/devtools.js (content/devtools.js)
#ifdef MOZ_WIDGET_GONK
content/devtools/adb.js (content/devtools/adb.js)
#endif
* content/devtools/debugger.js (content/devtools/debugger.js)
content/devtools/hud.js (content/devtools/hud.js)
#ifdef FXOS_SIMULATOR
content/desktop.css (content/desktop.css)
content/images/desktop/home-black.png (content/images/desktop/home-black.png)

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -12,12 +12,12 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3aa6abd313f965a84aa86c6b213dc154e4875139">
<project name="platform_build" path="build" remote="b2g" revision="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>

View File

@ -12,10 +12,10 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="7945ca73e687be5edbc7b928dc7fe3a208242144">
<project name="platform_build" path="build" remote="b2g" revision="1865c6639c51f0290d5778adef146147d5d6a5f0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -12,12 +12,12 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3aa6abd313f965a84aa86c6b213dc154e4875139">
<project name="platform_build" path="build" remote="b2g" revision="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "16e1bcb1ef744dbffbc9330ac395fa275d178fd0",
"revision": "ffbb39b4a20479d949ef88c688bf0534677d845a",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -12,12 +12,12 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="3aa6abd313f965a84aa86c6b213dc154e4875139">
<project name="platform_build" path="build" remote="b2g" revision="7eef86294cd794ab9e6a53d218c238bfc63c3a6d">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="dbc46f0bc269791c52becbef22f84c63469ee8be"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="00aa329503d73435c9821d4a50c2797a0374eac6"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="acead54e798dcc436433fc359dda3a1409c5a44a"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -422,6 +422,7 @@ Convert(bt_device_type_t aIn, BluetoothDeviceType& aOut)
return NS_OK;
}
#if ANDROID_VERSION >= 18
static nsresult
Convert(const bt_remote_version_t& aIn, BluetoothRemoteInfo& aOut)
{
@ -431,6 +432,7 @@ Convert(const bt_remote_version_t& aIn, BluetoothRemoteInfo& aOut)
return NS_OK;
}
#endif
static nsresult
Convert(const bt_service_record_t& aIn, BluetoothServiceRecord& aOut)
@ -840,10 +842,12 @@ Convert(const bt_property_t& aIn, BluetoothProperty& aOut)
case PROPERTY_REMOTE_RSSI:
aOut.mInt32 = *static_cast<int32_t*>(aIn.val);
break;
#if ANDROID_VERSION >= 18
case PROPERTY_REMOTE_VERSION_INFO:
rv = Convert(*static_cast<bt_remote_version_t*>(aIn.val),
aOut.mRemoteInfo);
break;
#endif
case PROPERTY_REMOTE_DEVICE_TIMESTAMP:
/* nothing to do */
break;
@ -3036,18 +3040,20 @@ BluetoothInterface::Init(BluetoothNotificationHandler* aNotificationHandler,
{
static bt_callbacks_t sBluetoothCallbacks = {
sizeof(sBluetoothCallbacks),
.adapter_state_changed_cb = BluetoothCallback::AdapterStateChanged,
.adapter_properties_cb = BluetoothCallback::AdapterProperties,
.remote_device_properties_cb = BluetoothCallback::RemoteDeviceProperties,
.device_found_cb = BluetoothCallback::DeviceFound,
.discovery_state_changed_cb= BluetoothCallback::DiscoveryStateChanged,
.pin_request_cb = BluetoothCallback::PinRequest,
.ssp_request_cb = BluetoothCallback::SspRequest,
.bond_state_changed_cb = BluetoothCallback::BondStateChanged,
.acl_state_changed_cb = BluetoothCallback::AclStateChanged,
.thread_evt_cb = BluetoothCallback::ThreadEvt,
.dut_mode_recv_cb = BluetoothCallback::DutModeRecv,
.le_test_mode_cb = BluetoothCallback::LeTestMode
BluetoothCallback::AdapterStateChanged,
BluetoothCallback::AdapterProperties,
BluetoothCallback::RemoteDeviceProperties,
BluetoothCallback::DeviceFound,
BluetoothCallback::DiscoveryStateChanged,
BluetoothCallback::PinRequest,
BluetoothCallback::SspRequest,
BluetoothCallback::BondStateChanged,
BluetoothCallback::AclStateChanged,
BluetoothCallback::ThreadEvt,
BluetoothCallback::DutModeRecv,
#if ANDROID_VERSION >= 18
BluetoothCallback::LeTestMode
#endif
};
sNotificationHandler = aNotificationHandler;

View File

@ -59,13 +59,13 @@ const ICC_MAX_LINEAR_FIXED_RECORDS = 0xfe;
// MMI match groups
const MMI_MATCH_GROUP_FULL_MMI = 1;
const MMI_MATCH_GROUP_MMI_PROCEDURE = 2;
const MMI_MATCH_GROUP_PROCEDURE = 2;
const MMI_MATCH_GROUP_SERVICE_CODE = 3;
const MMI_MATCH_GROUP_SIA = 5;
const MMI_MATCH_GROUP_SIB = 7;
const MMI_MATCH_GROUP_SIC = 9;
const MMI_MATCH_GROUP_PWD_CONFIRM = 11;
const MMI_MATCH_GROUP_DIALING_NUMBER = 12;
const MMI_MATCH_GROUP_SIA = 4;
const MMI_MATCH_GROUP_SIB = 5;
const MMI_MATCH_GROUP_SIC = 6;
const MMI_MATCH_GROUP_PWD_CONFIRM = 7;
const MMI_MATCH_GROUP_DIALING_NUMBER = 8;
const MMI_MAX_LENGTH_SHORT_CODE = 2;
@ -1679,20 +1679,6 @@ RilObject.prototype = {
this.exitEmergencyCbMode();
}
if (!this._isCdma) {
// TODO: Both dial() and sendMMI() functions should be unified at some
// point in the future. In the mean time we handle temporary CLIR MMI
// commands through the dial() function. Please see bug 889737.
let mmi = this._parseMMI(options.number);
if (mmi && this._isTemporaryModeCLIR(mmi)) {
options.number = mmi.dialNumber;
// In temporary mode, MMI_PROCEDURE_ACTIVATION means allowing CLI
// presentation, i.e. CLIR_SUPPRESSION. See TS 22.030, Annex B.
options.clirMode = mmi.procedure == MMI_PROCEDURE_ACTIVATION ?
CLIR_SUPPRESSION : CLIR_INVOCATION;
}
}
options.request = REQUEST_DIAL;
this.sendDialRequest(options);
},
@ -1907,7 +1893,7 @@ RilObject.prototype = {
} else if (call.state == CALL_STATE_ACTIVE) {
this.sendSwitchWaitingRequest();
}
},
},
resumeCall: function(options) {
let call = this.currentCalls[options.callIndex];
@ -2390,6 +2376,20 @@ RilObject.prototype = {
{callback: callback});
},
/**
* Parse the dial number to extract its mmi code part.
*
* @param number
* Phone number to be parsed
*/
parseMMIFromDialNumber: function(options) {
// We don't have to parse mmi in cdma.
if (!this._isCdma) {
options.mmi = this._parseMMI(options.number);
}
this.sendChromeMessage(options);
},
/**
* Helper to parse MMI/USSD string. TS.22.030 Figure 3.5.3.2.
*/
@ -2398,21 +2398,11 @@ RilObject.prototype = {
return null;
}
let matches = this._matchMMIRegexp(mmiString);
let matches = this._getMMIRegExp().exec(mmiString);
if (matches) {
// After successfully executing the regular expresion over the MMI string,
// the following match groups should contain:
// 1 = full MMI string that might be used as a USSD request.
// 2 = MMI procedure.
// 3 = Service code.
// 5 = SIA.
// 7 = SIB.
// 9 = SIC.
// 11 = Password registration.
// 12 = Dialing number.
return {
fullMMI: matches[MMI_MATCH_GROUP_FULL_MMI],
procedure: matches[MMI_MATCH_GROUP_MMI_PROCEDURE],
procedure: matches[MMI_MATCH_GROUP_PROCEDURE],
serviceCode: matches[MMI_MATCH_GROUP_SERVICE_CODE],
sia: matches[MMI_MATCH_GROUP_SIA],
sib: matches[MMI_MATCH_GROUP_SIB],
@ -2422,8 +2412,7 @@ RilObject.prototype = {
};
}
if (this._isPoundString(mmiString) ||
this._isMMIShortString(mmiString)) {
if (this._isPoundString(mmiString) || this._isMMIShortString(mmiString)) {
return {
fullMMI: mmiString
};
@ -2433,56 +2422,80 @@ RilObject.prototype = {
},
/**
* Helper to parse MMI string via regular expression. TS.22.030 Figure
* 3.5.3.2.
* Build the regex to parse MMI string.
*
* The resulting groups after matching will be:
* 1 = full MMI string that might be used as a USSD request.
* 2 = MMI procedure.
* 3 = Service code.
* 4 = SIA.
* 5 = SIB.
* 6 = SIC.
* 7 = Password registration.
* 8 = Dialing number.
*
* @see TS.22.030 Figure 3.5.3.2.
*/
_matchMMIRegexp: function(mmiString) {
// Regexp to parse and process the MMI code.
if (this._mmiRegExp == null) {
// The first group of the regexp takes the whole MMI string.
// The second group takes the MMI procedure that can be:
// - Activation (*SC*SI#).
// - Deactivation (#SC*SI#).
// - Interrogation (*#SC*SI#).
// - Registration (**SC*SI#).
// - Erasure (##SC*SI#).
// where SC = Service Code (2 or 3 digits) and SI = Supplementary Info
// (variable length).
let pattern = "((\\*[*#]?|##?)";
_buildMMIRegExp: function() {
// The general structure of the codes is as follows:
// - Activation (*SC*SI#).
// - Deactivation (#SC*SI#).
// - Interrogation (*#SC*SI#).
// - Registration (**SC*SI#).
// - Erasure (##SC*SI#).
//
// where SC = Service Code (2 or 3 digits) and SI = Supplementary Info
// (variable length).
// Third group of the regexp looks for the MMI Service code, which is a
// 2 or 3 digits that uniquely specifies the Supplementary Service
// associated with the MMI code.
pattern += "(\\d{2,3})";
// MMI procedure, which could be *, #, *#, **, ##
let procedure = "(\\*[*#]?|##?)";
// Groups from 4 to 9 looks for the MMI Supplementary Information SIA,
// SIB and SIC. SIA may comprise e.g. a PIN code or Directory Number,
// SIB may be used to specify the tele or bearer service and SIC to
// specify the value of the "No Reply Condition Timer". Where a particular
// service request does not require any SI, "*SI" is not entered. The use
// of SIA, SIB and SIC is optional and shall be entered in any of the
// following formats:
// - *SIA*SIB*SIC#
// - *SIA*SIB#
// - *SIA**SIC#
// - *SIA#
// - **SIB*SIC#
// - ***SISC#
pattern += "(\\*([^*#]*)(\\*([^*#]*)(\\*([^*#]*)";
// MMI Service code, which is a 2 or 3 digits that uniquely specifies the
// Supplementary Service associated with the MMI code.
let serviceCode = "(\\d{2,3})";
// The eleventh group takes the password for the case of a password
// registration procedure.
pattern += "(\\*([^*#]*))?)?)?)?#)";
// The last group takes the dial string after the #.
pattern += "([^#]*)";
this._mmiRegExp = new RegExp(pattern);
// MMI Supplementary Information SIA, SIB and SIC. SIA may comprise e.g. a
// PIN code or Directory Number, SIB may be used to specify the tele or
// bearer service and SIC to specify the value of the "No Reply Condition
// Timer". Where a particular service request does not require any SI,
// "*SI" is not entered. The use of SIA, SIB and SIC is optional and shall
// be entered in any of the following formats:
// - *SIA*SIB*SIC#
// - *SIA*SIB#
// - *SIA**SIC#
// - *SIA#
// - **SIB*SIC#
// - ***SIC#
//
// Also catch the additional NEW_PASSWORD for the case of a password
// registration procedure. Ex:
// - * 03 * ZZ * OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
// - ** 03 * ZZ * OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
// - * 03 ** OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
// - ** 03 ** OLD_PASSWORD * NEW_PASSWORD * NEW_PASSWORD #
let si = "\\*([^*#]*)";
let allSi = "";
for (let i = 0; i < 4; ++i) {
allSi = "(?:" + si + allSi + ")?";
}
// Regex only applys for those well-defined MMI strings (refer to TS.22.030
// Annex B), otherwise, null should be the expected return value.
return this._mmiRegExp.exec(mmiString);
let fullmmi = "(" + procedure + serviceCode + allSi + "#)";
// dial string after the #.
let dialString = "([^#]*)";
return new RegExp(fullmmi + dialString);
},
/**
* Provide the regex to parse MMI string.
*/
_getMMIRegExp: function() {
if (!this._mmiRegExp) {
this._mmiRegExp = this._buildMMIRegExp();
}
return this._mmiRegExp;
},
/**
@ -2508,11 +2521,12 @@ RilObject.prototype = {
return true;
}
if ((mmiString.length != 2) || (mmiString.charAt(0) !== '1')) {
return true;
// Input string is 2 digits starting with a "1"
if ((mmiString.length == 2) && (mmiString.charAt(0) === '1')) {
return false;
}
return false;
return true;
},
sendMMI: function(options) {
@ -3390,20 +3404,6 @@ RilObject.prototype = {
Buf.sendParcel();
},
/**
* Checks whether to temporarily suppress caller id for the call.
*
* @param mmi
* MMI full object.
*/
_isTemporaryModeCLIR: function(mmi) {
return (mmi &&
mmi.serviceCode == MMI_SC_CLIR &&
mmi.dialNumber &&
(mmi.procedure == MMI_PROCEDURE_ACTIVATION ||
mmi.procedure == MMI_PROCEDURE_DEACTIVATION));
},
/**
* Report STK Service is running.
*/

View File

@ -64,8 +64,7 @@ class Telephony::Callback : public nsITelephonyCallback
public:
NS_DECL_ISUPPORTS
Callback(Telephony* aTelephony, Promise* aPromise, uint32_t aServiceId,
const nsAString& aNumber)
Callback(Telephony* aTelephony, Promise* aPromise, uint32_t aServiceId)
: mTelephony(aTelephony), mPromise(aPromise), mServiceId(aServiceId)
{
MOZ_ASSERT(mTelephony);
@ -264,7 +263,7 @@ Telephony::DialInternal(uint32_t aServiceId, const nsAString& aNumber,
}
nsCOMPtr<nsITelephonyCallback> callback =
new Callback(this, promise, aServiceId, aNumber);
new Callback(this, promise, aServiceId);
nsresult rv = mService->Dial(aServiceId, aNumber, aEmergency, callback);
if (NS_FAILED(rv)) {
promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);

View File

@ -178,6 +178,10 @@ TelephonyService.prototype = {
return gRadioInterfaceLayer.getRadioInterface(aClientId);
},
_sendToRilWorker: function(aClientId, aType, aMessage, aCallback) {
this._getClient(aClientId).sendWorkerMessage(aType, aMessage, aCallback);
},
// An array of nsITelephonyListener instances.
_listeners: null,
_notifyAllListeners: function(aMethodName, aArgs) {
@ -318,8 +322,7 @@ TelephonyService.prototype = {
_enumerateCallsForClient: function(aClientId) {
if (DEBUG) debug("Enumeration of calls for client " + aClientId);
this._getClient(aClientId).sendWorkerMessage("enumerateCalls", null,
(function(response) {
this._sendToRilWorker(aClientId, "enumerateCalls", null, response => {
if (!this._currentCalls[aClientId]) {
this._currentCalls[aClientId] = {};
}
@ -331,9 +334,7 @@ TelephonyService.prototype = {
this._currentCalls[aClientId][call.callIndex] = call;
}
return false;
}).bind(this));
});
},
/**
@ -356,6 +357,35 @@ TelephonyService.prototype = {
return numbers.indexOf(aNumber) != -1;
},
/**
* Checks whether to temporarily suppress caller id for the call.
*
* @param aMmi
* MMI full object.
*/
_isTemporaryCLIR: function(aMmi) {
return (aMmi && aMmi.serviceCode === RIL.MMI_SC_CLIR) && aMmi.dialNumber;
},
/**
* Map MMI procedure to CLIR MODE.
*
* @param aProcedure
* MMI procedure
*/
_getTemporaryCLIRMode: function(aProcedure) {
// In temporary mode, MMI_PROCEDURE_ACTIVATION means allowing CLI
// presentation, i.e. CLIR_SUPPRESSION. See TS 22.030, Annex B.
switch (aProcedure) {
case RIL.MMI_PROCEDURE_ACTIVATION:
return RIL.CLIR_SUPPRESSION;
case RIL.MMI_PROCEDURE_DEACTIVATION:
return RIL.CLIR_INVOCATION;
default:
return RIL.CLIR_DEFAULT;
}
},
/**
* nsITelephonyService interface.
*/
@ -456,7 +486,31 @@ TelephonyService.prototype = {
this.notifyCallStateChanged(aClientId, parentCall);
},
_composeDialRequest: function(aClientId, aNumber) {
return new Promise((resolve, reject) => {
this._sendToRilWorker(aClientId, "parseMMIFromDialNumber",
{number: aNumber}, response => {
let options = {};
let mmi = response.mmi;
if (!mmi) {
resolve({
number: aNumber
});
} else if (this._isTemporaryCLIR(mmi)) {
resolve({
number: mmi.dialNumber,
clirMode: this._getTemporaryCLIRMode(mmi.procedure)
});
} else {
reject(DIAL_ERROR_BAD_NUMBER);
}
});
});
},
isDialing: false,
dial: function(aClientId, aNumber, aIsDialEmergency, aCallback) {
if (DEBUG) debug("Dialing " + (aIsDialEmergency ? "emergency " : "") + aNumber);
@ -495,49 +549,48 @@ TelephonyService.prototype = {
return;
}
let isEmergencyNumber = this._isEmergencyNumber(aNumber);
this._composeDialRequest(aClientId, aNumber).then(options => {
options.isEmergency = this._isEmergencyNumber(options.number);
options.isDialEmergency = aIsDialEmergency;
if (isEmergencyNumber) {
// Automatically select a proper clientId for emergency call.
aClientId = gRadioInterfaceLayer.getClientIdForEmergencyCall() ;
if (aClientId === -1) {
if (DEBUG) debug("Error: No client is avaialble for emergency call.");
aCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
return;
}
}
this.isDialing = true;
let options = {
isDialEmergency: aIsDialEmergency,
isEmergency: isEmergencyNumber,
number: aNumber
};
this._getClient(aClientId).sendWorkerMessage("dial", options,
(function(response) {
this.isDialing = false;
if (!response.success) {
aCallback.notifyDialError(response.errorMsg);
return false;
}
if (!response.isCdma) {
aCallback.notifyDialSuccess(response.callIndex, response.number);
} else {
let currentCallId = Object.keys(this._currentCalls[aClientId])[0];
if (currentCallId === undefined) {
aCallback.notifyDialSuccess(response.callIndex, response.number);
} else {
// RIL doesn't hold the 2nd call. We create one by ourselves.
aCallback.notifyDialSuccess(CDMA_SECOND_CALL_INDEX, response.number);
this._addCdmaChildCall(aClientId, aNumber, currentCallId);
if (options.isEmergency) {
// Automatically select a proper clientId for emergency call.
aClientId = gRadioInterfaceLayer.getClientIdForEmergencyCall() ;
if (aClientId === -1) {
if (DEBUG) debug("Error: No client is avaialble for emergency call.");
aCallback.notifyDialError(DIAL_ERROR_INVALID_STATE_ERROR);
return;
}
}
return false;
}).bind(this));
this._dialInternal(aClientId, options, aCallback);
}, cause => {
aCallback.notifyDialError(DIAL_ERROR_BAD_NUMBER);
});
},
_dialInternal: function(aClientId, aOptions, aCallback) {
this.isDialing = true;
this._sendToRilWorker(aClientId, "dial", aOptions, response => {
this.isDialing = false;
if (!response.success) {
aCallback.notifyDialError(response.errorMsg);
return;
}
let currentCdmaCallIndex = !response.isCdma ? null :
Object.keys(this._currentCalls[aClientId])[0];
if (currentCdmaCallIndex == null) {
aCallback.notifyDialSuccess(response.callIndex, response.number);
} else {
// RIL doesn't hold the 2nd call. We create one by ourselves.
aCallback.notifyDialSuccess(CDMA_SECOND_CALL_INDEX, response.number);
this._addCdmaChildCall(aClientId, aNumber, currentCdmaCallIndex);
}
});
},
hangUp: function(aClientId, aCallIndex) {
@ -547,24 +600,24 @@ TelephonyService.prototype = {
// the parent call, we send 'parentId' to RIL.
this.hangUp(aClientId, parentId);
} else {
this._getClient(aClientId).sendWorkerMessage("hangUp", { callIndex: aCallIndex });
this._sendToRilWorker(aClientId, "hangUp", { callIndex: aCallIndex });
}
},
startTone: function(aClientId, aDtmfChar) {
this._getClient(aClientId).sendWorkerMessage("startTone", { dtmfChar: aDtmfChar });
this._sendToRilWorker(aClientId, "startTone", { dtmfChar: aDtmfChar });
},
stopTone: function(aClientId) {
this._getClient(aClientId).sendWorkerMessage("stopTone");
this._sendToRilWorker(aClientId, "stopTone");
},
answerCall: function(aClientId, aCallIndex) {
this._getClient(aClientId).sendWorkerMessage("answerCall", { callIndex: aCallIndex });
this._sendToRilWorker(aClientId, "answerCall", { callIndex: aCallIndex });
},
rejectCall: function(aClientId, aCallIndex) {
this._getClient(aClientId).sendWorkerMessage("rejectCall", { callIndex: aCallIndex });
this._sendToRilWorker(aClientId, "rejectCall", { callIndex: aCallIndex });
},
holdCall: function(aClientId, aCallIndex) {
@ -575,7 +628,7 @@ TelephonyService.prototype = {
return;
}
this._getClient(aClientId).sendWorkerMessage("holdCall", { callIndex: aCallIndex });
this._sendToRilWorker(aClientId, "holdCall", { callIndex: aCallIndex });
},
resumeCall: function(aClientId, aCallIndex) {
@ -586,7 +639,7 @@ TelephonyService.prototype = {
return;
}
this._getClient(aClientId).sendWorkerMessage("resumeCall", { callIndex: aCallIndex });
this._sendToRilWorker(aClientId, "resumeCall", { callIndex: aCallIndex });
},
conferenceCall: function(aClientId) {
@ -619,19 +672,17 @@ TelephonyService.prototype = {
this.notifyConferenceCallStateChanged(RIL.CALL_STATE_ACTIVE);
}
this._getClient(aClientId).sendWorkerMessage("conferenceCall", null,
(function(response) {
this._sendToRilWorker(aClientId, "conferenceCall", null, response => {
if (!response.success) {
this._notifyAllListeners("notifyConferenceError", [response.errorName,
response.errorMsg]);
return false;
return;
}
if (response.isCdma) {
onCdmaConferenceCallSuccess.call(this);
}
return false;
}).bind(this));
});
},
separateCall: function(aClientId, aCallIndex) {
@ -664,28 +715,26 @@ TelephonyService.prototype = {
this.notifyCallDisconnected(aClientId, childCall);
}
this._getClient(aClientId).sendWorkerMessage("separateCall", {
callIndex: aCallIndex
}, (function(response) {
this._sendToRilWorker(aClientId, "separateCall", { callIndex: aCallIndex },
response => {
if (!response.success) {
this._notifyAllListeners("notifyConferenceError", [response.errorName,
response.errorMsg]);
return false;
return;
}
if (response.isCdma) {
onCdmaSeparateCallSuccess.call(this);
}
return false;
}).bind(this));
});
},
holdConference: function(aClientId) {
this._getClient(aClientId).sendWorkerMessage("holdConference");
this._sendToRilWorker(aClientId, "holdConference");
},
resumeConference: function(aClientId) {
this._getClient(aClientId).sendWorkerMessage("resumeConference");
this._sendToRilWorker(aClientId, "resumeConference");
},
get microphoneMuted() {

View File

@ -63,3 +63,4 @@ disabled = Bug 821958
[test_incomingcall_phonestate_speaker.js]
[test_temporary_clir.js]
[test_outgoing_error_state.js]
[test_mmi_code.js]

View File

@ -0,0 +1,23 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
let number = "";
function dialMMI() {
telephony.dial("*#06#").then(null, cause => {
log("Received promise 'reject'");
is(telephony.active, null);
is(telephony.calls.length, 0);
is(cause, "BadNumberError");
finish();
});
}
startTest(function() {
dialMMI();
});

View File

@ -169,6 +169,13 @@ void LossyConvertUTF8toUTF16(const char* aInput, uint32_t aLength, nsAString& aO
uint32_t j = 0;
for (uint32_t i = 0; i < srclen; i++, j++) {
uint32_t v = uint32_t(src[i]);
if (v == uint32_t('\0') && i < srclen - 1) {
// If the leading byte is '\0' and it's not the last byte,
// just ignore it to prevent from being truncated. This could
// be caused by |convertToBytes| (e.g. \x00 would be converted to '\0')
j--;
continue;
}
if (!(v & 0x80)) {
// ASCII code unit. Simple copy.
dst[j] = char16_t(v);

View File

@ -2898,24 +2898,28 @@ WifiWorker.prototype = {
// No change.
if (enabled === WifiManager.enabled) {
this._sendMessage(message, true, true, msg);
return;
}
// Can't enable wifi while hotspot mode is enabled.
if (enabled && (this.tetheringSettings[SETTINGS_WIFI_TETHERING_ENABLED] ||
WifiManager.isWifiTetheringEnabled(WifiManager.tetheringState))) {
self._sendMessage(message, false, "Can't enable Wifi while hotspot mode is enabled", msg);
}
// Reply error to pending requests.
if (!enabled) {
this._clearPendingRequest();
return;
}
WifiManager.setWifiEnabled(enabled, function(ok) {
if (ok === 0 || ok === "no change") {
self._sendMessage(message, true, true, msg);
// Reply error to pending requests.
if (!enabled) {
self._clearPendingRequest();
} else {
WifiManager.start();
}
} else {
self._sendMessage(message, false, "Set power saving mode failed", msg);
self._sendMessage(message, false, "Set wifi enabled failed", msg);
}
});
},

View File

@ -258,29 +258,39 @@ let gTestSuite = (function() {
*
* @return a resolved promise or deferred promise.
*/
function ensureWifiEnabled(aEnabled) {
function ensureWifiEnabled(aEnabled, useAPI) {
if (wifiManager.enabled === aEnabled) {
log('Already ' + (aEnabled ? 'enabled' : 'disabled'));
return Promise.resolve();
}
return requestWifiEnabled(aEnabled);
return requestWifiEnabled(aEnabled, useAPI);
}
/**
* Issue a request to enable/disable wifi.
*
* For current design, this function will attempt to enable/disable wifi by
* writing 'wifi.enabled' regardless of the wifi state.
* This function will attempt to enable/disable wifi, by calling API or by
* writing settings 'wifi.enabled' regardless of the wifi state, based on the
* value of |userAPI| parameter.
* Default is using settings.
*
* Note there's a limitation of co-existance of both method, per bug 930355,
* that once enable/disable wifi by API, the settings method won't work until
* reboot. So the test of wifi enable API should be executed last.
* TODO: Remove settings method after enable/disable wifi by settings is
* removed after bug 1050147.
*
* Fulfill params: (none)
* Reject params: (none)
*
* @return A deferred promise.
*/
function requestWifiEnabled(aEnabled) {
function requestWifiEnabled(aEnabled, useAPI) {
return Promise.all([
waitForWifiManagerEventOnce(aEnabled ? 'enabled' : 'disabled'),
setSettings({ 'wifi.enabled': aEnabled }),
useAPI ?
wrapDomRequestAsPromise(wifiManager.setWifiEnabled(aEnabled)) :
setSettings({ 'wifi.enabled': aEnabled }),
]);
}

View File

@ -11,3 +11,4 @@ qemu = true
[test_wifi_tethering_wifi_disabled.js]
[test_wifi_tethering_wifi_inactive.js]
[test_wifi_tethering_wifi_active.js]
[test_wifi_enable_api.js]

View File

@ -0,0 +1,13 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
gTestSuite.doTest(function() {
return Promise.resolve()
.then(() => gTestSuite.ensureWifiEnabled(false, true))
.then(() => gTestSuite.requestWifiEnabled(true, true))
.then(() => gTestSuite.requestWifiEnabled(false, true))
.then(() => gTestSuite.ensureWifiEnabled(true, true));
});

View File

@ -148,8 +148,10 @@ var tests = [
if (navigator.appVersion.indexOf("Android") == -1 &&
SpecialPowers.Services.appinfo.name != "B2G") {
tests.push(function() {SpecialPowers.setBoolPref("touchcaret.enabled", false);});
tests.push([ 'bug512295-1.html' , 'bug512295-1-ref.html' ]);
tests.push([ 'bug512295-2.html' , 'bug512295-2-ref.html' ]);
tests.push(function() {SpecialPowers.clearUserPref("touchcaret.enabled");});
tests.push(function() {SpecialPowers.setBoolPref("layout.css.overflow-clip-box.enabled", true);});
tests.push([ 'bug966992-1.html' , 'bug966992-1-ref.html' ]);
tests.push([ 'bug966992-2.html' , 'bug966992-2-ref.html' ]);