Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-10-24 16:07:51 +02:00
commit e7fb1af512
133 changed files with 2122 additions and 553 deletions

View File

@ -155,9 +155,10 @@ let AdbController = {
// 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 sysUsbConfig = libcutils.property_get("sys.usb.config").split(",");
let usbFuncActive = this.umsActive || isDebugging;
usbFuncActive |= (sysUsbConfig.indexOf("rndis") >= 0);
usbFuncActive |= (sysUsbConfig.indexOf("mtp") >= 0);
let enableAdb = this.remoteDebuggerEnabled &&
(!(this.lockEnabled && this.locked) || usbFuncActive);
@ -216,7 +217,6 @@ let AdbController = {
}
}
}
};
SettingsListener.observe("lockscreen.locked", false,

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -133,7 +133,7 @@
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
<project name="kernel/common" path="kernel" revision="310657b79caae2c89e6375a4185fe35fde089c39"/>
<project name="kernel/common" path="kernel" revision="291a7d55be6b0117786bf4d25366186c301185c2"/>
<project name="platform/system/core" path="system/core" revision="53d584d4a4b4316e4de9ee5f210d662f89b44e7e"/>
<project name="u-boot" path="u-boot" revision="982c1fd67b89d5573317c1796cf5b0143de44e8a"/>
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="6974f8e771d4d8e910357a6739ab124768891e8f"/>

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="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -17,7 +17,7 @@
</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="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="be8b952fde51d8c83748b41ce232f02b2218451d"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<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="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -132,7 +132,7 @@
<!-- Flame specific things -->
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/>
<project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="05aa7b98d3f891b334031dc710d48d0d6b82ec1d"/>
<project name="device-flame" path="device/t2m/flame" remote="b2g" revision="dbd93c93782c9aa2306b909acdfb6ded15d49022"/>
<project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="3c4f041e3e3dc676f2111caf20a186ec0467dbdb"/>
<project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="fda40423ffa573dc6cafd3780515010cb2a086be"/>
<project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="30b96dfca99cb384bf520a16b81f3aba56f09907"/>

View File

@ -17,7 +17,7 @@
</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="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="be8b952fde51d8c83748b41ce232f02b2218451d"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "e7679f24177bc939b159dd075085352229a4b709",
"revision": "b508914e27b34f26949fddbe8963fde897ae2268",
"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="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<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="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</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="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="be8b952fde51d8c83748b41ce232f02b2218451d"/>

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="d893a9b971a0f3ee48e5a57dca516837d92cf52b"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="29ed78a26d62b58f663437a45f273d57b9781d79"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="314f305d3163cc094e6fe7701d95a98fc180b639"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -1761,3 +1761,6 @@ pref("experiments.supported", true);
pref("media.gmp-gmpopenh264.provider.enabled", true);
pref("browser.apps.URL", "https://marketplace.firefox.com/discovery/");
pref("browser.polaris.enabled", false);
pref("privacy.trackingprotection.ui.enabled", false);

View File

@ -74,3 +74,13 @@ tabpanels {
browser[pending] {
display: none;
}
browser[pendingpaint] {
opacity: 0;
}
tabbrowser[pendingpaint] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
background-repeat: no-repeat;
background-position: center center;
}

View File

@ -136,6 +136,10 @@
""
</field>
<field name="_contentWaitingCount">
0
</field>
<property name="_numPinnedTabs" readonly="true">
<getter><![CDATA[
for (var i = 0; i < this.tabs.length; i++) {
@ -3238,6 +3242,31 @@
</body>
</method>
<method name="_showBusySpinnerRemoteBrowser">
<parameter name="aBrowser"/>
<body><![CDATA[
aBrowser.setAttribute("pendingpaint", "true");
if (this._contentWaitingCount <= 0) {
// We are not currently spinning
this.setAttribute("pendingpaint", "true");
this._contentWaitingCount = 1;
} else {
this._contentWaitingCount++;
}
]]></body>
</method>
<method name="_hideBusySpinnerRemoteBrowser">
<parameter name="aBrowser"/>
<body><![CDATA[
aBrowser.removeAttribute("pendingpaint");
this._contentWaitingCount--;
if (this._contentWaitingCount <= 0) {
this.removeAttribute("pendingpaint");
}
]]></body>
</method>
<method name="_prepareForTabSwitch">
<parameter name="toTab"/>
<parameter name="fromTab"/>
@ -3276,16 +3305,19 @@
let timeoutPromise = new Promise((aResolve, aReject) => {
timeoutId = setTimeout(() => {
this._showBusySpinnerRemoteBrowser(toBrowser);
attemptTabSwitch(aResolve, aReject);
}, kTabSwitchTimeout);
});
let paintPromise = new Promise((aResolve, aReject) => {
toBrowser.addEventListener("MozAfterRemotePaint", function onRemotePaint() {
let onRemotePaint = () => {
toBrowser.removeEventListener("MozAfterRemotePaint", onRemotePaint);
this._hideBusySpinnerRemoteBrowser(toBrowser);
clearTimeout(timeoutId);
attemptTabSwitch(aResolve, aReject);
});
};
toBrowser.addEventListener("MozAfterRemotePaint", onRemotePaint);
toBrowser.QueryInterface(Ci.nsIFrameLoaderOwner)
.frameLoader
.requestNotifyAfterRemotePaint();

View File

@ -203,7 +203,7 @@ let LoopCallsInternal = {
// Make the call to get the GUEST session regardless of whether the FXA
// request fails.
if (channelID == LoopCalls.channelIDs.FxA && MozLoopService.userProfile) {
if (channelID == MozLoopService.channelIDs.callsFxA && MozLoopService.userProfile) {
this._getCalls(LOOP_SESSION_TYPE.FXA, version);
} else {
this._getCalls(LOOP_SESSION_TYPE.GUEST, version);
@ -320,12 +320,6 @@ Object.freeze(LoopCallsInternal);
* Public API
*/
this.LoopCalls = {
// Channel ids that will be registered with the PushServer for notifications
channelIDs: {
FxA: "25389583-921f-4169-a426-a4673658944b",
Guest: "801f754b-686b-43ec-bd83-1419bbf58388",
},
/**
* Callback from MozLoopPushHandler - A push notification has been received from
* the server.

View File

@ -5,21 +5,166 @@
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
this.EXPORTED_SYMBOLS = ["LoopRooms"];
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopService",
"resource:///modules/loop/MozLoopService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LOOP_SESSION_TYPE",
"resource:///modules/loop/MozLoopService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
"resource:///modules/loop/MozLoopPushHandler.jsm");
/**
* Public Loop Rooms API
*/
this.LoopRooms = Object.freeze({
// Channel ids that will be registered with the PushServer for notifications
channelIDs: {
FxA: "6add272a-d316-477c-8335-f00f73dfde71",
Guest: "19d3f799-a8f3-4328-9822-b7cd02765832",
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
XPCOMUtils.defineLazyGetter(this, "log", () => {
let ConsoleAPI = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).ConsoleAPI;
let consoleOptions = {
maxLogLevel: Services.prefs.getCharPref(PREF_LOG_LEVEL).toLowerCase(),
prefix: "Loop",
};
return new ConsoleAPI(consoleOptions);
});
this.EXPORTED_SYMBOLS = ["LoopRooms", "roomsPushNotification"];
let gRoomsListFetched = false;
let gRooms = new Map();
/**
* Callback used to indicate changes to rooms data on the LoopServer.
*
* @param {Object} version Version number assigned to this change set.
* @param {Object} channelID Notification channel identifier.
*
*/
const roomsPushNotification = function(version, channelID) {
return LoopRoomsInternal.onNotification(version, channelID);
};
let LoopRoomsInternal = {
getAll: function(callback) {
Task.spawn(function*() {
yield MozLoopService.register();
if (gRoomsListFetched) {
callback(null, [...gRooms.values()]);
return;
}
// Fetch the rooms from the server.
let sessionType = MozLoopService.userProfile ? LOOP_SESSION_TYPE.FXA :
LOOP_SESSION_TYPE.GUEST;
let rooms = yield this.requestRoomList(sessionType);
// Add each room to our in-memory Map using a locally unique
// identifier.
for (let room of rooms) {
let id = MozLoopService.generateLocalID();
room.localRoomID = id;
// Next, request the detailed information for each room.
// If the request fails the room data will not be added to the map.
try {
let details = yield this.requestRoomDetails(room.roomToken, sessionType);
for (let attr in details) {
room[attr] = details[attr]
}
gRooms.set(id, room);
}
catch (error) {log.warn("failed GETing room details for roomToken = " + room.roomToken + ": ", error)}
}
callback(null, [...gRooms.values()]);
return;
}.bind(this)).catch((error) => {log.error("getAll error:", error);
callback(error)});
return;
},
getRoomData: function(roomID, callback) {
if (gRooms.has(roomID)) {
callback(null, gRooms.get(roomID));
} else {
callback(new Error("Room data not found or not fetched yet for room with ID " + roomID));
}
return;
},
/**
* Request list of all rooms associated with this account.
*
* @param {String} sessionType Indicates which hawkRequest endpoint to use.
*
* @returns {Promise} room list
*/
requestRoomList: function(sessionType) {
return MozLoopService.hawkRequest(sessionType, "/rooms", "GET")
.then(response => {
let roomsList = JSON.parse(response.body);
if (!Array.isArray(roomsList)) {
// Force a reject in the returned promise.
// To be caught by the caller using the returned Promise.
throw new Error("Missing array of rooms in response.");
}
return roomsList;
});
},
/**
* Request information about a specific room from the server.
*
* @param {Object} token Room identifier returned from the LoopServer.
* @param {String} sessionType Indicates which hawkRequest endpoint to use.
*
* @returns {Promise} room details
*/
requestRoomDetails: function(token, sessionType) {
return MozLoopService.hawkRequest(sessionType, "/rooms/" + token, "GET")
.then(response => JSON.parse(response.body));
},
/**
* Callback used to indicate changes to rooms data on the LoopServer.
*
* @param {Object} version Version number assigned to this change set.
* @param {Object} channelID Notification channel identifier.
*
*/
onNotification: function(version, channelID) {
return;
},
});
};
Object.freeze(LoopRoomsInternal);
/**
* The LoopRooms class.
*
* Each method that is a member of this class requires the last argument to be a
* callback Function. MozLoopAPI will cause things to break if this invariant is
* violated. You'll notice this as well in the documentation for each method.
*/
this.LoopRooms = {
/**
* Fetch a list of rooms that the currently registered user is a member of.
*
* @param {Function} callback Function that will be invoked once the operation
* finished. The first argument passed will be an
* `Error` object or `null`. The second argument will
* be the list of rooms, if it was fetched successfully.
*/
getAll: function(callback) {
return LoopRoomsInternal.getAll(callback);
},
/**
* Return the current stored version of the data for the indicated room.
*
* @param {String} roomID Local room identifier
* @param {Function} callback Function that will be invoked once the operation
* finished. The first argument passed will be an
* `Error` object or `null`. The second argument will
* be the list of rooms, if it was fetched successfully.
*/
getRoomData: function(roomID, callback) {
return LoopRoomsInternal.getRoomData(roomID, callback);
},
};
Object.freeze(LoopRooms);

View File

@ -11,6 +11,8 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/loop/LoopCalls.jsm");
Cu.import("resource:///modules/loop/MozLoopService.jsm");
Cu.import("resource:///modules/loop/LoopRooms.jsm");
Cu.import("resource:///modules/loop/LoopContacts.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LoopContacts",
"resource:///modules/loop/LoopContacts.jsm");
@ -124,6 +126,7 @@ function injectLoopAPI(targetWindow) {
let ringerStopper;
let appVersionInfo;
let contactsAPI;
let roomsAPI;
let api = {
/**
@ -245,6 +248,21 @@ function injectLoopAPI(targetWindow) {
}
},
/**
* Returns the rooms API.
*
* @returns {Object} The rooms API object
*/
rooms: {
enumerable: true,
get: function() {
if (roomsAPI) {
return roomsAPI;
}
return roomsAPI = injectObjectAPI(LoopRooms, targetWindow);
}
},
/**
* Import a list of (new) contacts from an external data source.
*

View File

@ -71,6 +71,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "LoopCalls",
XPCOMUtils.defineLazyModuleGetter(this, "LoopRooms",
"resource:///modules/loop/LoopRooms.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "roomsPushNotification",
"resource:///modules/loop/LoopRooms.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",
"resource:///modules/loop/MozLoopPushHandler.jsm");
@ -342,17 +345,18 @@ let MozLoopServiceInternal = {
let options = mockWebSocket ? {mockWebSocket: mockWebSocket} : {};
gPushHandler.initialize(options);
let callsRegGuest = registerForNotification(LoopCalls.channelIDs.Guest,
let callsRegGuest = registerForNotification(MozLoopService.channelIDs.callsGuest,
LoopCalls.onNotification);
let roomsRegGuest = registerForNotification(LoopRooms.channelIDs.Guest,
LoopRooms.onNotification);
let callsRegFxA = registerForNotification(LoopCalls.channelIDs.FxA,
let roomsRegGuest = registerForNotification(MozLoopService.channelIDs.roomsGuest,
roomsPushNotification);
let callsRegFxA = registerForNotification(MozLoopService.channelIDs.callsFxA,
LoopCalls.onNotification);
let roomsRegFxA = registerForNotification(MozLoopService.channelIDs.roomsFxA,
roomsPushNotification);
let roomsRegFxA = registerForNotification(LoopRooms.channelIDs.FxA,
LoopRooms.onNotification);
Promise.all([callsRegGuest, roomsRegGuest, callsRegFxA, roomsRegFxA])
.then((pushUrls) => {
return this.registerWithLoopServer(LOOP_SESSION_TYPE.GUEST,
@ -516,7 +520,13 @@ let MozLoopServiceInternal = {
* @return {Promise}
*/
registerWithLoopServer: function(sessionType, pushUrls, retry = true) {
return this.hawkRequest(sessionType, "/registration", "POST", { simplePushURLs: pushUrls})
// create a registration payload with a backwards compatible attribute (simplePushURL)
// that will register only the calls notification.
let msg = {
simplePushURL: pushUrls.calls,
simplePushURLs: pushUrls
};
return this.hawkRequest(sessionType, "/registration", "POST", msg)
.then((response) => {
// If this failed we got an invalid token. storeSessionToken rejects
// the gRegisteredDeferred promise for us, so here we just need to
@ -880,8 +890,8 @@ let gInitializeTimerFunc = (deferredInitialization, mockPushHandler, mockWebSock
let registeredPromise =
MozLoopServiceInternal.registerWithLoopServer(
LOOP_SESSION_TYPE.FXA, {
calls: gPushHandler.registeredChannels[LoopCalls.channelIDs.FxA],
rooms: gPushHandler.registeredChannels[LoopRooms.channelIDs.FxA]
calls: gPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA],
rooms: gPushHandler.registeredChannels[MozLoopService.channelIDs.roomsFxA]
});
registeredPromise.then(() => {
deferredInitialization.resolve("initialized to logged-in status");
@ -905,6 +915,17 @@ let gInitializeTimerFunc = (deferredInitialization, mockPushHandler, mockWebSock
this.MozLoopService = {
_DNSService: gDNSService,
get channelIDs() {
// Channel ids that will be registered with the PushServer for notifications
return {
callsFxA: "25389583-921f-4169-a426-a4673658944b",
callsGuest: "801f754b-686b-43ec-bd83-1419bbf58388",
roomsFxA: "6add272a-d316-477c-8335-f00f73dfde71",
roomsGuest: "19d3f799-a8f3-4328-9822-b7cd02765832",
};
},
set initializeTimerFunc(value) {
gInitializeTimerFunc = value;
},
@ -1127,6 +1148,21 @@ this.MozLoopService = {
return uuidgen.generateUUID().toString();
},
/**
* Returns a new non-global id
*
* @param {Function} notUnique [optional] This function will be
* applied to test the generated id for uniqueness
* in the callers domain.
*/
generateLocalID: function(notUnique = ((id) => {return false})) {
do {
var id = Date.now().toString(36) + Math.floor((Math.random() * 4096)).toString(16);
}
while (notUnique(id));
return id;
},
/**
* Retrieves MozLoopService "do not disturb" value.
*
@ -1265,8 +1301,8 @@ this.MozLoopService = {
return tokenData;
}).then(tokenData => {
return gRegisteredDeferred.promise.then(Task.async(function*() {
let callsUrl = gPushHandler.registeredChannels[LoopCalls.channelIDs.FxA],
roomsUrl = gPushHandler.registeredChannels[LoopRooms.channelIDs.FxA];
let callsUrl = gPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA],
roomsUrl = gPushHandler.registeredChannels[MozLoopService.channelIDs.roomsFxA];
if (callsUrl && roomsUrl) {
yield MozLoopServiceInternal.registerWithLoopServer(
LOOP_SESSION_TYPE.FXA, {calls: callsUrl, rooms: roomsUrl});
@ -1314,8 +1350,8 @@ this.MozLoopService = {
log.debug("logOutFromFxA");
let callsPushUrl, roomsPushUrl;
if (gPushHandler) {
callsPushUrl = gPushHandler.registeredChannels[LoopCalls.channelIDs.FxA];
roomsPushUrl = gPushHandler.registeredChannels[LoopRooms.channelIDs.FxA];
callsPushUrl = gPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA];
roomsPushUrl = gPushHandler.registeredChannels[MozLoopService.channelIDs.roomsFxA];
}
try {
if (callsPushUrl) {

View File

@ -232,7 +232,9 @@ loop.Client = (function($) {
this.mozLoop.hawkRequest(this.mozLoop.LOOP_SESSION_TYPE.FXA,
"/calls", "POST", {
calleeId: calleeIds,
callType: callType
callType: callType,
channel: this.mozLoop.appVersionInfo ?
this.mozLoop.appVersionInfo.channel : "unknown"
},
function (err, responseText) {
if (err) {

View File

@ -619,8 +619,6 @@ loop.conversation = (function(mozL10n) {
navigator.mozLoop.releaseCallData(callId);
});
document.body.classList.add(loop.shared.utils.getTargetPlatform());
React.renderComponent(AppControllerView({
localRoomStore: localRoomStore,
store: conversationStore,

View File

@ -619,8 +619,6 @@ loop.conversation = (function(mozL10n) {
navigator.mozLoop.releaseCallData(callId);
});
document.body.classList.add(loop.shared.utils.getTargetPlatform());
React.renderComponent(<AppControllerView
localRoomStore={localRoomStore}
store={conversationStore}

View File

@ -717,8 +717,11 @@ loop.panel = (function(_, mozL10n) {
UserIdentity({displayName: displayName}),
AvailabilityDropdown(null)
),
AuthLink(null),
SettingsDropdown(null)
React.DOM.div({className: "signin-details"},
AuthLink(null),
React.DOM.div({className: "footer-signin-separator"}),
SettingsDropdown(null)
)
)
)
);
@ -748,7 +751,6 @@ loop.panel = (function(_, mozL10n) {
dispatcher: dispatcher}
), document.querySelector("#main"));
document.body.classList.add(loop.shared.utils.getTargetPlatform());
document.body.setAttribute("dir", mozL10n.getDirection());
// Notify the window that we've finished initalization and initial layout

View File

@ -717,8 +717,11 @@ loop.panel = (function(_, mozL10n) {
<UserIdentity displayName={displayName} />
<AvailabilityDropdown />
</div>
<AuthLink />
<SettingsDropdown />
<div className="signin-details">
<AuthLink />
<div className="footer-signin-separator" />
<SettingsDropdown />
</div>
</div>
</div>
);
@ -748,7 +751,6 @@ loop.panel = (function(_, mozL10n) {
dispatcher={dispatcher}
/>, document.querySelector("#main"));
document.body.classList.add(loop.shared.utils.getTargetPlatform());
document.body.setAttribute("dir", mozL10n.getDirection());
// Notify the window that we've finished initalization and initial layout

View File

@ -358,12 +358,6 @@ p {
color: rgba(51, 51, 51, .5);
}
.mac p,
.windows p,
.linux p {
line-height: 16px;
}
/* Web panel */
.info-panel {

View File

@ -268,7 +268,7 @@ body {
.dropdown-menu {
position: absolute;
top: -28px;
bottom: 0;
left: 0;
background-color: #fdfdfd;
box-shadow: 0 1px 3px rgba(0,0,0,.3);
@ -345,6 +345,10 @@ body[dir=rtl] .dropdown-menu-item {
.dnd-status {
border: 1px solid transparent;
padding: 2px 4px;
margin: 0;
/* Undo the start border + padding so that unhovered dnd-status is aligned
as if there was no additional spacing. */
-moz-margin-start: calc(-1px + -4px);
font-size: .9em;
cursor: pointer;
border-radius: 3px;
@ -377,10 +381,7 @@ body[dir=rtl] .dropdown-menu-item {
.signin-link {
flex: 2 1 auto;
margin-top: 14px;
border-right: 1px solid #aaa;
padding-right: 1em;
margin-right: 1em;
margin: 0;
text-align: right;
}
@ -390,6 +391,12 @@ body[dir=rtl] .dropdown-menu-item {
color: #888;
}
.footer-signin-separator {
border-right: 1px solid #aaa;
height: 16px;
margin: 0 1em;
}
/* Settings (gear) menu */
.button-settings {
@ -413,7 +420,6 @@ body[dir=rtl] .dropdown-menu-item {
}
.footer .button-settings {
margin-top: 17px; /* used to align the gear icon with the availability dropdown menu inner text */
opacity: .6; /* used to "grey" the icon a little */
}
@ -459,10 +465,22 @@ body[dir=rtl] .dropdown-menu-item {
flex-wrap: nowrap;
justify-content: space-between;
align-content: stretch;
align-items: flex-start;
align-items: center;
font-size: 1em;
border-top: 1px solid #D1D1D1;
background-color: #eaeaea;
color: #7f7f7f;
padding: 14px;
}
.footer .signin-details {
align-items: center;
display: flex;
-moz-margin-start: 5px;
}
.footer .user-identity {
color: #000;
font-weight: bold;
margin: 0;
}

View File

@ -29,26 +29,6 @@ loop.shared.utils = (function(mozL10n) {
return date.toLocaleDateString(navigator.language, options);
}
/**
* Used for adding different styles to the panel
* @returns {String} Corresponds to the client platform
* */
function getTargetPlatform() {
var platform="unknown_platform";
if (navigator.platform.indexOf("Win") !== -1) {
platform = "windows";
}
if (navigator.platform.indexOf("Mac") !== -1) {
platform = "mac";
}
if (navigator.platform.indexOf("Linux") !== -1) {
platform = "linux";
}
return platform;
}
/**
* Used for getting a boolean preference. It will either use the browser preferences
* (if navigator.mozLoop is defined) or try to get them from localStorage.
@ -133,7 +113,6 @@ loop.shared.utils = (function(mozL10n) {
Helper: Helper,
composeCallUrlEmail: composeCallUrlEmail,
formatDate: formatDate,
getTargetPlatform: getTargetPlatform,
getBoolPreference: getBoolPreference
};
})(document.mozL10n || navigator.mozL10n);

View File

@ -115,7 +115,7 @@ loop.StandaloneClient = (function($) {
method: "POST",
contentType: "application/json",
dataType: "json",
data: JSON.stringify({callType: callType})
data: JSON.stringify({callType: callType, channel: "standalone"})
});
req.done(function(sessionData) {

View File

@ -272,7 +272,23 @@ describe("loop.Client", function() {
mozLoop.LOOP_SESSION_TYPE.FXA,
"/calls",
"POST",
{ calleeId: calleeIds, callType: callType }
{ calleeId: calleeIds, callType: callType, channel: "unknown" }
);
});
it("should include the channel when defined", function() {
mozLoop.appVersionInfo = {
channel: "beta"
};
client.setupOutgoingCall(calleeIds, callType);
sinon.assert.calledOnce(hawkRequestStub);
sinon.assert.calledWith(hawkRequestStub,
mozLoop.LOOP_SESSION_TYPE.FXA,
"/calls",
"POST",
{ calleeId: calleeIds, callType: callType, channel: "beta" }
);
});

View File

@ -256,8 +256,8 @@ add_task(function* basicAuthorizationAndRegistration() {
// Normally the same pushUrl would be registered but we change it in the test
// to be able to check for success on the second registration.
mockPushHandler.registeredChannels[LoopCalls.channelIDs.FxA] = "https://localhost/pushUrl/fxa-calls";
mockPushHandler.registeredChannels[LoopRooms.channelIDs.FxA] = "https://localhost/pushUrl/fxa-rooms";
mockPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA] = "https://localhost/pushUrl/fxa-calls";
mockPushHandler.registeredChannels[MozLoopService.channelIDs.roomsFxA] = "https://localhost/pushUrl/fxa-rooms";
statusChangedPromise = promiseObserverNotified("loop-status-changed");
yield loadLoopPanel({loopURL: BASE_URL, stayOnline: true});
@ -333,8 +333,8 @@ add_task(function* loginWithParams401() {
add_task(function* logoutWithIncorrectPushURL() {
yield resetFxA();
let pushURL = "http://www.example.com/";
mockPushHandler.registeredChannels[LoopCalls.channelIDs.FxA] = pushURL;
mockPushHandler.registeredChannels[LoopRooms.channelIDs.FxA] = pushURL;
mockPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA] = pushURL;
mockPushHandler.registeredChannels[MozLoopService.channelIDs.roomsFxA] = pushURL;
// Create a fake FxA hawk session token
const fxASessionPref = MozLoopServiceInternal.getSessionTokenPrefName(LOOP_SESSION_TYPE.FXA);
@ -343,7 +343,7 @@ add_task(function* logoutWithIncorrectPushURL() {
yield MozLoopServiceInternal.registerWithLoopServer(LOOP_SESSION_TYPE.FXA, {calls: pushURL});
let registrationResponse = yield promiseOAuthGetRegistration(BASE_URL);
ise(registrationResponse.response.simplePushURLs.calls, pushURL, "Check registered push URL");
mockPushHandler.registeredChannels[LoopCalls.channelIDs.FxA] = "http://www.example.com/invalid";
mockPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA] = "http://www.example.com/invalid";
let caught = false;
yield MozLoopService.logOutFromFxA().catch((error) => {
caught = true;
@ -357,7 +357,7 @@ add_task(function* logoutWithIncorrectPushURL() {
add_task(function* logoutWithNoPushURL() {
yield resetFxA();
let pushURL = "http://www.example.com/";
mockPushHandler.registeredChannels[LoopCalls.channelIDs.FxA] = pushURL;
mockPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA] = pushURL;
// Create a fake FxA hawk session token
const fxASessionPref = MozLoopServiceInternal.getSessionTokenPrefName(LOOP_SESSION_TYPE.FXA);
@ -366,8 +366,8 @@ add_task(function* logoutWithNoPushURL() {
yield MozLoopServiceInternal.registerWithLoopServer(LOOP_SESSION_TYPE.FXA, {calls: pushURL});
let registrationResponse = yield promiseOAuthGetRegistration(BASE_URL);
ise(registrationResponse.response.simplePushURLs.calls, pushURL, "Check registered push URL");
mockPushHandler.registeredChannels[LoopCalls.channelIDs.FxA] = null;
mockPushHandler.registeredChannels[LoopRooms.channelIDs.FxA] = null;
mockPushHandler.registeredChannels[MozLoopService.channelIDs.callsFxA] = null;
mockPushHandler.registeredChannels[MozLoopService.channelIDs.roomsFxA] = null;
yield MozLoopService.logOutFromFxA();
checkLoggedOutState();
registrationResponse = yield promiseOAuthGetRegistration(BASE_URL);

View File

@ -128,7 +128,7 @@ describe("loop.StandaloneClient", function() {
expect(requests).to.have.length.of(1);
expect(requests[0].url).to.be.equal("http://fake.api/calls/fake");
expect(requests[0].method).to.be.equal("POST");
expect(requests[0].requestBody).to.be.equal('{"callType":"audio"}');
expect(requests[0].requestBody).to.be.equal('{"callType":"audio","channel":"standalone"}');
});
it("should receive call data for the given call", function() {

View File

@ -10,6 +10,7 @@ Cu.import("resource://testing-common/httpd.js");
Cu.import("resource:///modules/loop/MozLoopService.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource:///modules/loop/LoopCalls.jsm");
Cu.import("resource:///modules/loop/LoopRooms.jsm");
const { MozLoopServiceInternal } = Cu.import("resource:///modules/loop/MozLoopService.jsm", {});
XPCOMUtils.defineLazyModuleGetter(this, "MozLoopPushHandler",

View File

@ -35,7 +35,7 @@ add_test(function test_busy_2guest_calls() {
opened++;
};
mockPushHandler.notify(1, LoopCalls.channelIDs.Guest);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsGuest);
waitForCondition(() => {return actionReceived && opened > 0}).then(() => {
do_check_true(opened === 1, "should open only one chat window");
@ -58,8 +58,8 @@ add_test(function test_busy_1fxa_1guest_calls() {
opened++;
};
mockPushHandler.notify(1, LoopCalls.channelIDs.FxA);
mockPushHandler.notify(1, LoopCalls.channelIDs.Guest);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsFxA);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsGuest);
waitForCondition(() => {return actionReceived && opened > 0}).then(() => {
do_check_true(opened === 1, "should open only one chat window");
@ -82,7 +82,7 @@ add_test(function test_busy_2fxa_calls() {
opened++;
};
mockPushHandler.notify(1, LoopCalls.channelIDs.FxA);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsFxA);
waitForCondition(() => {return actionReceived && opened > 0}).then(() => {
do_check_true(opened === 1, "should open only one chat window");
@ -105,8 +105,8 @@ add_test(function test_busy_1guest_1fxa_calls() {
opened++;
};
mockPushHandler.notify(1, LoopCalls.channelIDs.Guest);
mockPushHandler.notify(1, LoopCalls.channelIDs.FxA);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsGuest);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsFxA);
waitForCondition(() => {return actionReceived && opened > 0}).then(() => {
do_check_true(opened === 1, "should open only one chat window");

View File

@ -37,7 +37,7 @@ add_test(function test_do_not_disturb_disabled_should_open_chat_window() {
opened = true;
};
mockPushHandler.notify(1, LoopCalls.channelIDs.Guest);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsGuest);
waitForCondition(function() opened).then(() => {
run_next_test();
@ -56,7 +56,7 @@ add_test(function test_do_not_disturb_enabled_shouldnt_open_chat_window() {
opened = true;
};
mockPushHandler.notify(1, LoopCalls.channelIDs.Guest);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsGuest);
do_timeout(500, function() {
do_check_false(opened, "should not open a chat window");

View File

@ -16,7 +16,7 @@ add_test(function test_openChatWindow_on_notification() {
opened = true;
};
mockPushHandler.notify(1, LoopCalls.channelIDs.Guest);
mockPushHandler.notify(1, MozLoopService.channelIDs.callsGuest);
waitForCondition(function() opened).then(() => {
do_check_true(opened, "should open a chat window");

View File

@ -0,0 +1,131 @@
/* 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/. */
Cu.import("resource://services-common/utils.js");
XPCOMUtils.defineLazyModuleGetter(this, "Chat",
"resource:///modules/Chat.jsm");
let hasTheseProps = function(a, b) {
for (let prop in a) {
if (a[prop] != b[prop]) {
do_print("hasTheseProps fail: prop = " + prop);
return false;
}
}
return true;
}
let openChatOrig = Chat.open;
add_test(function test_getAllRooms() {
let roomList = [
{ roomToken: "_nxD4V4FflQ",
roomName: "First Room Name",
roomUrl: "http://localhost:3000/rooms/_nxD4V4FflQ",
maxSize: 2,
currSize: 0,
ctime: 1405517546 },
{ roomToken: "QzBbvGmIZWU",
roomName: "Second Room Name",
roomUrl: "http://localhost:3000/rooms/QzBbvGmIZWU",
maxSize: 2,
currSize: 0,
ctime: 140551741 },
{ roomToken: "3jKS_Els9IU",
roomName: "Third Room Name",
roomUrl: "http://localhost:3000/rooms/3jKS_Els9IU",
maxSize: 3,
clientMaxSize: 2,
currSize: 1,
ctime: 1405518241 }
]
let roomDetail = {
roomName: "First Room Name",
roomUrl: "http://localhost:3000/rooms/_nxD4V4FflQ",
roomOwner: "Alexis",
maxSize: 2,
clientMaxSize: 2,
creationTime: 1405517546,
expiresAt: 1405534180,
participants: [
{ displayName: "Alexis", account: "alexis@example.com", roomConnectionId: "2a1787a6-4a73-43b5-ae3e-906ec1e763cb" },
{ displayName: "Adam", roomConnectionId: "781f012b-f1ea-4ce1-9105-7cfc36fb4ec7" }
]
}
loopServer.registerPathHandler("/rooms", (request, response) => {
response.setStatusLine(null, 200, "OK");
response.write(JSON.stringify(roomList));
response.processAsync();
response.finish();
});
let returnRoomDetails = function(response, roomName) {
roomDetail.roomName = roomName;
response.setStatusLine(null, 200, "OK");
response.write(JSON.stringify(roomDetail));
response.processAsync();
response.finish();
}
loopServer.registerPathHandler("/rooms/_nxD4V4FflQ", (request, response) => {
returnRoomDetails(response, "First Room Name");
});
loopServer.registerPathHandler("/rooms/QzBbvGmIZWU", (request, response) => {
returnRoomDetails(response, "Second Room Name");
});
loopServer.registerPathHandler("/rooms/3jKS_Els9IU", (request, response) => {
returnRoomDetails(response, "Third Room Name");
});
MozLoopService.register(mockPushHandler).then(() => {
LoopRooms.getAll((error, rooms) => {
do_check_false(error);
do_check_true(rooms);
do_check_eq(rooms.length, 3);
do_check_eq(rooms[0].roomName, "First Room Name");
do_check_eq(rooms[1].roomName, "Second Room Name");
do_check_eq(rooms[2].roomName, "Third Room Name");
let room = rooms[0];
do_check_true(room.localRoomID);
do_check_true(hasTheseProps(roomList[0], room));
delete roomDetail.roomName;
delete room.participants;
delete roomDetail.participants;
do_check_true(hasTheseProps(roomDetail, room));
LoopRooms.getRoomData(room.localRoomID, (error, roomData) => {
do_check_false(error);
do_check_true(hasTheseProps(room, roomData));
run_next_test();
});
});
});
});
function run_test()
{
setupFakeLoopServer();
mockPushHandler.registrationPushURL = kEndPointUrl;
loopServer.registerPathHandler("/registration", (request, response) => {
response.setStatusLine(null, 200, "OK");
response.processAsync();
response.finish();
});
do_register_cleanup(function() {
// Revert original Chat.open implementation
Chat.open = openChatOrig;
});
run_next_test();
}

View File

@ -21,3 +21,4 @@ skip-if = toolkit == 'gonk'
[test_loopservice_token_send.js]
[test_loopservice_token_validation.js]
[test_loopservice_busy.js]
[test_rooms_getdata.js]

View File

@ -21,5 +21,6 @@ navigator.mozLoop = {
callback(null, []);
},
on: function() {}
}
},
fxAEnabled: true
};

View File

@ -537,10 +537,7 @@
}
window.addEventListener("DOMContentLoaded", function() {
var body = document.body;
body.className = loop.shared.utils.getTargetPlatform();
React.renderComponent(App(null), body);
React.renderComponent(App(null), document.body);
_renderComponentsInIframes();

View File

@ -537,10 +537,7 @@
}
window.addEventListener("DOMContentLoaded", function() {
var body = document.body;
body.className = loop.shared.utils.getTargetPlatform();
React.renderComponent(<App />, body);
React.renderComponent(<App />, document.body);
_renderComponentsInIframes();

View File

@ -52,6 +52,20 @@
<!-- Short Description -->
<div id="errorTrailerDesc">
<div>
<div class="radioRestoreContainer">
<input class="radioRestoreButton" id="radioRestoreAll" type="radio"
name="restore" checked="checked"/>
<label class="radioRestoreLabel" for="radioRestoreAll">&welcomeback2.label.restoreAll;</label>
</div>
<div class="radioRestoreContainer">
<input class="radioRestoreButton" id="radioRestoreChoose" type="radio"
name="restore"/>
<label class="radioRestoreLabel" for="radioRestoreChoose">&welcomeback2.label.restoreSome;</label>
</div>
</div>
<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="tabList" flex="1" seltype="single" hidecolumnpicker="true"
onclick="onListClick(event);" onkeydown="onListKeyDown(event);"

View File

@ -9,6 +9,7 @@ const Cr = Components.results;
const Cu = Components.utils;
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const POLARIS_ENABLED = "browser.polaris.enabled";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -397,6 +398,13 @@ BrowserGlue.prototype = {
Services.obs.removeObserver(this, "browser-search-service");
this._syncSearchEngines();
break;
case "nsPref:changed":
if (data == POLARIS_ENABLED) {
let enabled = Services.prefs.getBoolPref(POLARIS_ENABLED);
Services.prefs.setBoolPref("privacy.donottrackheader.enabled", enabled);
Services.prefs.setBoolPref("privacy.trackingprotection.enabled", enabled);
Services.prefs.setBoolPref("privacy.trackingprotection.ui.enabled", enabled);
}
}
},
@ -443,6 +451,9 @@ BrowserGlue.prototype = {
#endif
os.addObserver(this, "browser-search-engine-modified", false);
os.addObserver(this, "browser-search-service", false);
#ifdef NIGHTLY_BUILD
Services.prefs.addObserver(POLARIS_ENABLED, this, false);
#endif
},
// cleanup (called on application shutdown)
@ -483,6 +494,9 @@ BrowserGlue.prototype = {
os.removeObserver(this, "browser-search-service");
// may have already been removed by the observer
} catch (ex) {}
#ifdef NIGHTLY_BUILD
Services.prefs.removeObserver(POLARIS_ENABLED, this);
#endif
},
_onAppDefaults: function BG__onAppDefaults() {

View File

@ -20,6 +20,14 @@ window.onload = function() {
anchor.setAttribute("href", baseURL + "troubleshooting");
}
// wire up click handlers for the radio buttons if they exist.
for (let radioId of ["radioRestoreAll", "radioRestoreChoose"]) {
let button = document.getElementById(radioId);
if (button) {
button.addEventListener("click", updateTabListVisibility);
}
}
// the crashed session state is kept inside a textbox so that SessionStore picks it up
// (for when the tab is closed or the session crashes right again)
var sessionData = document.getElementById("sessionData");
@ -40,7 +48,17 @@ window.onload = function() {
document.getElementById("errorTryAgain").focus();
};
function isTreeViewVisible() {
let tabList = document.getElementById("tabList");
return tabList.hasAttribute("available");
}
function initTreeView() {
// If we aren't visible we initialize as we are made visible (and it's OK
// to initialize multiple times)
if (!isTreeViewVisible()) {
return;
}
var tabList = document.getElementById("tabList");
var winLabel = tabList.getAttribute("_window_label");
@ -75,31 +93,42 @@ function initTreeView() {
}
// User actions
function updateTabListVisibility() {
let tabList = document.getElementById("tabList");
if (document.getElementById("radioRestoreChoose").checked) {
tabList.setAttribute("available", "true");
} else {
tabList.removeAttribute("available");
}
initTreeView();
}
function restoreSession() {
document.getElementById("errorTryAgain").disabled = true;
if (!gTreeData.some(aItem => aItem.checked)) {
// This should only be possible when we have no "cancel" button, and thus
// the "Restore session" button always remains enabled. In that case and
// when nothing is selected, we just want a new session.
startNewSession();
return;
}
if (isTreeViewVisible()) {
if (!gTreeData.some(aItem => aItem.checked)) {
// This should only be possible when we have no "cancel" button, and thus
// the "Restore session" button always remains enabled. In that case and
// when nothing is selected, we just want a new session.
startNewSession();
return;
}
// remove all unselected tabs from the state before restoring it
var ix = gStateObject.windows.length - 1;
for (var t = gTreeData.length - 1; t >= 0; t--) {
if (treeView.isContainer(t)) {
if (gTreeData[t].checked === 0)
// this window will be restored partially
gStateObject.windows[ix].tabs =
gStateObject.windows[ix].tabs.filter(function(aTabData, aIx)
gTreeData[t].tabs[aIx].checked);
else if (!gTreeData[t].checked)
// this window won't be restored at all
gStateObject.windows.splice(ix, 1);
ix--;
// remove all unselected tabs from the state before restoring it
var ix = gStateObject.windows.length - 1;
for (var t = gTreeData.length - 1; t >= 0; t--) {
if (treeView.isContainer(t)) {
if (gTreeData[t].checked === 0)
// this window will be restored partially
gStateObject.windows[ix].tabs =
gStateObject.windows[ix].tabs.filter(function(aTabData, aIx)
gTreeData[t].tabs[aIx].checked);
else if (!gTreeData[t].checked)
// this window won't be restored at all
gStateObject.windows.splice(ix, 1);
ix--;
}
}
}
var stateString = JSON.stringify(gStateObject);

View File

@ -57,7 +57,7 @@
<tree xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="tabList" flex="1" seltype="single" hidecolumnpicker="true"
onclick="onListClick(event);" onkeydown="onListKeyDown(event);"
_window_label="&restorepage.windowLabel;">
available="true" _window_label="&restorepage.windowLabel;">
<treecols>
<treecol cycler="true" id="restore" type="checkbox" label="&restorepage.restoreHeader;"/>
<splitter class="tree-splitter"/>

View File

@ -2,3 +2,5 @@
[browser_bug538331.js]
skip-if = e10s # Bug ?????? - child process crash, but only when run as part of the suite (ie, probably not actually this tests fault!?)
[browser_polaris_prefs.js]

View File

@ -0,0 +1,57 @@
const POLARIS_ENABLED = "browser.polaris.enabled";
const PREF_DNT = "privacy.donottrackheader.enabled";
const PREF_TP = "privacy.trackingprotection.enabled";
const PREF_TPUI = "privacy.trackingprotection.ui.enabled";
let prefs = [PREF_DNT, PREF_TP, PREF_TPUI];
function spinEventLoop() {
return new Promise((resolve) => executeSoon(resolve));
};
// Spin event loop before checking so that polaris pref observer can set
// dependent prefs.
function* assertPref(pref, enabled) {
yield spinEventLoop();
let prefEnabled = Services.prefs.getBoolPref(pref);
Assert.equal(prefEnabled, enabled, "Checking state of pref " + pref + ".");
};
function* testPrefs(test) {
for (let pref of prefs) {
yield test(pref);
}
}
add_task(function* test_default_values() {
Assert.ok(!Services.prefs.getBoolPref(POLARIS_ENABLED), POLARIS_ENABLED + " is disabled by default.");
Assert.ok(!Services.prefs.getBoolPref(PREF_TPUI), PREF_TPUI + "is disabled by default.");
});
add_task(function* test_changing_pref_changes_tracking() {
function* testPref(pref) {
Services.prefs.setBoolPref(POLARIS_ENABLED, true);
yield assertPref(pref, true);
Services.prefs.setBoolPref(POLARIS_ENABLED, false);
yield assertPref(pref, false);
Services.prefs.setBoolPref(POLARIS_ENABLED, true);
yield assertPref(pref, true);
}
yield testPrefs(testPref);
});
add_task(function* test_prefs_can_be_changed_individually() {
function* testPref(pref) {
Services.prefs.setBoolPref(POLARIS_ENABLED, true);
yield assertPref(pref, true);
Services.prefs.setBoolPref(pref, false);
yield assertPref(pref, false);
yield assertPref(POLARIS_ENABLED, true);
Services.prefs.setBoolPref(POLARIS_ENABLED, false);
yield assertPref(pref, false);
Services.prefs.setBoolPref(pref, true);
yield assertPref(pref, true);
yield assertPref(POLARIS_ENABLED, false);
}
yield testPrefs(testPref);
});

View File

@ -45,6 +45,8 @@ skip-if = true # Bug 1047124
skip-if = true # Bug 1047124
[browser_profiler_recording-selected-02.js]
skip-if = true # Bug 1047124
[browser_profiler_recording-selected-03.js]
skip-if = true # Bug 1047124
[browser_profiler_recording-utils.js]
skip-if = true # Bug 1047124
[browser_profiler_recordings-clear.js]

View File

@ -0,0 +1,35 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if the profiler UI does not forget that recording is active when
* selected recording changes. Bug 1060885.
*/
let test = Task.async(function*() {
let [target, debuggee, panel] = yield initFrontend(SIMPLE_URL);
let { $, EVENTS, RecordingsListView, ProfileView } = panel.panelWin;
yield startRecording(panel);
yield stopRecording(panel, { waitForDisplay: true });
yield startRecording(panel);
yield stopRecording(panel, { waitForDisplay: true });
yield startRecording(panel);
info("Selecting recording #0 and waiting for it to be displayed.");
let selected = panel.panelWin.once(EVENTS.RECORDING_DISPLAYED);
RecordingsListView.selectedIndex = 0;
yield selected;
ok($("#record-button").hasAttribute("checked"),
"Button is still checked after selecting another item.");
ok(!$("#record-button").hasAttribute("locked"),
"Button is not locked after selecting another item.");
yield teardown(panel);
finish();
});

View File

@ -150,9 +150,10 @@ function* stopRecording(panel, { waitForDisplay }) {
if (waitForDisplay) {
yield displayed;
ok(!button.hasAttribute("checked"),
"The record button should not be checked anymore.");
if (!win.RecordingsListView.getItemForPredicate(e => e.isRecording)) {
ok(!button.hasAttribute("checked"),
"The record button should not be checked anymore.");
}
ok(!button.hasAttribute("locked"),
"The record button should not be locked anymore.");
}

View File

@ -202,7 +202,12 @@ let RecordingsListView = Heritage.extend(WidgetMethods, {
yield ProfileView.addTabAndPopulate(recordingData, 0, durationMillis);
ProfileView.showTabbedBrowser();
$("#record-button").removeAttribute("checked");
// Only clear the checked state if there's nothing recording.
if (!this.getItemForPredicate(e => e.isRecording)) {
$("#record-button").removeAttribute("checked");
}
// But don't leave it locked in any case.
$("#record-button").removeAttribute("locked");
window.emit(EVENTS.RECORDING_DISPLAYED);

View File

@ -6,7 +6,6 @@ const Cu = Components.utils;
Cu.import('resource:///modules/devtools/gDevTools.jsm');
const {require} = Cu.import('resource://gre/modules/devtools/Loader.jsm', {}).devtools;
const {Services} = Cu.import('resource://gre/modules/Services.jsm');
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
const {AppManager} = require('devtools/webide/app-manager');
const {AppActorFront} = require('devtools/app-actor-front');
const {Connection} = require('devtools/client/connection-manager');
@ -227,8 +226,7 @@ let Monitor = {
*/
pollB2GInfo: function() {
if (AppManager.selectedRuntime) {
let id = AppManager.selectedRuntime.id;
let device = Devices.getByName(id);
let device = AppManager.selectedRuntime.device;
if (device && device.shell) {
device.shell('b2g-info').then(s => {
let lines = s.split('\n');

View File

@ -35,12 +35,6 @@
<input data-pref="devtools.webide.templatesURL"/>
</label>
</li>
<li>
<label title="&prefs_options_enablelocalruntime_tooltip;">
<input type="checkbox" data-pref="devtools.webide.enableLocalRuntime"/>
<span>&prefs_options_enablelocalruntime;</span>
</label>
</li>
<li>
<label title="&prefs_options_rememberlastproject_tooltip;">
<input type="checkbox" data-pref="devtools.webide.restoreLastProject"/>

View File

@ -7,8 +7,7 @@ const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {require} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
const {AppManager} = require("devtools/webide/app-manager");
const {Connection} = require("devtools/client/connection-manager");
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
const {USBRuntime} = require("devtools/webide/runtimes");
const {RuntimeTypes} = require("devtools/webide/runtimes");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
window.addEventListener("load", function onLoad() {
@ -86,8 +85,8 @@ function CheckLockState() {
AppManager.connection.status == Connection.Status.CONNECTED) {
// ADB check
if (AppManager.selectedRuntime instanceof USBRuntime) {
let device = Devices.getByName(AppManager.selectedRuntime.id);
if (AppManager.selectedRuntime.type === RuntimeTypes.USB) {
let device = AppManager.selectedRuntime.device;
if (device && device.summonRoot) {
device.isRoot().then(isRoot => {
if (isRoot) {
@ -127,16 +126,16 @@ function CheckLockState() {
}
function EnableCertApps() {
let device = Devices.getByName(AppManager.selectedRuntime.id);
let device = AppManager.selectedRuntime.device;
device.shell(
"stop b2g && " +
"cd /data/b2g/mozilla/*.default/ && " +
"echo 'user_pref(\"devtools.debugger.forbid-certified-apps\", false);' >> prefs.js && " +
"start b2g"
)
);
}
function RootADB() {
let device = Devices.getByName(AppManager.selectedRuntime.id);
let device = AppManager.selectedRuntime.device;
device.summonRoot().then(CheckLockState, (e) => console.error(e));
}

View File

@ -22,6 +22,7 @@ const {GetAvailableAddons} = require("devtools/webide/addons");
const {GetTemplatesJSON, GetAddonsJSON} = require("devtools/webide/remote-resources");
const utils = require("devtools/webide/utils");
const Telemetry = require("devtools/shared/telemetry");
const {RuntimeScanners, WiFiScanner} = require("devtools/webide/runtimes");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
@ -148,7 +149,10 @@ let UI = {
case "list-tabs-response":
this.updateCommands();
break;
case "runtime":
case "runtime-details":
this.updateRuntimeButton();
break;
case "runtime-changed":
this.updateRuntimeButton();
this.saveLastConnectedRuntime();
break;
@ -305,17 +309,17 @@ let UI = {
/********** RUNTIME **********/
updateRuntimeList: function() {
let wifiHeaderNode = document.querySelector("#runtime-header-wifi-devices");
if (AppManager.isWiFiScanningEnabled) {
let wifiHeaderNode = document.querySelector("#runtime-header-wifi");
if (WiFiScanner.allowed) {
wifiHeaderNode.removeAttribute("hidden");
} else {
wifiHeaderNode.setAttribute("hidden", "true");
}
let USBListNode = document.querySelector("#runtime-panel-usbruntime");
let WiFiListNode = document.querySelector("#runtime-panel-wifi-devices");
let simulatorListNode = document.querySelector("#runtime-panel-simulators");
let customListNode = document.querySelector("#runtime-panel-custom");
let usbListNode = document.querySelector("#runtime-panel-usb");
let wifiListNode = document.querySelector("#runtime-panel-wifi");
let simulatorListNode = document.querySelector("#runtime-panel-simulator");
let otherListNode = document.querySelector("#runtime-panel-other");
let noHelperNode = document.querySelector("#runtime-panel-noadbhelper");
let noUSBNode = document.querySelector("#runtime-panel-nousbdevice");
@ -326,25 +330,27 @@ let UI = {
noHelperNode.removeAttribute("hidden");
}
if (AppManager.runtimeList.usb.length == 0 && Devices.helperAddonInstalled) {
let runtimeList = AppManager.runtimeList;
if (runtimeList.usb.length === 0 && Devices.helperAddonInstalled) {
noUSBNode.removeAttribute("hidden");
} else {
noUSBNode.setAttribute("hidden", "true");
}
for (let [type, parent] of [
["usb", USBListNode],
["wifi", WiFiListNode],
["usb", usbListNode],
["wifi", wifiListNode],
["simulator", simulatorListNode],
["custom", customListNode],
["other", otherListNode],
]) {
while (parent.hasChildNodes()) {
parent.firstChild.remove();
}
for (let runtime of AppManager.runtimeList[type]) {
for (let runtime of runtimeList[type]) {
let panelItemNode = document.createElement("toolbarbutton");
panelItemNode.className = "panel-item runtime-panel-item-" + type;
panelItemNode.setAttribute("label", runtime.getName());
panelItemNode.setAttribute("label", runtime.name);
parent.appendChild(panelItemNode);
let r = runtime;
panelItemNode.addEventListener("click", () => {
@ -366,18 +372,18 @@ let UI = {
type = type.toLowerCase();
// Local connection is mapped to AppManager.runtimeList.custom array
// Local connection is mapped to AppManager.runtimeList.other array
if (type == "local") {
type = "custom";
type = "other";
}
// We support most runtimes except simulator, that needs to be manually
// launched
if (type == "usb" || type == "wifi" || type == "custom") {
if (type == "usb" || type == "wifi" || type == "other") {
for (let runtime of AppManager.runtimeList[type]) {
// Some runtimes do not expose getID function and don't support
// autoconnect (like remote connection)
if (typeof(runtime.getID) == "function" && runtime.getID() == id) {
// Some runtimes do not expose an id and don't support autoconnect (like
// remote connection)
if (runtime.id == id) {
this.connectToRuntime(runtime);
}
}
@ -385,10 +391,10 @@ let UI = {
},
connectToRuntime: function(runtime) {
let name = runtime.getName();
let name = runtime.name;
let promise = AppManager.connectToRuntime(runtime);
promise.then(() => this.initConnectionTelemetry());
return this.busyUntil(promise, "connecting to runtime");
return this.busyUntil(promise, "connecting to runtime " + name);
},
updateRuntimeButton: function() {
@ -396,15 +402,16 @@ let UI = {
if (!AppManager.selectedRuntime) {
labelNode.setAttribute("value", Strings.GetStringFromName("runtimeButton_label"));
} else {
let name = AppManager.selectedRuntime.getName();
let name = AppManager.selectedRuntime.name;
labelNode.setAttribute("value", name);
}
},
saveLastConnectedRuntime: function () {
if (AppManager.selectedRuntime &&
typeof(AppManager.selectedRuntime.getID) === "function") {
this.lastConnectedRuntime = AppManager.selectedRuntime.type + ":" + AppManager.selectedRuntime.getID();
AppManager.selectedRuntime.id !== undefined) {
this.lastConnectedRuntime = AppManager.selectedRuntime.type + ":" +
AppManager.selectedRuntime.id;
} else {
this.lastConnectedRuntime = "";
}
@ -1125,7 +1132,7 @@ let Cmds = {
},
showRuntimePanel: function() {
AppManager.scanForWiFiRuntimes();
RuntimeScanners.scan();
let panel = document.querySelector("#runtime-panel");
let anchor = document.querySelector("#runtime-panel-button > .panel-button-anchor");

View File

@ -151,17 +151,17 @@
<!-- Runtime panel -->
<panel id="runtime-panel" type="arrow" position="bottomcenter topright" consumeoutsideclicks="true" animate="false">
<vbox flex="1">
<label class="panel-header">&runtimePanel_USBDevices;</label>
<label class="panel-header">&runtimePanel_usb;</label>
<toolbarbutton class="panel-item" label="&runtimePanel_nousbdevice;" id="runtime-panel-nousbdevice" command="cmd_showTroubleShooting"/>
<toolbarbutton class="panel-item" label="&runtimePanel_noadbhelper;" id="runtime-panel-noadbhelper" command="cmd_showAddons"/>
<vbox id="runtime-panel-usbruntime"></vbox>
<label class="panel-header" id="runtime-header-wifi-devices">&runtimePanel_WiFiDevices;</label>
<vbox id="runtime-panel-wifi-devices"></vbox>
<label class="panel-header">&runtimePanel_simulators;</label>
<vbox id="runtime-panel-simulators"></vbox>
<vbox id="runtime-panel-usb"></vbox>
<label class="panel-header" id="runtime-header-wifi">&runtimePanel_wifi;</label>
<vbox id="runtime-panel-wifi"></vbox>
<label class="panel-header">&runtimePanel_simulator;</label>
<vbox id="runtime-panel-simulator"></vbox>
<toolbarbutton class="panel-item" label="&runtimePanel_installsimulator;" id="runtime-panel-installsimulator" command="cmd_showAddons"/>
<label class="panel-header">&runtimePanel_custom;</label>
<vbox id="runtime-panel-custom"></vbox>
<label class="panel-header">&runtimePanel_other;</label>
<vbox id="runtime-panel-other"></vbox>
<vbox flex="1" id="runtime-actions">
<toolbarbutton class="panel-item" id="runtime-details" command="cmd_showRuntimeDetails"/>
<toolbarbutton class="panel-item" id="runtime-permissions" command="cmd_showPermissionsTable"/>

View File

@ -7,11 +7,9 @@ const {Cu} = require("chrome");
let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {});
const {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
const {Devices} = Cu.import("resource://gre/modules/devtools/Devices.jsm");
const {Services} = Cu.import("resource://gre/modules/Services.jsm");
const {FileUtils} = Cu.import("resource://gre/modules/FileUtils.jsm");
const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm");
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
const EventEmitter = require("devtools/toolkit/event-emitter");
const {TextEncoder, OS} = Cu.import("resource://gre/modules/osfile.jsm", {});
const {AppProjects} = require("devtools/app-manager/app-projects");
const TabStore = require("devtools/webide/tab-store");
@ -22,26 +20,20 @@ const {getDeviceFront} = require("devtools/server/actors/device");
const {getPreferenceFront} = require("devtools/server/actors/preference");
const {setTimeout} = require("sdk/timers");
const {Task} = Cu.import("resource://gre/modules/Task.jsm", {});
const {USBRuntime, WiFiRuntime, SimulatorRuntime,
gLocalRuntime, gRemoteRuntime} = require("devtools/webide/runtimes");
const discovery = require("devtools/toolkit/discovery/discovery");
const {RuntimeScanners, RuntimeTypes} = require("devtools/webide/runtimes");
const {NetUtil} = Cu.import("resource://gre/modules/NetUtil.jsm", {});
const Telemetry = require("devtools/shared/telemetry");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
const WIFI_SCANNING_PREF = "devtools.remote.wifi.scan";
exports.AppManager = AppManager = {
let AppManager = exports.AppManager = {
// FIXME: will break when devtools/app-manager will be removed:
DEFAULT_PROJECT_ICON: "chrome://browser/skin/devtools/app-manager/default-app-icon.png",
DEFAULT_PROJECT_NAME: "--",
init: function() {
let host = Services.prefs.getCharPref("devtools.debugger.remote-host");
let port = Services.prefs.getIntPref("devtools.debugger.remote-port");
this.connection = ConnectionManager.createConnection("localhost", port);
this.onConnectionChanged = this.onConnectionChanged.bind(this);
this.connection.on(Connection.Events.STATUS_CHANGED, this.onConnectionChanged);
@ -52,33 +44,22 @@ exports.AppManager = AppManager = {
this.tabStore.on("navigate", this.onTabNavigate);
this.tabStore.on("closed", this.onTabClosed);
this.runtimeList = {
usb: [],
wifi: [],
simulator: [],
custom: [gRemoteRuntime]
};
if (Services.prefs.getBoolPref("devtools.webide.enableLocalRuntime")) {
this.runtimeList.custom.push(gLocalRuntime);
}
this.trackUSBRuntimes();
this.trackWiFiRuntimes();
this.trackSimulatorRuntimes();
this._clearRuntimeList();
this._rebuildRuntimeList = this._rebuildRuntimeList.bind(this);
RuntimeScanners.on("runtime-list-updated", this._rebuildRuntimeList);
RuntimeScanners.enable();
this._rebuildRuntimeList();
this.onInstallProgress = this.onInstallProgress.bind(this);
this.observe = this.observe.bind(this);
Services.prefs.addObserver(WIFI_SCANNING_PREF, this, false);
this._telemetry = new Telemetry();
},
uninit: function() {
this.selectedProject = null;
this.selectedRuntime = null;
this.untrackUSBRuntimes();
this.untrackWiFiRuntimes();
this.untrackSimulatorRuntimes();
RuntimeScanners.off("runtime-list-updated", this._rebuildRuntimeList);
RuntimeScanners.disable();
this.runtimeList = null;
this.tabStore.off("navigate", this.onTabNavigate);
this.tabStore.off("closed", this.onTabClosed);
@ -88,17 +69,6 @@ exports.AppManager = AppManager = {
this._listTabsResponse = null;
this.connection.disconnect();
this.connection = null;
Services.prefs.removeObserver(WIFI_SCANNING_PREF, this);
},
observe: function(subject, topic, data) {
if (data !== WIFI_SCANNING_PREF) {
return;
}
// Cycle WiFi tracking to reflect the new value
this.untrackWiFiRuntimes();
this.trackWiFiRuntimes();
this._updateWiFiRuntimes();
},
update: function(what, details) {
@ -334,7 +304,7 @@ exports.AppManager = AppManager = {
this.selectedProject.type == "tab")) {
this.selectedProject = null;
}
this.update("runtime");
this.update("runtime-changed");
},
get selectedRuntime() {
@ -607,89 +577,41 @@ exports.AppManager = AppManager = {
/* RUNTIME LIST */
trackUSBRuntimes: function() {
this._updateUSBRuntimes = this._updateUSBRuntimes.bind(this);
Devices.on("register", this._updateUSBRuntimes);
Devices.on("unregister", this._updateUSBRuntimes);
Devices.on("addon-status-updated", this._updateUSBRuntimes);
this._updateUSBRuntimes();
_clearRuntimeList: function() {
this.runtimeList = {
usb: [],
wifi: [],
simulator: [],
other: []
};
},
untrackUSBRuntimes: function() {
Devices.off("register", this._updateUSBRuntimes);
Devices.off("unregister", this._updateUSBRuntimes);
Devices.off("addon-status-updated", this._updateUSBRuntimes);
},
_updateUSBRuntimes: function() {
this.runtimeList.usb = [];
for (let id of Devices.available()) {
let r = new USBRuntime(id);
this.runtimeList.usb.push(r);
r.updateNameFromADB().then(
() => {
this.update("runtimelist");
// Also update the runtime button label, if the currently selected
// runtime name changes
if (r == this.selectedRuntime) {
this.update("runtime");
}
},
() => {});
_rebuildRuntimeList: function() {
let runtimes = RuntimeScanners.listRuntimes();
this._clearRuntimeList();
// Reorganize runtimes by type
for (let runtime of runtimes) {
switch (runtime.type) {
case RuntimeTypes.USB:
this.runtimeList.usb.push(runtime);
break;
case RuntimeTypes.WIFI:
this.runtimeList.wifi.push(runtime);
break;
case RuntimeTypes.SIMULATOR:
this.runtimeList.simulator.push(runtime);
break;
default:
this.runtimeList.other.push(runtime);
}
}
this.update("runtime-details");
this.update("runtimelist");
},
get isWiFiScanningEnabled() {
return Services.prefs.getBoolPref(WIFI_SCANNING_PREF);
},
scanForWiFiRuntimes: function() {
if (!this.isWiFiScanningEnabled) {
return;
}
discovery.scan();
},
trackWiFiRuntimes: function() {
if (!this.isWiFiScanningEnabled) {
return;
}
this._updateWiFiRuntimes = this._updateWiFiRuntimes.bind(this);
discovery.on("devtools-device-added", this._updateWiFiRuntimes);
discovery.on("devtools-device-updated", this._updateWiFiRuntimes);
discovery.on("devtools-device-removed", this._updateWiFiRuntimes);
this._updateWiFiRuntimes();
},
untrackWiFiRuntimes: function() {
if (!this.isWiFiScanningEnabled) {
return;
}
discovery.off("devtools-device-added", this._updateWiFiRuntimes);
discovery.off("devtools-device-updated", this._updateWiFiRuntimes);
discovery.off("devtools-device-removed", this._updateWiFiRuntimes);
},
_updateWiFiRuntimes: function() {
this.runtimeList.wifi = [];
for (let device of discovery.getRemoteDevicesWithService("devtools")) {
this.runtimeList.wifi.push(new WiFiRuntime(device));
}
this.update("runtimelist");
},
trackSimulatorRuntimes: function() {
this._updateSimulatorRuntimes = this._updateSimulatorRuntimes.bind(this);
Simulator.on("register", this._updateSimulatorRuntimes);
Simulator.on("unregister", this._updateSimulatorRuntimes);
this._updateSimulatorRuntimes();
},
untrackSimulatorRuntimes: function() {
Simulator.off("register", this._updateSimulatorRuntimes);
Simulator.off("unregister", this._updateSimulatorRuntimes);
},
_updateSimulatorRuntimes: function() {
this.runtimeList.simulator = [];
for (let version of Simulator.availableVersions()) {
this.runtimeList.simulator.push(new SimulatorRuntime(version));
}
this.update("runtimelist");
},
/* MANIFEST UTILS */
writeManifest: function(project) {
if (project.type != "packaged") {
@ -707,6 +629,6 @@ exports.AppManager = AppManager = {
let array = encoder.encode(text);
return OS.File.writeAtomic(manifestPath, array, {tmpPath: manifestPath + ".tmp"});
},
}
};
EventEmitter.decorate(AppManager);

View File

@ -9,50 +9,413 @@ const {Simulator} = Cu.import("resource://gre/modules/devtools/Simulator.jsm");
const {ConnectionManager, Connection} = require("devtools/client/connection-manager");
const {DebuggerServer} = require("resource://gre/modules/devtools/dbg-server.jsm");
const discovery = require("devtools/toolkit/discovery/discovery");
const EventEmitter = require("devtools/toolkit/event-emitter");
const promise = require("promise");
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/webide.properties");
// These type strings are used for logging events to Telemetry
let RuntimeTypes = {
usb: "USB",
wifi: "WIFI",
simulator: "SIMULATOR",
remote: "REMOTE",
local: "LOCAL"
/**
* Runtime and Scanner API
*
* |RuntimeScanners| maintains a set of |Scanner| objects that produce one or
* more |Runtime|s to connect to. Add-ons can extend the set of known runtimes
* by registering additional |Scanner|s that emit them.
*
* Each |Scanner| must support the following API:
*
* enable()
* Bind any event handlers and start any background work the scanner needs to
* maintain an updated set of |Runtime|s.
* Called when the first consumer (such as WebIDE) actively interested in
* maintaining the |Runtime| list enables the registry.
* disable()
* Unbind any event handlers and stop any background work the scanner needs to
* maintain an updated set of |Runtime|s.
* Called when the last consumer (such as WebIDE) actively interested in
* maintaining the |Runtime| list disables the registry.
* emits "runtime-list-updated"
* If the set of runtimes a |Scanner| manages has changed, it must emit this
* event to notify consumers of changes.
* scan()
* Actively refreshes the list of runtimes the scanner knows about. If your
* scanner uses an active scanning approach (as opposed to listening for
* events when changes occur), the bulk of the work would be done here.
* @return Promise
* Should be resolved when scanning is complete. If scanning has no
* well-defined end point, you can resolve immediately, as long as
* update event is emitted later when changes are noticed.
* listRuntimes()
* Return the current list of runtimes known to the |Scanner| instance.
* @return Iterable
*
* Each |Runtime| must support the following API:
*
* |type| field
* The |type| must be one of the values from the |RuntimeTypes| object. This
* is used for Telemetry and to support displaying sets of |Runtime|s
* categorized by type.
* |id| field
* An identifier that is unique in the set of all runtimes with the same
* |type|. WebIDE tries to save the last used runtime via type + id, and
* tries to locate it again in the next session, so this value should attempt
* to be stable across Firefox sessions.
* |name| field
* A user-visible label to identify the runtime that will be displayed in a
* runtime list.
* connect()
* Configure the passed |connection| object with any settings need to
* successfully connect to the runtime, and call the |connection|'s connect()
* method.
* @param Connection connection
* A |Connection| object from the DevTools |ConnectionManager|.
* @return Promise
* Resolved once you've called the |connection|'s connect() method.
*/
/* SCANNER REGISTRY */
let RuntimeScanners = {
_enabledCount: 0,
_scanners: new Set(),
get enabled() {
return !!this._enabledCount;
},
add(scanner) {
if (this.enabled) {
// Enable any scanner added while globally enabled
this._enableScanner(scanner);
}
this._scanners.add(scanner);
this._emitUpdated();
},
remove(scanner) {
this._scanners.delete(scanner);
if (this.enabled) {
// Disable any scanner removed while globally enabled
this._disableScanner(scanner);
}
this._emitUpdated();
},
has(scanner) {
return this._scanners.has(scanner);
},
scan() {
if (!this.enabled) {
return promise.resolve();
}
if (this._scanPromise) {
return this._scanPromise;
}
let promises = [];
for (let scanner of this._scanners) {
promises.push(scanner.scan());
}
this._scanPromise = promise.all(promises);
// Reset pending promise
this._scanPromise.then(() => {
this._scanPromise = null;
}, () => {
this._scanPromise = null;
});
return this._scanPromise;
},
listRuntimes: function*() {
for (let scanner of this._scanners) {
for (let runtime of scanner.listRuntimes()) {
yield runtime;
}
}
},
_emitUpdated() {
this.emit("runtime-list-updated");
},
enable() {
if (this._enabledCount++ !== 0) {
// Already enabled scanners during a previous call
return;
}
this._emitUpdated = this._emitUpdated.bind(this);
for (let scanner of this._scanners) {
this._enableScanner(scanner);
}
},
_enableScanner(scanner) {
scanner.enable();
scanner.on("runtime-list-updated", this._emitUpdated);
},
disable() {
if (--this._enabledCount !== 0) {
// Already disabled scanners during a previous call
return;
}
for (let scanner of this._scanners) {
this._disableScanner(scanner);
}
},
_disableScanner(scanner) {
scanner.off("runtime-list-updated", this._emitUpdated);
scanner.disable();
},
};
function USBRuntime(id) {
this.id = id;
EventEmitter.decorate(RuntimeScanners);
exports.RuntimeScanners = RuntimeScanners;
/* SCANNERS */
let SimulatorScanner = {
_runtimes: [],
enable() {
this._updateRuntimes = this._updateRuntimes.bind(this);
Simulator.on("register", this._updateRuntimes);
Simulator.on("unregister", this._updateRuntimes);
this._updateRuntimes();
},
disable() {
Simulator.off("register", this._updateRuntimes);
Simulator.off("unregister", this._updateRuntimes);
},
_emitUpdated() {
this.emit("runtime-list-updated");
},
_updateRuntimes() {
this._runtimes = [];
for (let version of Simulator.availableVersions()) {
this._runtimes.push(new SimulatorRuntime(version));
}
this._emitUpdated();
},
scan() {
return promise.resolve();
},
listRuntimes: function() {
return this._runtimes;
}
};
EventEmitter.decorate(SimulatorScanner);
RuntimeScanners.add(SimulatorScanner);
/**
* TODO: Remove this comaptibility layer in the future (bug 1085393)
* This runtime exists to support the ADB Helper add-on below version 0.7.0.
*
* This scanner will list all ADB devices as runtimes, even if they may or may
* not actually connect (since the |DeprecatedUSBRuntime| assumes a Firefox OS
* device).
*/
let DeprecatedAdbScanner = {
_runtimes: [],
enable() {
this._updateRuntimes = this._updateRuntimes.bind(this);
Devices.on("register", this._updateRuntimes);
Devices.on("unregister", this._updateRuntimes);
Devices.on("addon-status-updated", this._updateRuntimes);
this._updateRuntimes();
},
disable() {
Devices.off("register", this._updateRuntimes);
Devices.off("unregister", this._updateRuntimes);
Devices.off("addon-status-updated", this._updateRuntimes);
},
_emitUpdated() {
this.emit("runtime-list-updated");
},
_updateRuntimes() {
this._runtimes = [];
for (let id of Devices.available()) {
let runtime = new DeprecatedUSBRuntime(id);
this._runtimes.push(runtime);
runtime.updateNameFromADB().then(() => {
this._emitUpdated();
}, () => {});
}
this._emitUpdated();
},
scan() {
return promise.resolve();
},
listRuntimes: function() {
return this._runtimes;
}
};
EventEmitter.decorate(DeprecatedAdbScanner);
RuntimeScanners.add(DeprecatedAdbScanner);
// ADB Helper 0.7.0 and later will replace this scanner on startup
exports.DeprecatedAdbScanner = DeprecatedAdbScanner;
let WiFiScanner = {
_runtimes: [],
init() {
this.updateRegistration();
Services.prefs.addObserver(this.ALLOWED_PREF, this, false);
},
enable() {
this._updateRuntimes = this._updateRuntimes.bind(this);
discovery.on("devtools-device-added", this._updateRuntimes);
discovery.on("devtools-device-updated", this._updateRuntimes);
discovery.on("devtools-device-removed", this._updateRuntimes);
this._updateRuntimes();
},
disable() {
discovery.off("devtools-device-added", this._updateRuntimes);
discovery.off("devtools-device-updated", this._updateRuntimes);
discovery.off("devtools-device-removed", this._updateRuntimes);
},
_emitUpdated() {
this.emit("runtime-list-updated");
},
_updateRuntimes() {
this._runtimes = [];
for (let device of discovery.getRemoteDevicesWithService("devtools")) {
this._runtimes.push(new WiFiRuntime(device));
}
this._emitUpdated();
},
scan() {
discovery.scan();
return promise.resolve();
},
listRuntimes: function() {
return this._runtimes;
},
ALLOWED_PREF: "devtools.remote.wifi.scan",
get allowed() {
return Services.prefs.getBoolPref(this.ALLOWED_PREF);
},
updateRegistration() {
if (this.allowed) {
RuntimeScanners.add(WiFiScanner);
} else {
RuntimeScanners.remove(WiFiScanner);
}
this._emitUpdated();
},
observe(subject, topic, data) {
if (data !== WiFiScanner.ALLOWED_PREF) {
return;
}
WiFiScanner.updateRegistration();
}
};
EventEmitter.decorate(WiFiScanner);
WiFiScanner.init();
exports.WiFiScanner = WiFiScanner;
let StaticScanner = {
enable() {},
disable() {},
scan() { return promise.resolve(); },
listRuntimes() { return [gRemoteRuntime, gLocalRuntime]; }
};
EventEmitter.decorate(StaticScanner);
RuntimeScanners.add(StaticScanner);
/* RUNTIMES */
// These type strings are used for logging events to Telemetry.
// You must update Histograms.json if new types are added.
let RuntimeTypes = exports.RuntimeTypes = {
USB: "USB",
WIFI: "WIFI",
SIMULATOR: "SIMULATOR",
REMOTE: "REMOTE",
LOCAL: "LOCAL",
OTHER: "OTHER"
};
/**
* TODO: Remove this comaptibility layer in the future (bug 1085393)
* This runtime exists to support the ADB Helper add-on below version 0.7.0.
*
* This runtime assumes it is connecting to a Firefox OS device.
*/
function DeprecatedUSBRuntime(id) {
this._id = id;
}
USBRuntime.prototype = {
type: RuntimeTypes.usb,
DeprecatedUSBRuntime.prototype = {
type: RuntimeTypes.USB,
get device() {
return Devices.getByName(this._id);
},
connect: function(connection) {
let device = Devices.getByName(this.id);
if (!device) {
return promise.reject("Can't find device: " + this.getName());
if (!this.device) {
return promise.reject("Can't find device: " + this.name);
}
return device.connect().then((port) => {
return this.device.connect().then((port) => {
connection.host = "localhost";
connection.port = port;
connection.connect();
});
},
getID: function() {
return this.id;
get id() {
return this._id;
},
getName: function() {
return this._productModel || this.id;
get name() {
return this._productModel || this._id;
},
updateNameFromADB: function() {
if (this._productModel) {
return promise.resolve();
return promise.reject();
}
let device = Devices.getByName(this.id);
let deferred = promise.defer();
if (device && device.shell) {
device.shell("getprop ro.product.model").then(stdout => {
if (this.device && this.device.shell) {
this.device.shell("getprop ro.product.model").then(stdout => {
this._productModel = stdout;
deferred.resolve();
}, () => {});
@ -62,43 +425,49 @@ USBRuntime.prototype = {
}
return deferred.promise;
},
}
};
// For testing use only
exports._DeprecatedUSBRuntime = DeprecatedUSBRuntime;
function WiFiRuntime(deviceName) {
this.deviceName = deviceName;
}
WiFiRuntime.prototype = {
type: RuntimeTypes.wifi,
type: RuntimeTypes.WIFI,
connect: function(connection) {
let service = discovery.getRemoteService("devtools", this.deviceName);
if (!service) {
return promise.reject("Can't find device: " + this.getName());
return promise.reject("Can't find device: " + this.name);
}
connection.host = service.host;
connection.port = service.port;
connection.connect();
return promise.resolve();
},
getID: function() {
get id() {
return this.deviceName;
},
getName: function() {
get name() {
return this.deviceName;
},
}
};
// For testing use only
exports._WiFiRuntime = WiFiRuntime;
function SimulatorRuntime(version) {
this.version = version;
}
SimulatorRuntime.prototype = {
type: RuntimeTypes.simulator,
type: RuntimeTypes.SIMULATOR,
connect: function(connection) {
let port = ConnectionManager.getFreeTCPPort();
let simulator = Simulator.getByVersion(this.version);
if (!simulator || !simulator.launch) {
return promise.reject("Can't find simulator: " + this.getName());
return promise.reject("Can't find simulator: " + this.name);
}
return simulator.launch({port: port}).then(() => {
connection.host = "localhost";
@ -108,16 +477,23 @@ SimulatorRuntime.prototype = {
connection.connect();
});
},
getID: function() {
get id() {
return this.version;
},
getName: function() {
get name() {
let simulator = Simulator.getByVersion(this.version);
if (!simulator) {
return "Unknown";
}
return Simulator.getByVersion(this.version).appinfo.label;
},
}
};
// For testing use only
exports._SimulatorRuntime = SimulatorRuntime;
let gLocalRuntime = {
type: RuntimeTypes.local,
type: RuntimeTypes.LOCAL,
connect: function(connection) {
if (!DebuggerServer.initialized) {
DebuggerServer.init();
@ -128,16 +504,19 @@ let gLocalRuntime = {
connection.connect();
return promise.resolve();
},
getName: function() {
get id() {
return "local";
},
get name() {
return Strings.GetStringFromName("local_runtime");
},
getID: function () {
return "local";
}
}
};
// For testing use only
exports._gLocalRuntime = gLocalRuntime;
let gRemoteRuntime = {
type: RuntimeTypes.remote,
type: RuntimeTypes.REMOTE,
connect: function(connection) {
let win = Services.wm.getMostRecentWindow("devtools:webide");
if (!win) {
@ -159,13 +538,10 @@ let gRemoteRuntime = {
connection.connect();
return promise.resolve();
},
getName: function() {
get name() {
return Strings.GetStringFromName("remote_runtime");
},
}
};
exports.USBRuntime = USBRuntime;
exports.WiFiRuntime = WiFiRuntime;
exports.SimulatorRuntime = SimulatorRuntime;
exports.gRemoteRuntime = gRemoteRuntime;
exports.gLocalRuntime = gLocalRuntime;
// For testing use only
exports._gRemoteRuntime = gRemoteRuntime;

View File

@ -43,7 +43,7 @@ function connectToLocal(win) {
win.AppManager.connection.once(
win.Connection.Events.CONNECTED,
() => deferred.resolve());
win.document.querySelectorAll(".runtime-panel-item-custom")[1].click();
win.document.querySelectorAll(".runtime-panel-item-other")[1].click();
return deferred.promise;
}

View File

@ -22,7 +22,6 @@ if (window.location === "chrome://browser/content/browser.xul") {
}
Services.prefs.setBoolPref("devtools.webide.enabled", true);
Services.prefs.setBoolPref("devtools.webide.enableLocalRuntime", true);
Services.prefs.setCharPref("devtools.webide.addonsURL", TEST_BASE + "addons/simulators.json");
Services.prefs.setCharPref("devtools.webide.simulatorAddonsURL", TEST_BASE + "addons/fxos_#SLASHED_VERSION#_simulator-#OS#.xpi");
@ -33,7 +32,6 @@ Services.prefs.setCharPref("devtools.webide.templatesURL", TEST_BASE + "template
SimpleTest.registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.webide.enabled");
Services.prefs.clearUserPref("devtools.webide.enableLocalRuntime");
Services.prefs.clearUserPref("devtools.webide.autoinstallADBHelper");
Services.prefs.clearUserPref("devtools.webide.autoinstallFxdtAdapters");
});

View File

@ -35,11 +35,11 @@
return promise.resolve();
},
getID: function() {
get id() {
return "fakeRuntime";
},
getName: function() {
get name() {
return "fakeRuntime";
}
};

View File

@ -34,11 +34,11 @@
yield documentIsLoaded(permIframe.contentWindow.document);
yield documentIsLoaded(infoIframe.contentWindow.document);
win.AppManager.update("runtimelist");
win.AppManager._rebuildRuntimeList();
let panelNode = win.document.querySelector("#runtime-panel");
let items = panelNode.querySelectorAll(".runtime-panel-item-custom");
is(items.length, 2, "Found 2 custom runtimes button");
let items = panelNode.querySelectorAll(".runtime-panel-item-other");
is(items.length, 2, "Found 2 other runtimes button");
let deferred = promise.defer();
win.AppManager.on("app-manager-update", function onUpdate(e,w) {

View File

@ -57,7 +57,7 @@
return promise.resolve();
},
getName: function() {
get name() {
return "fakeRuntime";
}
});
@ -110,7 +110,7 @@
ok(!isPlayActive(), "play button is disabled 4");
ok(!isStopActive(), "stop button is disabled 4");
win.document.querySelectorAll(".runtime-panel-item-custom")[1].click();
win.document.querySelectorAll(".runtime-panel-item-other")[1].click();
yield waitForUpdate(win, "list-tabs-response");

View File

@ -16,8 +16,9 @@
<script type="application/javascript;version=1.8">
const Telemetry = require("devtools/shared/telemetry");
const { USBRuntime, WiFiRuntime, SimulatorRuntime, gRemoteRuntime,
gLocalRuntime } = require("devtools/webide/runtimes");
const { _DeprecatedUSBRuntime, _WiFiRuntime, _SimulatorRuntime,
_gRemoteRuntime, _gLocalRuntime, RuntimeTypes }
= require("devtools/webide/runtimes");
// Because we need to gather stats for the period of time that a tool has
// been opened we make use of setTimeout() to create tool active times.
@ -55,7 +56,7 @@
// We use the real runtimes here (and switch out some functionality)
// so we can ensure that logging happens as it would in real use.
let usb = new USBRuntime("fakeUSB");
let usb = new _DeprecatedUSBRuntime("fakeUSB");
// Use local pipe instead
usb.connect = function(connection) {
ok(connection, win.AppManager.connection, "connection is valid");
@ -65,7 +66,7 @@
};
win.AppManager.runtimeList.usb.push(usb);
let wifi = new WiFiRuntime("fakeWiFi");
let wifi = new _WiFiRuntime("fakeWiFi");
// Use local pipe instead
wifi.connect = function(connection) {
ok(connection, win.AppManager.connection, "connection is valid");
@ -75,7 +76,7 @@
};
win.AppManager.runtimeList.wifi.push(wifi);
let sim = new SimulatorRuntime("fakeSimulator");
let sim = new _SimulatorRuntime("fakeSimulator");
// Use local pipe instead
sim.connect = function(connection) {
ok(connection, win.AppManager.connection, "connection is valid");
@ -83,12 +84,14 @@
connection.connect();
return promise.resolve();
};
sim.getName = function() {
return this.version;
};
Object.defineProperty(sim, "name", {
get() {
return this.version;
}
});
win.AppManager.runtimeList.simulator.push(sim);
let remote = gRemoteRuntime;
let remote = _gRemoteRuntime;
// Use local pipe instead
remote.connect = function(connection) {
ok(connection, win.AppManager.connection, "connection is valid");
@ -96,8 +99,12 @@
connection.connect();
return promise.resolve();
};
let local = gLocalRuntime;
win.AppManager.runtimeList.custom = [gRemoteRuntime, gLocalRuntime];
let local = _gLocalRuntime;
let other = Object.create(_gLocalRuntime);
other.type = RuntimeTypes.OTHER;
win.AppManager.runtimeList.other = [remote, local, other];
win.AppManager.update("runtimelist");
}
@ -164,7 +171,7 @@
ok(okay, "All " + histId + " entries have time > 0");
} else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_RESULT") {
ok(value.length === 5, histId + " has 5 connection results");
ok(value.length === 6, histId + " has 6 connection results");
let okay = value.every(function(element) {
return !!element;
@ -175,7 +182,7 @@
ok(value.length === 1 && !!value[0],
histId + " has 1 successful connection");
} else if (histId === "DEVTOOLS_WEBIDE_CONNECTION_TIME_SECONDS") {
ok(value.length === 5, histId + " has 5 connection results");
ok(value.length === 6, histId + " has 6 connection results");
let okay = value.every(function(element) {
return element > 0;
@ -183,7 +190,7 @@
ok(okay, "All " + histId + " connections have time > 0");
} else if (histId.endsWith("USED")) {
ok(value.length === 5, histId + " has 5 connection actions");
ok(value.length === 6, histId + " has 6 connection actions");
let okay = value.every(function(element) {
return !element;
@ -239,9 +246,11 @@
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, "simulator");
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, "custom", 0 /* remote */);
yield connectToRuntime(win, "other", 0 /* remote */);
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, "custom", 1 /* local */);
yield connectToRuntime(win, "other", 1 /* local */);
yield waitForTime(TOOL_DELAY);
yield connectToRuntime(win, "other", 2 /* other */);
yield waitForTime(TOOL_DELAY);
yield closeWebIDE(win);

View File

@ -209,7 +209,7 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
padding: 12px 0 0;
}
#runtime-panel-custom {
#runtime-panel-other {
margin-bottom: 12px;
}
@ -222,7 +222,7 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
#runtime-panel-installsimulator,
.runtime-panel-item-usb,
.runtime-panel-item-wifi,
.runtime-panel-item-custom,
.runtime-panel-item-other,
.runtime-panel-item-simulator {
list-style-image: url("icons.png");
}
@ -236,7 +236,7 @@ panel > .panel-arrowcontainer > .panel-arrowcontent {
#runtime-panel-installsimulator { -moz-image-region: rect(0px,438px,26px,412px) }
.runtime-panel-item-usb { -moz-image-region: rect(52px,438px,78px,412px) }
.runtime-panel-item-wifi { -moz-image-region: rect(208px,438px,234px,412px) }
.runtime-panel-item-custom { -moz-image-region: rect(26px,438px,52px,412px) }
.runtime-panel-item-other { -moz-image-region: rect(26px,438px,52px,412px) }
.runtime-panel-item-simulator { -moz-image-region: rect(0px,438px,26px,412px) }
#runtime-actions {

View File

@ -8,7 +8,6 @@ pref("devtools.webide.templatesURL", "https://code.cdn.mozilla.net/templates/lis
pref("devtools.webide.autoinstallADBHelper", true);
pref("devtools.webide.autoinstallFxdtAdapters", false);
pref("devtools.webide.restoreLastProject", true);
pref("devtools.webide.enableLocalRuntime", true);
pref("devtools.webide.addonsURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/index.json");
pref("devtools.webide.simulatorAddonsURL", "https://ftp.mozilla.org/pub/mozilla.org/labs/fxos-simulator/#VERSION#/#OS#/fxos_#SLASHED_VERSION#_simulator-#OS#-latest.xpi");
pref("devtools.webide.simulatorAddonID", "fxos_#SLASHED_VERSION#_simulator@mozilla.org");

View File

@ -63,10 +63,10 @@
<!ENTITY projectPanel_myProjects "My Projects">
<!ENTITY projectPanel_runtimeApps "Runtime Apps">
<!ENTITY projectPanel_tabs "Tabs">
<!ENTITY runtimePanel_USBDevices "USB Devices">
<!ENTITY runtimePanel_WiFiDevices "Wi-Fi Devices">
<!ENTITY runtimePanel_simulators "Simulators">
<!ENTITY runtimePanel_custom "Custom">
<!ENTITY runtimePanel_usb "USB Devices">
<!ENTITY runtimePanel_wifi "Wi-Fi Devices">
<!ENTITY runtimePanel_simulator "Simulators">
<!ENTITY runtimePanel_other "Other">
<!ENTITY runtimePanel_installsimulator "Install Simulator">
<!ENTITY runtimePanel_noadbhelper "Install ADB Helper">
<!ENTITY runtimePanel_nousbdevice "Can't see your device?">
@ -101,8 +101,6 @@
<!ENTITY prefs_general_title "General">
<!ENTITY prefs_restore "Restore Defaults">
<!ENTITY prefs_simulators "Manage Simulators">
<!ENTITY prefs_options_enablelocalruntime "Enable local runtime">
<!ENTITY prefs_options_enablelocalruntime_tooltip "Allow WebIDE to connect to its own runtime (running browser instance)">
<!ENTITY prefs_options_rememberlastproject "Remember last project">
<!ENTITY prefs_options_rememberlastproject_tooltip "Restore previous project when WebIDE starts">
<!ENTITY prefs_options_templatesurl "Templates URL">

View File

@ -14,7 +14,7 @@ const Cu = Components.utils;
// The minimum sizes for the auto-resize panel code, minimum size necessary to
// properly show the error page in the panel.
const PANEL_MIN_HEIGHT = 200;
const PANEL_MIN_HEIGHT = 190;
const PANEL_MIN_WIDTH = 330;
Cu.import("resource://gre/modules/Services.jsm");

View File

@ -187,6 +187,9 @@ browser.jar:
skin/classic/browser/tabbrowser/tab-stroke-start.png (tabbrowser/tab-stroke-start.png)
skin/classic/browser/tabbrowser/tabDragIndicator.png (tabbrowser/tabDragIndicator.png)
skin/classic/browser/tabbrowser/tab-separator.png (tabbrowser/tab-separator.png)
skin/classic/browser/tabbrowser/pendingpaint.png (../shared/tabbrowser/pendingpaint.png)
skin/classic/browser/tabview/edit-light.png (tabview/edit-light.png)
skin/classic/browser/tabview/search.png (tabview/search.png)
skin/classic/browser/tabview/stack-expander.png (tabview/stack-expander.png)

View File

@ -302,6 +302,8 @@ browser.jar:
skin/classic/browser/tabbrowser/tab-background-start@2x.png (tabbrowser/tab-background-start@2x.png)
skin/classic/browser/tabbrowser/tab-overflow-indicator.png (../shared/tabbrowser/tab-overflow-indicator.png)
skin/classic/browser/tabbrowser/pendingpaint.png (../shared/tabbrowser/pendingpaint.png)
# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in
# Makefile.in with a non-default marker of "%" and the result of that gets packaged.
skin/classic/browser/tabbrowser/tab-selected-end.svg (tab-selected-end.svg)

View File

@ -3,6 +3,7 @@ body {
margin-top: 2em;
font: message-box;
font-size: 100%;
min-height: 200px;
}
p {

View File

@ -4,4 +4,39 @@
#errorPageContainer {
background-image: url("chrome://global/skin/icons/information-64.png");
height: auto;
}
/* tablist starts out hidden, but JS may make it visible in response to
clicks on the radio buttons by setting an "available" attribute.
*/
#tabList {
display: none;
}
#tabList[available] {
display: -moz-box;
}
.radioRestoreContainer {
display: flex;
}
.radioRestoreButton {
flex: 0 0 auto;
}
.radioRestoreButton:-moz-focusring {
outline: 1px dotted black;
}
.radioChooseLabel {
flex: 1 1 auto;
}
/* We want errorTrailerDesc to have the same padding-top as errorShortDesc
has padding-bottom
*/
#errorTrailerDesc {
padding-top: 1em;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

View File

@ -208,6 +208,8 @@ browser.jar:
skin/classic/browser/tabbrowser/tab-background-end@2x.png (tabbrowser/tab-background-end@2x.png)
skin/classic/browser/tabbrowser/tab-overflow-indicator.png (../shared/tabbrowser/tab-overflow-indicator.png)
skin/classic/browser/tabbrowser/pendingpaint.png (../shared/tabbrowser/pendingpaint.png)
# NOTE: The following two files (tab-selected-end.svg, tab-selected-start.svg) get pre-processed in
# Makefile.in with a non-default marker of "%" and the result of that gets packaged.
skin/classic/browser/tabbrowser/tab-selected-end.svg (tab-selected-end.svg)

View File

@ -61,6 +61,9 @@ ROBOCOP_FILES := \
$(wildcard $(TESTPATH)/test*.js) \
$(wildcard $(TESTPATH)/robocop*.js) \
$(wildcard $(TESTPATH)/*.xml) \
$(wildcard $(TESTPATH)/*.ogg) \
$(wildcard $(TESTPATH)/*.mp4) \
$(wildcard $(TESTPATH)/*.webm) \
$(wildcard $(TESTPATH)/*.swf) \
$(NULL)

View File

@ -107,6 +107,7 @@ function _setAppProperties(aObj, aApp) {
aObj.redirects = aApp.redirects;
aObj.widgetPages = aApp.widgetPages || [];
aObj.kind = aApp.kind;
aObj.enabled = aApp.enabled !== undefined ? aApp.enabled : true;
}
this.AppsUtils = {

View File

@ -424,6 +424,10 @@ WebappsApplication.prototype = {
return new this._window.DOMError(this._proxy.downloadError);
},
get enabled() {
return this._proxy.enabled;
},
download: function() {
cpmm.sendAsyncMessage("Webapps:Download",
{ manifestURL: this.manifestURL });
@ -613,7 +617,7 @@ WebappsApplication.prototype = {
case "Webapps:Launch:Return:KO":
this.removeMessageListeners(["Webapps:Launch:Return:OK",
"Webapps:Launch:Return:KO"]);
Services.DOMRequest.fireError(req, "APP_INSTALL_PENDING");
Services.DOMRequest.fireError(req, msg.error);
break;
case "Webapps:Launch:Return:OK":
this.removeMessageListeners(["Webapps:Launch:Return:OK",
@ -722,12 +726,14 @@ WebappsApplicationMgmt.prototype = {
"Webapps:Install:Return:OK",
"Webapps:GetNotInstalled:Return:OK",
"Webapps:Import:Return",
"Webapps:ExtractManifest:Return"]);
"Webapps:ExtractManifest:Return",
"Webapps:SetEnabled:Return"]);
cpmm.sendAsyncMessage("Webapps:RegisterForMessages",
{
messages: ["Webapps:Install:Return:OK",
"Webapps:Uninstall:Return:OK",
"Webapps:Uninstall:Broadcast:Return:OK"]
"Webapps:Uninstall:Broadcast:Return:OK",
"Webapps:SetEnabled:Return"]
}
);
},
@ -736,7 +742,8 @@ WebappsApplicationMgmt.prototype = {
cpmm.sendAsyncMessage("Webapps:UnregisterForMessages",
["Webapps:Install:Return:OK",
"Webapps:Uninstall:Return:OK",
"Webapps:Uninstall:Broadcast:Return:OK"]);
"Webapps:Uninstall:Broadcast:Return:OK",
"Webapps:SetEnabled:Return"]);
},
applyDownload: function(aApp) {
@ -804,6 +811,12 @@ WebappsApplicationMgmt.prototype = {
});
},
setEnabled: function(aApp, aValue) {
cpmm.sendAsyncMessage("Webapps:SetEnabled",
{ manifestURL: aApp.manifestURL,
enabled: aValue });
},
get oninstall() {
return this.__DOM_IMPL__.getEventHandler("oninstall");
},
@ -812,6 +825,10 @@ WebappsApplicationMgmt.prototype = {
return this.__DOM_IMPL__.getEventHandler("onuninstall");
},
get onenabledstatechange() {
return this.__DOM_IMPL__.getEventHandler("onenabledstatechange");
},
set oninstall(aCallback) {
this.__DOM_IMPL__.setEventHandler("oninstall", aCallback);
},
@ -820,9 +837,14 @@ WebappsApplicationMgmt.prototype = {
this.__DOM_IMPL__.setEventHandler("onuninstall", aCallback);
},
set onenabledstatechange(aCallback) {
this.__DOM_IMPL__.setEventHandler("onenabledstatechange", aCallback);
},
receiveMessage: function(aMessage) {
let msg = aMessage.data;
let req;
if (["Webapps:Import:Return",
"Webapps:ExtractManifest:Return"]
.indexOf(aMessage.name) != -1) {
@ -831,11 +853,13 @@ WebappsApplicationMgmt.prototype = {
req = this.getRequest(msg.requestID);
}
// We want Webapps:Install:Return:OK and Webapps:Uninstall:Broadcast:Return:OK
// We want Webapps:Install:Return:OK, Webapps:Uninstall:Broadcast:Return:OK
// and Webapps:SetEnabled:Return
// to be broadcasted to all instances of mozApps.mgmt.
if (!((msg.oid == this._id && req) ||
aMessage.name == "Webapps:Install:Return:OK" ||
aMessage.name == "Webapps:Uninstall:Broadcast:Return:OK")) {
aMessage.name == "Webapps:Uninstall:Broadcast:Return:OK" ||
aMessage.name == "Webapps:SetEnabled:Return")) {
return;
}
@ -879,6 +903,14 @@ WebappsApplicationMgmt.prototype = {
req.reject(new this._window.DOMError(msg.error || ""));
}
break;
case "Webapps:SetEnabled:Return":
{
let app = createContentApplicationObject(this._window, msg);
let event =
new this._window.MozApplicationEvent("enabledstatechange", { application : app });
this.__DOM_IMPL__.dispatchEvent(event);
}
break;
}
if (aMessage.name !== "Webapps:Uninstall:Broadcast:Return:OK") {
this.removeRequest(msg.requestID);

View File

@ -173,20 +173,30 @@ this.DOMApplicationRegistry = {
dirKey: DIRECTORY_NAME,
init: function() {
this.messages = ["Webapps:Install", "Webapps:Uninstall",
"Webapps:GetSelf", "Webapps:CheckInstalled",
"Webapps:GetInstalled", "Webapps:GetNotInstalled",
this.messages = ["Webapps:Install",
"Webapps:Uninstall",
"Webapps:GetSelf",
"Webapps:CheckInstalled",
"Webapps:GetInstalled",
"Webapps:GetNotInstalled",
"Webapps:Launch",
"Webapps:InstallPackage",
"Webapps:GetList", "Webapps:RegisterForMessages",
"Webapps:GetList",
"Webapps:RegisterForMessages",
"Webapps:UnregisterForMessages",
"Webapps:CancelDownload", "Webapps:CheckForUpdate",
"Webapps:Download", "Webapps:ApplyDownload",
"Webapps:Install:Return:Ack", "Webapps:AddReceipt",
"Webapps:RemoveReceipt", "Webapps:ReplaceReceipt",
"Webapps:CancelDownload",
"Webapps:CheckForUpdate",
"Webapps:Download",
"Webapps:ApplyDownload",
"Webapps:Install:Return:Ack",
"Webapps:AddReceipt",
"Webapps:RemoveReceipt",
"Webapps:ReplaceReceipt",
"Webapps:RegisterBEP",
"Webapps:Export", "Webapps:Import",
"Webapps:Export",
"Webapps:Import",
"Webapps:ExtractManifest",
"Webapps:SetEnabled",
"child-process-shutdown"];
this.frameMessages = ["Webapps:ClearBrowserData"];
@ -283,6 +293,10 @@ this.DOMApplicationRegistry = {
continue;
}
if (app.enabled === undefined) {
app.enabled = true;
}
// At startup we can't be downloading, and the $TMP directory
// will be empty so we can't just apply a staged update.
app.downloading = false;
@ -1181,13 +1195,14 @@ this.DOMApplicationRegistry = {
Services.prefs.setBoolPref("dom.mozApps.used", true);
// We need to check permissions for calls coming from mozApps.mgmt.
// These are: getNotInstalled(), applyDownload(), uninstall(), import() and
// extractManifest().
// These are: getNotInstalled(), applyDownload(), uninstall(), import(),
// extractManifest(), setEnabled().
if (["Webapps:GetNotInstalled",
"Webapps:ApplyDownload",
"Webapps:Uninstall",
"Webapps:Import",
"Webapps:ExtractManifest"].indexOf(aMessage.name) != -1) {
"Webapps:ExtractManifest",
"Webapps:SetEnabled"].indexOf(aMessage.name) != -1) {
if (!aMessage.target.assertPermission("webapps-manage")) {
debug("mozApps message " + aMessage.name +
" from a content process with no 'webapps-manage' privileges.");
@ -1322,6 +1337,9 @@ this.DOMApplicationRegistry = {
case "Webapps:ExtractManifest":
this.doExtractManifest(msg, mm);
break;
case "Webapps:SetEnabled":
this.setEnabled(msg);
break;
}
});
},
@ -1534,6 +1552,7 @@ this.DOMApplicationRegistry = {
aMm.sendAsyncMessage("Webapps:Launch:Return:OK", aData);
},
function onfailure(reason) {
aData.error = reason;
aMm.sendAsyncMessage("Webapps:Launch:Return:KO", aData);
}
);
@ -4299,6 +4318,25 @@ this.DOMApplicationRegistry = {
});
},
setEnabled: function(aData) {
debug("setEnabled " + aData.manifestURL + " : " + aData.enabled);
let id = this._appIdForManifestURL(aData.manifestURL);
if (!id || !this.webapps[id]) {
return;
}
debug("Enabling " + id);
let app = this.webapps[id];
app.enabled = aData.enabled;
this._saveApps().then(() => {
DOMApplicationRegistry.broadcastMessage("Webapps:UpdateState", {
app: app,
id: app.id
});
this.broadcastMessage("Webapps:SetEnabled:Return", app);
});
},
getManifestFor: function(aManifestURL) {
let id = this._appIdForManifestURL(aManifestURL);
let app = this.webapps[id];

View File

@ -22,6 +22,7 @@ support-files =
marketplace/*
pkg_install_iframe.html
[test_app_enabled.html]
[test_app_update.html]
[test_bug_795164.html]
[test_import_export.html]

View File

@ -0,0 +1,129 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id={1XXXXXX}
-->
<head>
<title>Test for Bug {1072090}</title>
<script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id={1072090}">Mozilla Bug {1072090}</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
var gManifestURL = "http://test/tests/dom/apps/tests/file_app.sjs?apptype=hosted&getmanifest=true";
var gGenerator = runTest();
function go() {
SpecialPowers.pushPermissions(
[{ "type": "webapps-manage", "allow": 1, "context": document }],
function() { gGenerator.next() });
}
function continueTest() {
try {
gGenerator.next();
} catch (e if e instanceof StopIteration) {
finish();
}
}
function finish() {
SimpleTest.finish();
}
function cbError(aEvent) {
ok(false, "Error callback invoked " +
aEvent.target.error.name + " " + aEvent.target.error.message);
finish();
}
SimpleTest.waitForExplicitFinish();
/**
* Flip the `enabled` state of an app back and forth.
*/
function runTest() {
SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.autoConfirmAppInstall(continueTest);
yield undefined;
SpecialPowers.autoConfirmAppUninstall(continueTest);
yield undefined;
request = navigator.mozApps.mgmt.getAll();
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var initialAppsCount = request.result.length;
info("Starting with " + initialAppsCount + " apps installed.");
var request = navigator.mozApps.install(gManifestURL, { });
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
var app = request.result;
ok(app, "App is non-null");
is(app.manifestURL, gManifestURL, "App manifest url is correct.");
is(app.enabled, true, "App is enabled by default after install.");
// Switch the app to disabled.
navigator.mozApps.mgmt.onenabledstatechange = function(event) {
ok(true, "onenabledstatechange received");
is(event.application.enabled, false, "Application is disabled");
is(app.enabled, false, "Application is disabled");
continueTest();
}
navigator.mozApps.mgmt.setEnabled(app, false);
yield undefined;
// Re-enable the app.
navigator.mozApps.mgmt.onenabledstatechange = function(event) {
ok(true, "onenabledstatechange received");
is(event.application.enabled, true, "Application is enabled");
is(app.enabled, true, "Application is enabled");
continueTest();
}
navigator.mozApps.mgmt.setEnabled(app, true);
yield undefined;
navigator.mozApps.mgmt.onuninstall = function(event) {
var app = event.application;
is(app.manifestURL, gManifestURL, "App uninstall event ok.");
is(app.manifest.name, "Really Rapid Release (hosted)",
"App uninstall manifest ok.");
continueTest();
}
request = navigator.mozApps.mgmt.uninstall(app);
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
yield undefined;
is(request.result, gManifestURL, "App uninstalled.");
navigator.mozApps.mgmt.onuninstall = null;
request = navigator.mozApps.mgmt.getAll();
request.onerror = cbError;
request.onsuccess = continueTest;
yield undefined;
is(request.result.length, initialAppsCount, "All apps are uninstalled.");
}
addLoadEvent(go);
</script>
</pre>
</body>
</html>

View File

@ -77,7 +77,7 @@ function cbError(aEvent) {
SimpleTest.waitForExplicitFinish();
/**
* Install 2 apps from the same origin and uninstall them.
* Test exporting and importing hosted and packaged apps.
*/
function runTest() {
SpecialPowers.setAllAppsLaunchable(true);

View File

@ -17,6 +17,16 @@ ASSERT_NETWORK_SELECTION_MODE_EQUALITY(Manual, NETWORK_SELECTION_MODE_MANUAL);
#undef ASSERT_NETWORK_SELECTION_MODE_EQUALITY
#define ASSERT_MOBILE_RADIO_STATE_EQUALITY(webidlState, xpidlState) \
static_assert(static_cast<int32_t>(MobileRadioState::webidlState) == nsIMobileConnection::xpidlState, \
"MobileRadioState::" #webidlState " should equal to nsIMobileConnection::" #xpidlState)
ASSERT_MOBILE_RADIO_STATE_EQUALITY(Enabling, MOBILE_RADIO_STATE_ENABLING);
ASSERT_MOBILE_RADIO_STATE_EQUALITY(Enabled, MOBILE_RADIO_STATE_ENABLED);
ASSERT_MOBILE_RADIO_STATE_EQUALITY(Disabling, MOBILE_RADIO_STATE_DISABLING);
ASSERT_MOBILE_RADIO_STATE_EQUALITY(Disabled, MOBILE_RADIO_STATE_DISABLED);
#undef ASSERT_MOBILE_RADIO_STATE_EQUALITY
} // namespace dom
} // namespace mozilla

View File

@ -368,9 +368,12 @@ MobileConnection::GetRadioState() const
return retVal;
}
nsAutoString state;
mMobileConnection->GetRadioState(state);
CONVERT_STRING_TO_NULLABLE_ENUM(state, MobileRadioState, retVal);
int32_t state = nsIMobileConnection::MOBILE_RADIO_STATE_UNKNOWN;
if (NS_SUCCEEDED(mMobileConnection->GetRadioState(&state)) &&
state != nsIMobileConnection::MOBILE_RADIO_STATE_UNKNOWN) {
MOZ_ASSERT(state < static_cast<int32_t>(MobileRadioState::EndGuard_));
retVal.SetValue(static_cast<MobileRadioState>(state));
}
return retVal;
}

View File

@ -379,7 +379,7 @@ MobileConnectionProvider.prototype = {
data: null,
iccId: null,
networkSelectionMode: Ci.nsIMobileConnection.NETWORK_SELECTION_MODE_UNKNOWN,
radioState: null,
radioState: Ci.nsIMobileConnection.MOBILE_RADIO_STATE_UNKNOWN,
lastKnownNetwork: null,
lastKnownHomeNetwork: null,
supportedNetworkTypes: null,
@ -743,7 +743,7 @@ MobileConnectionProvider.prototype = {
},
setPreferredNetworkType: function(aType, aCallback) {
if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) {
if (this.radioState !== Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED) {
this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE);
return;
}
@ -762,7 +762,7 @@ MobileConnectionProvider.prototype = {
},
getPreferredNetworkType: function(aCallback) {
if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) {
if (this.radioState !== Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED) {
this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE);
return;
}
@ -984,7 +984,7 @@ MobileConnectionProvider.prototype = {
return;
}
if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) {
if (this.radioState !== Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED) {
this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE);
return;
}
@ -1003,7 +1003,7 @@ MobileConnectionProvider.prototype = {
},
getCallingLineIdRestriction: function(aCallback) {
if (this.radioState !== RIL.GECKO_RADIOSTATE_ENABLED) {
if (this.radioState !== Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED) {
this._dispatchNotifyError(aCallback, RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE);
return;
}

View File

@ -9,7 +9,7 @@
"@mozilla.org/mobileconnection/gonkmobileconnectionservice;1"
%}
[scriptable, uuid(2d574f0e-4a02-11e4-b1b3-cbc14b7608ce)]
[scriptable, uuid(7322619d-9abd-4410-99ce-207da80f9879)]
interface nsIGonkMobileConnectionService : nsIMobileConnectionService
{
void notifyNetworkInfoChanged(in unsigned long clientId, in jsval networkInfo);
@ -27,7 +27,7 @@ interface nsIGonkMobileConnectionService : nsIMobileConnectionService
void notifyOtaStatusChanged(in unsigned long clientId, in DOMString status);
void notifyRadioStateChanged(in unsigned long clientId,
in DOMString radioState);
in long radioState);
void notifyUssdReceived(in unsigned long clientId,
in DOMString message,

View File

@ -236,7 +236,7 @@ already_AddRefed<nsIMobileConnectionService>
NS_CreateMobileConnectionService();
%}
[scriptable, uuid(cfc7d15b-d2c2-4f28-ad9f-b250030c3073)]
[scriptable, uuid(99818dc7-e770-4249-87e2-2de0a928ed08)]
interface nsIMobileConnection : nsISupports
{
/*
@ -304,6 +304,15 @@ interface nsIMobileConnection : nsISupports
const long NETWORK_SELECTION_MODE_AUTOMATIC = 0;
const long NETWORK_SELECTION_MODE_MANUAL = 1;
/**
* Mobile Radio State.
*/
const long MOBILE_RADIO_STATE_UNKNOWN = -1;
const long MOBILE_RADIO_STATE_ENABLING = 0;
const long MOBILE_RADIO_STATE_ENABLED = 1;
const long MOBILE_RADIO_STATE_DISABLING = 2;
const long MOBILE_RADIO_STATE_DISABLED = 3;
readonly attribute unsigned long serviceId;
/**
@ -347,10 +356,10 @@ interface nsIMobileConnection : nsISupports
readonly attribute long networkSelectionMode;
/**
* Current radio state. Possible values are 'enabling', 'enabled',
* 'disabling', 'disabled', null (unknown).
* Current radio state. One of the nsIMobileConnection.MOBILE_RADIO_STATE_*
* values.
*/
readonly attribute DOMString radioState;
readonly attribute long radioState;
/**
* The network types supported by this radio.

View File

@ -106,9 +106,9 @@ MobileConnectionChild::GetIccId(nsAString& aIccId)
}
NS_IMETHODIMP
MobileConnectionChild::GetRadioState(nsAString& aRadioState)
MobileConnectionChild::GetRadioState(int32_t* aRadioState)
{
aRadioState = mRadioState;
*aRadioState = mRadioState;
return NS_OK;
}
@ -488,9 +488,9 @@ MobileConnectionChild::RecvNotifyIccChanged(const nsString& aIccId)
}
bool
MobileConnectionChild::RecvNotifyRadioStateChanged(const nsString& aRadioState)
MobileConnectionChild::RecvNotifyRadioStateChanged(const int32_t& aRadioState)
{
mRadioState.Assign(aRadioState);
mRadioState = aRadioState;
for (int32_t i = 0; i < mListeners.Count(); i++) {
mListeners[i]->NotifyRadioStateChanged();

View File

@ -92,7 +92,7 @@ protected:
RecvNotifyIccChanged(const nsString& aIccId) MOZ_OVERRIDE;
virtual bool
RecvNotifyRadioStateChanged(const nsString& aRadioState) MOZ_OVERRIDE;
RecvNotifyRadioStateChanged(const int32_t& aRadioState) MOZ_OVERRIDE;
virtual bool
RecvNotifyClirModeChanged(const uint32_t& aMode) MOZ_OVERRIDE;
@ -113,7 +113,7 @@ private:
nsRefPtr<MobileConnectionInfo> mVoice;
nsRefPtr<MobileConnectionInfo> mData;
nsString mIccId;
nsString mRadioState;
int32_t mRadioState;
nsString mLastNetwork;
nsString mLastHomeNetwork;
int32_t mNetworkSelectionMode;

View File

@ -130,7 +130,7 @@ MobileConnectionParent::RecvInit(nsMobileConnectionInfo* aVoice,
nsString* aLastKnownHomeNetwork,
nsString* aIccId,
int32_t* aNetworkSelectionMode,
nsString* aRadioState,
int32_t* aRadioState,
nsTArray<nsString>* aSupportedNetworkTypes)
{
NS_ENSURE_TRUE(mMobileConnection, false);
@ -141,7 +141,7 @@ MobileConnectionParent::RecvInit(nsMobileConnectionInfo* aVoice,
NS_ENSURE_SUCCESS(mMobileConnection->GetLastKnownHomeNetwork(*aLastKnownHomeNetwork), false);
NS_ENSURE_SUCCESS(mMobileConnection->GetIccId(*aIccId), false);
NS_ENSURE_SUCCESS(mMobileConnection->GetNetworkSelectionMode(aNetworkSelectionMode), false);
NS_ENSURE_SUCCESS(mMobileConnection->GetRadioState(*aRadioState), false);
NS_ENSURE_SUCCESS(mMobileConnection->GetRadioState(aRadioState), false);
char16_t** types = nullptr;
uint32_t length = 0;
@ -262,8 +262,8 @@ MobileConnectionParent::NotifyRadioStateChanged()
NS_ENSURE_TRUE(mLive, NS_ERROR_FAILURE);
nsresult rv;
nsAutoString radioState;
rv = mMobileConnection->GetRadioState(radioState);
int32_t radioState;
rv = mMobileConnection->GetRadioState(&radioState);
NS_ENSURE_SUCCESS(rv, rv);
return SendNotifyRadioStateChanged(radioState) ? NS_OK : NS_ERROR_FAILURE;

View File

@ -52,7 +52,7 @@ protected:
RecvInit(nsMobileConnectionInfo* aVoice, nsMobileConnectionInfo* aData,
nsString* aLastKnownNetwork, nsString* aLastKnownHomeNetwork,
nsString* aIccId, int32_t* aNetworkSelectionMode,
nsString* aRadioState, nsTArray<nsString>* aSupportedNetworkTypes) MOZ_OVERRIDE;
int32_t* aRadioState, nsTArray<nsString>* aSupportedNetworkTypes) MOZ_OVERRIDE;
private:
nsCOMPtr<nsIMobileConnection> mMobileConnection;

View File

@ -28,7 +28,7 @@ child:
NotifyEmergencyCbModeChanged(bool aActive, uint32_t aTimeoutMs);
NotifyOtaStatusChanged(nsString aStatus);
NotifyIccChanged(nsString aIccId);
NotifyRadioStateChanged(nsString aRadioState);
NotifyRadioStateChanged(int32_t aRadioState);
NotifyClirModeChanged(uint32_t aMode);
NotifyLastNetworkChanged(nsString aNetwork);
NotifyLastHomeNetworkChanged(nsString aNetwork);
@ -52,7 +52,7 @@ parent:
returns (nsMobileConnectionInfo aVoice, nsMobileConnectionInfo aData,
nsString aLastKnownNetwork, nsString aLastKnownHomeNetwork,
nsString aIccId, int32_t aNetworkSelectionMode,
nsString aRadioState, nsString[] aSupportedNetworkTypes);
int32_t aRadioState, nsString[] aSupportedNetworkTypes);
};
/**

View File

@ -504,13 +504,15 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() {
},
_isValidStateForSetRadioEnabled: function(radioState) {
return radioState == RIL.GECKO_RADIOSTATE_ENABLED ||
radioState == RIL.GECKO_RADIOSTATE_DISABLED;
return radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED ||
radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED;
},
_isDummyForSetRadioEnabled: function(radioState, data) {
return (radioState == RIL.GECKO_RADIOSTATE_ENABLED && data.enabled) ||
(radioState == RIL.GECKO_RADIOSTATE_DISABLED && !data.enabled);
return (radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED &&
data.enabled) ||
(radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED &&
!data.enabled);
},
_handleMessage: function(message) {
@ -573,15 +575,15 @@ XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() {
let radioInterface = _ril.getRadioInterface(clientId);
this.notifyRadioStateChanged(clientId,
enabled ? RIL.GECKO_RADIOSTATE_ENABLING
: RIL.GECKO_RADIOSTATE_DISABLING);
enabled ? Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLING
: Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLING);
radioInterface.workerMessenger.send("setRadioEnabled", message.data,
(function(response) {
if (response.errorMsg) {
// Request fails. Rollback to the original radioState.
this.notifyRadioStateChanged(clientId,
enabled ? RIL.GECKO_RADIOSTATE_DISABLED
: RIL.GECKO_RADIOSTATE_ENABLED);
enabled ? Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED
: Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED);
}
message.callback(response);
return false;
@ -1197,7 +1199,7 @@ DataConnectionHandler.prototype = {
// This check avoids data call connection if the radio is not ready
// yet after toggling off airplane mode.
let radioState = connection && connection.radioState;
if (radioState != RIL.GECKO_RADIOSTATE_ENABLED) {
if (radioState != Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED) {
if (DEBUG) {
this.debug("RIL is not ready for data connection: radio's not ready");
}
@ -3525,8 +3527,8 @@ RadioInterface.prototype = {
if (DEBUG) this.debug("Error! Address is invalid when sending SMS: " +
options.number);
errorCode = Ci.nsIMobileMessageCallback.INVALID_ADDRESS_ERROR;
} else if (radioState == null ||
radioState == RIL.GECKO_RADIOSTATE_DISABLED) {
} else if (radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_UNKNOWN ||
radioState == Ci.nsIMobileConnection.MOBILE_RADIO_STATE_DISABLED) {
if (DEBUG) this.debug("Error! Radio is disabled when sending SMS.");
errorCode = Ci.nsIMobileMessageCallback.RADIO_DISABLED_ERROR;
} else if (this.rilContext.cardState != Ci.nsIIccProvider.CARD_STATE_READY) {

View File

@ -2490,12 +2490,12 @@ this.CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242;
this.CALL_FAIL_IMEI_NOT_ACCEPTED = 243;
this.CALL_FAIL_ERROR_UNSPECIFIED = 0xffff;
// Other Gecko-specific constants
this.GECKO_RADIOSTATE_UNKNOWN = null;
this.GECKO_RADIOSTATE_ENABLING = "enabling";
this.GECKO_RADIOSTATE_ENABLED = "enabled";
this.GECKO_RADIOSTATE_DISABLING = "disabling";
this.GECKO_RADIOSTATE_DISABLED = "disabled";
// See nsIMobileConnection::MOBILE_RADIO_STATE_*
this.GECKO_RADIOSTATE_UNKNOWN = -1;
this.GECKO_RADIOSTATE_ENABLING = 0;
this.GECKO_RADIOSTATE_ENABLED = 1;
this.GECKO_RADIOSTATE_DISABLING = 2;
this.GECKO_RADIOSTATE_DISABLED = 3;
// Only used in ril_worker.js
this.GECKO_CARDSTATE_UNINITIALIZED = 4294967294; // UINT32_MAX - 1

View File

@ -44,11 +44,13 @@ var mgmtProps = {
uninstall: "function",
oninstall: "object",
onuninstall: "object",
onenabledstatechange: "object",
ownerGlobal: "object",
removeEventListener: "function",
setEventHandler: "function",
extractManifest: "function",
import: "function"
import: "function",
setEnabled: "function"
};
isDeeply([p for (p in navigator.mozApps.mgmt)].sort(),

View File

@ -32,6 +32,7 @@ interface DOMApplication : EventTarget {
readonly attribute DOMString installOrigin;
readonly attribute DOMTimeStamp installTime;
readonly attribute boolean removable;
readonly attribute boolean enabled;
[Cached, Pure]
readonly attribute sequence<DOMString> receipts;
@ -96,6 +97,9 @@ interface DOMApplicationsManager : EventTarget {
Promise<DOMApplication> import(Blob blob);
Promise<any> extractManifest(Blob blob);
void setEnabled(DOMApplication app, boolean state);
attribute EventHandler oninstall;
attribute EventHandler onuninstall;
attribute EventHandler onenabledstatechange;
};

View File

@ -1347,6 +1347,7 @@ ParentImpl::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
{
AssertIsInMainProcess();
AssertIsOnMainThread();
MOZ_ASSERT(aCtx->GetContentParent());
const ProtocolId protocolId = GetProtocolId();
@ -1363,7 +1364,7 @@ ParentImpl::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
}
PBackgroundParent* clonedActor =
Alloc(mContent, transport, base::GetProcId(aPeerProcess));
Alloc(aCtx->GetContentParent(), transport, base::GetProcId(aPeerProcess));
MOZ_ASSERT(clonedActor);
clonedActor->CloneManagees(this, aCtx);

View File

@ -19,6 +19,7 @@ import java.util.UUID;
import java.util.regex.Pattern;
import org.json.JSONObject;
import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.util.ThreadUtils;
import android.content.BroadcastReceiver;
@ -134,6 +135,13 @@ public final class ANRReporter extends BroadcastReceiver
// Return the "traces.txt" file, or null if there is no such file
private static File getTracesFile() {
// Check most common location first.
File tracesFile = new File("/data/anr/traces.txt");
if (tracesFile.isFile() && tracesFile.canRead()) {
return tracesFile;
}
// Find the traces file name if we can.
try {
// getprop [prop-name [default-value]]
Process propProc = (new ProcessBuilder())
@ -150,7 +158,7 @@ public final class ANRReporter extends BroadcastReceiver
// getprop can return empty string when the prop value is empty
// or prop is undefined, treat both cases the same way
if (propVal != null && propVal.length() != 0) {
File tracesFile = new File(propVal);
tracesFile = new File(propVal);
if (tracesFile.isFile() && tracesFile.canRead()) {
return tracesFile;
} else if (DEBUG) {
@ -167,11 +175,6 @@ public final class ANRReporter extends BroadcastReceiver
} catch (ClassCastException e) {
Log.w(LOGTAG, e); // Bug 975436
}
// Check most common location one last time just in case
File tracesFile = new File("/data/anr/traces.txt");
if (tracesFile.isFile() && tracesFile.canRead()) {
return tracesFile;
}
return null;
}
@ -407,14 +410,11 @@ public final class ANRReporter extends BroadcastReceiver
return total;
}
private static void fillPingFooter(OutputStream ping,
boolean haveNativeStack)
throws IOException {
// We are at the end of ANR data
int total = writePingPayload(ping, ("\"," +
"\"androidLogcat\":\""));
private static void fillLogcat(final OutputStream ping) {
if (Versions.preJB) {
// Logcat retrieval is not supported on pre-JB devices.
return;
}
try {
// get the last 200 lines of logcat
@ -435,6 +435,17 @@ public final class ANRReporter extends BroadcastReceiver
// ignore because logcat is not essential
Log.w(LOGTAG, e);
}
}
private static void fillPingFooter(OutputStream ping,
boolean haveNativeStack)
throws IOException {
// We are at the end of ANR data
int total = writePingPayload(ping, ("\"," +
"\"androidLogcat\":\""));
fillLogcat(ping);
if (haveNativeStack) {
total += writePingPayload(ping, ("\"," +

View File

@ -501,6 +501,7 @@ public class BrowserApp extends GeckoApp
mMediaCastingBar = (MediaCastingBar) findViewById(R.id.media_casting);
EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener)this,
"Menu:Open",
"Menu:Update",
"Search:Keyword",
"Prompt:ShowTop",
@ -1047,6 +1048,7 @@ public class BrowserApp extends GeckoApp
}
EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener)this,
"Menu:Open",
"Menu:Update",
"Search:Keyword",
"Prompt:ShowTop",
@ -1482,7 +1484,13 @@ public class BrowserApp extends GeckoApp
@Override
public void handleMessage(String event, JSONObject message) {
try {
if (event.equals("Menu:Update")) {
if (event.equals("Menu:Open")) {
if (mBrowserToolbar.isEditing()) {
mBrowserToolbar.cancelEdit();
}
openOptionsMenu();
} else if (event.equals("Menu:Update")) {
final int id = message.getInt("id") + ADDON_MENU_OFFSET;
final JSONObject options = message.getJSONObject("options");
ThreadUtils.postToUiThread(new Runnable() {

View File

@ -180,8 +180,10 @@ class CrashHandler implements Thread.UncaughtExceptionHandler {
}
protected String getAppPackageName() {
if (appContext != null) {
return appContext.getPackageName();
final Context context = getAppContext();
if (context != null) {
return context.getPackageName();
}
try {
@ -206,6 +208,10 @@ class CrashHandler implements Thread.UncaughtExceptionHandler {
return getJavaPackageName();
}
protected Context getAppContext() {
return appContext;
}
/**
* Get the crash "extras" to be reported.
*
@ -213,8 +219,8 @@ class CrashHandler implements Thread.UncaughtExceptionHandler {
* @param exc An exception
* @return "Extras" in the from of a Bundle
*/
protected Bundle getCrashExtras(final Thread thread, final Throwable exc,
final Context appContext) {
protected Bundle getCrashExtras(final Thread thread, final Throwable exc) {
final Context context = getAppContext();
final Bundle extras = new Bundle();
final String pkgName = getAppPackageName();
@ -222,8 +228,8 @@ class CrashHandler implements Thread.UncaughtExceptionHandler {
extras.putLong("CrashTime", getCrashTime());
extras.putLong("StartupTime", getStartupTime());
if (appContext != null) {
final PackageManager pkgMgr = appContext.getPackageManager();
if (context != null) {
final PackageManager pkgMgr = context.getPackageManager();
try {
final PackageInfo pkgInfo = pkgMgr.getPackageInfo(pkgName, 0);
extras.putString("Version", pkgInfo.versionName);
@ -277,17 +283,18 @@ class CrashHandler implements Thread.UncaughtExceptionHandler {
*/
protected boolean launchCrashReporter(final String dumpFile, final String extraFile) {
try {
final Context context = getAppContext();
final String javaPkg = getJavaPackageName();
final String pkg = getAppPackageName();
final String component = javaPkg + ".CrashReporter";
final String action = javaPkg + ".reportCrash";
final ProcessBuilder pb;
if (appContext != null) {
if (context != null) {
final Intent intent = new Intent(action);
intent.setComponent(new ComponentName(pkg, component));
intent.putExtra("minidumpPath", dumpFile);
appContext.startActivity(intent);
context.startActivity(intent);
return true;
}
@ -329,12 +336,13 @@ class CrashHandler implements Thread.UncaughtExceptionHandler {
* @return Whether the exception was successfully reported
*/
protected boolean reportException(final Thread thread, final Throwable exc) {
final Context context = getAppContext();
final String id = UUID.randomUUID().toString();
// Use the cache directory under the app directory to store crash files.
final File dir;
if (appContext != null) {
dir = appContext.getCacheDir();
if (context != null) {
dir = context.getCacheDir();
} else {
dir = new File("/data/data/" + getAppPackageName() + "/cache");
}
@ -366,7 +374,7 @@ class CrashHandler implements Thread.UncaughtExceptionHandler {
try {
// Write out crash extra file as text.
final Bundle extras = getCrashExtras(thread, exc, appContext);
final Bundle extras = getCrashExtras(thread, exc);
final String url = getServerUrl(extras);
extras.putString("ServerURL", url);

View File

@ -21,6 +21,8 @@ import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.util.zip.GZIPOutputStream;
import org.mozilla.gecko.AppConstants.Versions;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ProgressDialog;
@ -395,7 +397,7 @@ public class CrashReporter extends Activity
Log.e(LOGTAG, "Exception while sending SDK version 8 keys", ex);
}
sendPart(os, boundary, "Android_Version", Build.VERSION.SDK_INT + " (" + Build.VERSION.CODENAME + ")");
if (Build.VERSION.SDK_INT >= 16 && includeURLCheckbox.isChecked()) {
if (Versions.feature16Plus && includeURLCheckbox.isChecked()) {
sendPart(os, boundary, "Android_Logcat", readLogcat());
}

Some files were not shown because too many files have changed in this diff Show More