From d1c3df037a9545e50d44faafcfad02f96415f36c Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Fri, 12 Jul 2013 04:50:23 -0700 Subject: [PATCH 01/30] Bumping gaia.json for 2 gaia-central revision(s) ======== https://hg.mozilla.org/integration/gaia-central/rev/8c6337a829ab Author: Dale Harvey Desc: Merge pull request #10905 from huchengtw-moz/video/Bug_889191_using_videojs_for_playing_bluetooth_files Bug 889191 - [Video] video player shows spinner for the few events when. r=daleharvey ======== https://hg.mozilla.org/integration/gaia-central/rev/718d60470bfd Author: John Hu Desc: Bug 889191 - [Video] video player shows spinner for the few events when playing local file. --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 80674f70e1da..e2733ce89f25 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "8f402e9a5c9a8ba8b5b7d6345952fbb5a7db2d69", + "revision": "8c6337a829abaf74de9db4bbb019da1b2e51c1c7", "repo_path": "/integration/gaia-central" } From 42835bb35fd4801b18a811e8d90d549595fcc973 Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Fri, 12 Jul 2013 05:15:23 -0700 Subject: [PATCH 02/30] Bumping gaia.json for 2 gaia-central revision(s) ======== https://hg.mozilla.org/integration/gaia-central/rev/1cccf057956b Author: Francisco Borja Salguero Castellano Desc: Merge pull request #10898 from arcturus/bug-890206 Bug 890206 - [SMS] Messages dissapear from the thread when trying to re-send a failed message ======== https://hg.mozilla.org/integration/gaia-central/rev/dacf73ce8f65 Author: Francisco Jordano Desc: Bug 890206 - [SMS] Messages dissapear from the thread when trying to re-send a failed message --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index e2733ce89f25..e1dc6cc45c63 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "8c6337a829abaf74de9db4bbb019da1b2e51c1c7", + "revision": "1cccf057956b73e8f10a88e2d2e25e36ec5abd7e", "repo_path": "/integration/gaia-central" } From 7fc6c2c678523c10c7d4648a77fa08e61df4ffe2 Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Fri, 12 Jul 2013 05:25:26 -0700 Subject: [PATCH 03/30] Bumping gaia.json for 2 gaia-central revision(s) ======== https://hg.mozilla.org/integration/gaia-central/rev/69c79383c797 Author: Timothy Guan-tin Chien Desc: Merge pull request #10777 from gasolin/master-881136 Bug 881136 - hdpi/xhdpi resolution assets and layout for Browser app, r=dale ======== https://hg.mozilla.org/integration/gaia-central/rev/130d7b0f10fb Author: gasolin Desc: Bug 881136 - hdpi/xhdpi resolution assets and layout for Browser app --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index e1dc6cc45c63..963604fc9b5e 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "1cccf057956b73e8f10a88e2d2e25e36ec5abd7e", + "revision": "69c79383c79720c8e8e27e364db377858885376d", "repo_path": "/integration/gaia-central" } From bb8a41a5df85d4b9914091d0c96323c94b9ae1ff Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Fri, 12 Jul 2013 05:45:23 -0700 Subject: [PATCH 04/30] Bumping gaia.json for 2 gaia-central revision(s) ======== https://hg.mozilla.org/integration/gaia-central/rev/de71fa3f7ac4 Author: Francisco Borja Salguero Castellano Desc: Merge pull request #10941 from julienw/890460-fixedheader-followup Bug 890460 - [SMS] After deleting all the messages in particular thread,... ======== https://hg.mozilla.org/integration/gaia-central/rev/cfd7cefd6d22 Author: Julien Wajsberg Desc: Bug 890460 - [SMS] After deleting all the messages in particular thread,the 'TODAY' bar still exists in thread_list r=borja Ensure FixedHeader.refresh is called when rendering an empty screen --- b2g/config/gaia.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/config/gaia.json b/b2g/config/gaia.json index 963604fc9b5e..48855b23f4e7 100644 --- a/b2g/config/gaia.json +++ b/b2g/config/gaia.json @@ -1,4 +1,4 @@ { - "revision": "69c79383c79720c8e8e27e364db377858885376d", + "revision": "de71fa3f7ac4fa32ed961b46d5cbbcbb6cf0de2f", "repo_path": "/integration/gaia-central" } From 396546855e7afde9044932d6bbb588902793922e Mon Sep 17 00:00:00 2001 From: Yuan Xulei Date: Fri, 12 Jul 2013 09:04:05 -0400 Subject: [PATCH 05/30] Bug 883129 - Converts the non-textual element to placeholder character for mozKeyboard. r=hsivonen --- b2g/chrome/content/forms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/b2g/chrome/content/forms.js b/b2g/chrome/content/forms.js index b5ee3b6d0c37..b48f24a214e6 100644 --- a/b2g/chrome/content/forms.js +++ b/b2g/chrome/content/forms.js @@ -675,7 +675,7 @@ function getDocumentEncoder(element) { let flags = Ci.nsIDocumentEncoder.SkipInvisibleContent | Ci.nsIDocumentEncoder.OutputRaw | Ci.nsIDocumentEncoder.OutputLFLineBreak | - Ci.nsIDocumentEncoder.OutputDropInvisibleBreak; + Ci.nsIDocumentEncoder.OutputNonTextContentAsPlaceholder; encoder.init(element.ownerDocument, "text/plain", flags); return encoder; } From 5ec44ef3f67cd6a8d27ed4f2eedacef18dd0adf7 Mon Sep 17 00:00:00 2001 From: Peter Chang Date: Fri, 12 Jul 2013 09:06:26 -0400 Subject: [PATCH 06/30] Bug 885345 - HwcComposer2D doesn't render Camera or Video frames. r=nrc Correct the buffer validation inside GetRenderState() to pass gralloc buffer to composer module --- gfx/layers/opengl/TextureHostOGL.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index 8aea3d6aa4ec..e7a056b1a6fa 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -837,7 +837,7 @@ GrallocDeprecatedTextureHostOGL::SetBuffer(SurfaceDescriptor* aBuffer, ISurfaceA LayerRenderState GrallocDeprecatedTextureHostOGL::GetRenderState() { - if (mBuffer && IsSurfaceDescriptorValid(*mBuffer)) { + if (mGraphicBuffer.get()) { uint32_t flags = mFlags & NeedsYFlip ? LAYER_RENDER_STATE_Y_FLIPPED : 0; @@ -854,8 +854,10 @@ GrallocDeprecatedTextureHostOGL::GetRenderState() flags |= LAYER_RENDER_STATE_FORMAT_RB_SWAP; } + nsIntSize bufferSize(mGraphicBuffer->getWidth(), mGraphicBuffer->getHeight()); + return LayerRenderState(mGraphicBuffer.get(), - mBuffer->get_SurfaceDescriptorGralloc().size(), + bufferSize, flags); } From 2c87ec0cf77835ad381d6a44523e35ec889395f6 Mon Sep 17 00:00:00 2001 From: Tapas Kundu Date: Thu, 11 Jul 2013 14:27:12 -0700 Subject: [PATCH 07/30] Bug 892037 - Update Date/Time even if hardware RTC fails to update. r=mwu --- hal/gonk/GonkHal.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp index 6663f9583f5b..c6681a64f0a2 100644 --- a/hal/gonk/GonkHal.cpp +++ b/hal/gonk/GonkHal.cpp @@ -734,7 +734,6 @@ AdjustSystemClock(int64_t aDeltaMilliseconds) if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) { HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno))); - return; } hal::NotifySystemClockChange(aDeltaMilliseconds); From 75a52316988324e6bd26641dcd7ad451e93119ae Mon Sep 17 00:00:00 2001 From: Ken Chang Date: Fri, 12 Jul 2013 12:44:22 +0800 Subject: [PATCH 08/30] Bug 837488 - B2G RIL: Using array for data call settings and handling multiple sharing on one APN connection. r=hsinyi --- dom/system/gonk/RadioInterfaceLayer.js | 444 ++++++++++++------------- 1 file changed, 217 insertions(+), 227 deletions(-) diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 7946fc2fc7f2..20464a0fa6fa 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -610,12 +610,20 @@ XPCOMUtils.defineLazyGetter(RadioInterfaceLayer.prototype, function RadioInterface(options) { this.clientId = options.clientId; - this.dataCallSettings = {}; - this.dataNetworkInterface = new RILNetworkInterface(this, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE); - this.dataCallSettingsMMS = {}; - this.mmsNetworkInterface = new RILNetworkInterface(this, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS); - this.dataCallSettingsSUPL = {}; - this.suplNetworkInterface = new RILNetworkInterface(this, Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_SUPL); + this.dataCallSettings = { + oldEnabled: false, + enabled: false, + roamingEnabled: false + }; + + // apnSettings is used to keep all APN settings. + // byApn[] makes it easier to get the APN settings via APN, user + // name, and password. + // byType[] makes it easier to get the APN settings via APN types. + this.apnSettings = { + byType: {}, + byAPN: {} + }; if (DEBUG) this.debug("Starting RIL Worker[" + this.clientId + "]"); this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js"); @@ -677,39 +685,9 @@ function RadioInterface(options) { lock.get("ril.radio.preferredNetworkType", this); // Read the APN data from the settings DB. - lock.get("ril.data.apn", this); - lock.get("ril.data.user", this); - lock.get("ril.data.passwd", this); - lock.get("ril.data.authtype", this); - lock.get("ril.data.httpProxyHost", this); - lock.get("ril.data.httpProxyPort", this); lock.get("ril.data.roaming_enabled", this); lock.get("ril.data.enabled", this); - this._dataCallSettingsToRead = ["ril.data.enabled", - "ril.data.roaming_enabled", - "ril.data.apn", - "ril.data.user", - "ril.data.passwd", - "ril.data.authtype", - "ril.data.httpProxyHost", - "ril.data.httpProxyPort"]; - - // Read secondary APNs from the settings DB. - lock.get("ril.mms.apn", this); - lock.get("ril.mms.user", this); - lock.get("ril.mms.passwd", this); - lock.get("ril.mms.authtype", this); - lock.get("ril.mms.httpProxyHost", this); - lock.get("ril.mms.httpProxyPort", this); - lock.get("ril.mms.mmsc", this); - lock.get("ril.mms.mmsproxy", this); - lock.get("ril.mms.mmsport", this); - lock.get("ril.supl.apn", this); - lock.get("ril.supl.user", this); - lock.get("ril.supl.passwd", this); - lock.get("ril.supl.authtype", this); - lock.get("ril.supl.httpProxyHost", this); - lock.get("ril.supl.httpProxyPort", this); + lock.get("ril.data.apnSettings", this); // Read the 'time.nitz.automatic-update.enabled' setting to see if // we need to adjust the system clock time and time zone by NITZ. @@ -1218,8 +1196,12 @@ RadioInterface.prototype = { dataInfo.type = newInfo.type; // For the data connection, the `connected` flag indicates whether // there's an active data call. - dataInfo.connected = (this.getDataCallStateByType("default") == - RIL.GECKO_NETWORK_STATE_CONNECTED); + let apnSetting = this.apnSettings.byType.default; + dataInfo.connected = false; + if (apnSetting) { + dataInfo.connected = (this.getDataCallStateByType("default") == + RIL.GECKO_NETWORK_STATE_CONNECTED); + } // Make sure we also reset the operator and signal strength information // if we drop off the network. @@ -1248,9 +1230,13 @@ RadioInterface.prototype = { */ handleDataCallError: function handleDataCallError(message) { // Notify data call error only for data APN - if (message.apn == this.dataCallSettings.apn) { - gMessageManager.sendMobileConnectionMessage("RIL:DataError", - this.clientId, message); + if (this.apnSettings.byType.default) { + let apnSetting = this.apnSettings.byType.default; + if (message.apn == apnSetting.apn && + apnSetting.iface.inConnectedTypes("default")) { + gMessageManager.sendMobileConnectionMessage("RIL:DataError", + this.clientId, message); + } } this._deliverDataCallCallback("dataCallError", [message]); @@ -1430,11 +1416,85 @@ RadioInterface.prototype = { } }, + /** + * This function will do the following steps: + * 1. Clear the old APN settings. + * 2. Combine APN, user name, and password as the key of byAPN{} and store + * corresponding APN setting into byApn{}, which makes it easiler to get + * the APN setting. + * 3. Use APN type as the index of byType{} and store the link of + * corresponding APN setting into byType{}, which makes it easier to get + * the APN setting via APN types. + */ + updateApnSettings: function updateApnSettings(allApnSettings) { + // TODO: Support multi-SIM, bug 799023. + let simNumber = 1; + for (let simId = 0; simId < simNumber; simId++) { + let thisSimApnSettings = allApnSettings[simId]; + if (!thisSimApnSettings) { + return; + } + + // Clear old APN settings. + for each (let apnSetting in this.apnSettings.byAPN) { + // Clear all connections of this APN settings. + for each (let type in apnSetting.types) { + if (this.getDataCallStateByType(type) == + RIL.GECKO_NETWORK_STATE_CONNECTED) { + this.deactivateDataCallByType(type); + } + } + if (apnSetting.iface.name in gNetworkManager.networkInterfaces) { + gNetworkManager.unregisterNetworkInterface(apnSetting.iface); + } + this.unregisterDataCallCallback(apnSetting.iface); + delete apnSetting.iface; + } + this.apnSettings.byAPN = {}; + this.apnSettings.byType = {}; + + // Create new APN settings. + for (let apnIndex = 0; thisSimApnSettings[apnIndex]; apnIndex++) { + let inputApnSetting = thisSimApnSettings[apnIndex]; + if (!this.validateApnSetting(inputApnSetting)) { + continue; + } + + // Combine APN, user name, and password as the key of byAPN{} to get + // the corresponding APN setting. + let apnKey = inputApnSetting.apn + (inputApnSetting.user || '') + + (inputApnSetting.password || ''); + if (!this.apnSettings.byAPN[apnKey]) { + this.apnSettings.byAPN[apnKey] = {}; + this.apnSettings.byAPN[apnKey] = inputApnSetting; + this.apnSettings.byAPN[apnKey].iface = + new RILNetworkInterface(this, this.apnSettings.byAPN[apnKey]); + } else { + this.apnSettings.byAPN[apnKey].types.push(inputApnSetting.types); + } + for each (let type in inputApnSetting.types) { + this.apnSettings.byType[type] = {}; + this.apnSettings.byType[type] = this.apnSettings.byAPN[apnKey]; + } + } + } + }, + + /** + * Check if we get all necessary APN data. + */ + validateApnSetting: function validateApnSetting(apnSetting) { + return (apnSetting && + apnSetting.apn && + apnSetting.types && + apnSetting.types.length); + }, + updateRILNetworkInterface: function updateRILNetworkInterface() { - if (this._dataCallSettingsToRead.length) { + let apnSetting = this.apnSettings.byType.default; + if (!this.validateApnSetting(apnSetting)) { if (DEBUG) { - this.debug("We haven't read completely the APN data from the " + - "settings DB yet. Wait for that."); + this.debug("We haven't gotten completely the APN data."); } return; } @@ -1453,7 +1513,7 @@ RadioInterface.prototype = { // true and any of the remaining flags change the setting application // should turn this flag to false and then to true in order to reload // the new values and reconnect the data call. - if (this._oldRilDataEnabledState == this.dataCallSettings.enabled) { + if (this.dataCallSettings.oldEnabled == this.dataCallSettings.enabled) { if (DEBUG) { this.debug("No changes for ril.data.enabled flag. Nothing to do."); } @@ -1490,17 +1550,24 @@ RadioInterface.prototype = { let defaultDataCallConnected = defaultDataCallState == RIL.GECKO_NETWORK_STATE_CONNECTED; if (defaultDataCallConnected && - (!this.dataCallSettings.enabled || wifi_active || - (dataInfo.roaming && !this.dataCallSettings.roaming_enabled))) { + (!this.dataCallSettings.enabled || + (dataInfo.roaming && !this.dataCallSettings.roamingEnabled))) { if (DEBUG) this.debug("Data call settings: disconnect data call."); this.deactivateDataCallByType("default"); return; } + + if (defaultDataCallConnected && wifi_active) { + if (DEBUG) this.debug("Disconnect data call when Wifi is connected."); + this.deactivateDataCallByType("default"); + return; + } + if (!this.dataCallSettings.enabled || defaultDataCallConnected) { if (DEBUG) this.debug("Data call settings: nothing to do."); return; } - if (dataInfo.roaming && !this.dataCallSettings.roaming_enabled) { + if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) { if (DEBUG) this.debug("We're roaming, but data roaming is disabled."); return; } @@ -1980,15 +2047,22 @@ RadioInterface.prototype = { */ handleDataCallState: function handleDataCallState(datacall) { let data = this.rilContext.data; - - if (datacall.ifname && datacall.apn == this.dataCallSettings.apn) { - data.connected = false; - if (this.dataNetworkInterface.inConnectedTypes("default") && - datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED) { - data.connected = true; + let apnSetting = this.apnSettings.byType.default; + let dataCallConnected = + (datacall.state == RIL.GECKO_NETWORK_STATE_CONNECTED); + if (apnSetting && datacall.ifname) { + if (dataCallConnected && datacall.apn == apnSetting.apn && + apnSetting.iface.inConnectedTypes("default")) { + data.connected = dataCallConnected; + gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", + this.clientId, data); + data.apn = datacall.apn; + } else if (!dataCallConnected && datacall.apn == data.apn) { + data.connected = dataCallConnected; + delete data.apn; + gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", + this.clientId, data); } - gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", - this.clientId, data); } this._deliverDataCallCallback("dataCallStateChanged", @@ -2215,9 +2289,11 @@ RadioInterface.prototype = { // Cancel the timer for the call-ring wake lock. this._cancelCallRingWakeLockTimer(); // Shutdown all RIL network interfaces - this.dataNetworkInterface.shutdown(); - this.mmsNetworkInterface.shutdown(); - this.suplNetworkInterface.shutdown(); + for each (let apnSetting in this.apnSettings.byAPN) { + if (apnSetting.iface) { + apnSetting.iface.shutdown(); + } + } Services.obs.removeObserver(this, "xpcom-shutdown"); Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic); Services.obs.removeObserver(this, kSysClockChangeObserverTopic); @@ -2247,12 +2323,10 @@ RadioInterface.prototype = { // the radio power. _changingRadioPower: false, - // APN data for making data calls. + // Data calls setting. dataCallSettings: null, - dataCallSettingsMMS: null, - dataCallSettingsSUPL: null, - _dataCallSettingsToRead: null, - _oldRilDataEnabledState: null, + + apnSettings: null, // Flag to determine whether to use NITZ. It corresponds to the // 'time.nitz.automatic-update.enabled' setting from the UI. @@ -2294,46 +2368,22 @@ RadioInterface.prototype = { this.setPreferredNetworkType(aResult); break; case "ril.data.enabled": - this._oldRilDataEnabledState = this.dataCallSettings.enabled; - // Fall through. - case "ril.data.roaming_enabled": - case "ril.data.apn": - case "ril.data.user": - case "ril.data.passwd": - case "ril.data.authtype": - case "ril.data.httpProxyHost": - case "ril.data.httpProxyPort": - let key = aName.slice(9); - this.dataCallSettings[key] = aResult; - if (DEBUG) { - this.debug("'" + aName + "'" + " is now " + this.dataCallSettings[key]); - } - let index = this._dataCallSettingsToRead.indexOf(aName); - if (index != -1) { - this._dataCallSettingsToRead.splice(index, 1); - } + if (DEBUG) this.debug("'ril.data.enabled' is now " + aResult); + this.dataCallSettings.oldEnabled = this.dataCallSettings.enabled; + this.dataCallSettings.enabled = aResult; this.updateRILNetworkInterface(); break; - case "ril.mms.apn": - case "ril.mms.user": - case "ril.mms.passwd": - case "ril.mms.authtype": - case "ril.mms.httpProxyHost": - case "ril.mms.httpProxyPort": - case "ril.mms.mmsc": - case "ril.mms.mmsproxy": - case "ril.mms.mmsport": - key = aName.slice(8); - this.dataCallSettingsMMS[key] = aResult; + case "ril.data.roaming_enabled": + if (DEBUG) this.debug("'ril.data.roaming_enabled' is now " + aResult); + this.dataCallSettings.roamingEnabled = aResult; + this.updateRILNetworkInterface(); break; - case "ril.supl.apn": - case "ril.supl.user": - case "ril.supl.passwd": - case "ril.supl.authtype": - case "ril.supl.httpProxyHost": - case "ril.supl.httpProxyPort": - key = aName.slice(9); - this.dataCallSettingsSUPL[key] = aResult; + case "ril.data.apnSettings": + if (DEBUG) this.debug("'ril.data.apnSettings' is now " + JSON.stringify(aResult)); + if (aResult) { + this.updateApnSettings(aResult); + this.updateRILNetworkInterface(); + } break; case kTimeNitzAutomaticUpdateEnabled: this._nitzAutomaticUpdateEnabled = aResult; @@ -2360,8 +2410,13 @@ RadioInterface.prototype = { this._ensureRadioState(); // Clean data call setting. - this.dataCallSettings = {}; + this.dataCallSettings.oldEnabled = false; this.dataCallSettings.enabled = false; + this.dataCallSettings.roamingEnabled = false; + this.apnSettings = { + byType: {}, + byAPN: {}, + }; }, // nsIRadioWorker @@ -3161,32 +3216,27 @@ RadioInterface.prototype = { } }, - /** - * Determine whether secondary APN goes through default APN. - */ - usingDefaultAPN: function usingDefaultAPN(apntype) { - switch (apntype) { - case "mms": - return (this.dataCallSettingsMMS.apn == this.dataCallSettings.apn); - case "supl": - return (this.dataCallSettingsSUPL.apn == this.dataCallSettings.apn); - default: - return false; + setupDataCallByType: function setupDataCallByType(apntype) { + let apnSetting = this.apnSettings.byType[apntype]; + if (!apnSetting) { + return; } - }, - setupDataCallBySharedApn: function setupDataCallBySharedApn(apntype) { - this.dataNetworkInterface.connect(this.dataCallSettings, apntype); + let dataInfo = this.rilContext.data; + if (dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED || + dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) { + return; + } + apnSetting.iface.connect(apntype); // We just call connect() function, so this interface should be in // connecting state. If this interface is already in connected state, we // are sure that this interface have successfully established connection // for other data call types before we call connect() function for current // data call type. In this circumstance, we have to directly update the // necessary data call and interface information to RILContentHelper - // and network manager. - if (this.dataNetworkInterface.connected) { - let dataInfo = this.rilContext.data; + // and network manager for current data call type. + if (apnSetting.iface.connected) { if (apntype == "default" && !dataInfo.connected) { dataInfo.connected = true; gMessageManager.sendMobileConnectionMessage("RIL:DataInfoChanged", @@ -3195,53 +3245,31 @@ RadioInterface.prototype = { // Update the interface status via-registration if the interface has // already been registered in the network manager. - if (this.dataNetworkInterface.name in gNetworkManager.networkInterfaces) { - gNetworkManager.unregisterNetworkInterface(this.dataNetworkInterface); + if (apnSetting.iface.name in gNetworkManager.networkInterfaces) { + gNetworkManager.unregisterNetworkInterface(apnSetting.iface); } - gNetworkManager.registerNetworkInterface(this.dataNetworkInterface); + gNetworkManager.registerNetworkInterface(apnSetting.iface); - Services.obs.notifyObservers(this.dataNetworkInterface, + Services.obs.notifyObservers(apnSetting.iface, kNetworkInterfaceStateChangedTopic, null); } }, - setupDataCallByType: function setupDataCallByType(apntype) { - // If it's a shared apn type then we can only reuse the - // dataNetworkInterface in current design. - if (this.usingDefaultAPN(apntype) || - (apntype == "default" && this.usingDefaultAPN("mms")) || - (apntype == "default" && this.usingDefaultAPN("supl"))) { - this.setupDataCallBySharedApn(apntype); + deactivateDataCallByType: function deactivateDataCallByType(apntype) { + let apnSetting = this.apnSettings.byType[apntype]; + if (!apnSetting) { return; } - switch (apntype) { - case "default": - this.dataNetworkInterface.connect(this.dataCallSettings, apntype); - break; - case "mms": - this.mmsNetworkInterface.connect(this.dataCallSettingsMMS, apntype); - break; - case "supl": - this.suplNetworkInterface.connect(this.dataCallSettingsSUPL, apntype); - break; - default: - if (DEBUG) this.debug("Unsupported APN type " + apntype); - break; - } - }, - - deactivateDataCallBySharedApn: function deactivateDataCallBySharedApn(apntype) { - this.dataNetworkInterface.disconnect(apntype); + apnSetting.iface.disconnect(apntype); // We just call disconnect() function, so this interface should be in // disconnecting state. If this interface is still in connected state, we // are sure that other data call types still need this connection of this // interface. In this circumstance, we have to directly update the // necessary data call and interface information to RILContentHelper - // and network manager. - if (this.dataNetworkInterface.connectedTypes.length && - this.dataNetworkInterface.connected) { + // and network manager for current data call type. + if (apnSetting.iface.connectedTypes.length && apnSetting.iface.connected) { let dataInfo = this.rilContext.data; if (apntype == "default" && dataInfo.connected) { dataInfo.connected = false; @@ -3251,63 +3279,26 @@ RadioInterface.prototype = { // Update the interface status via-registration if the interface has // already been registered in the network manager. - if (this.dataNetworkInterface.name in gNetworkManager.networkInterfaces) { - gNetworkManager.unregisterNetworkInterface(this.dataNetworkInterface); + if (apnSetting.iface.name in gNetworkManager.networkInterfaces) { + gNetworkManager.unregisterNetworkInterface(apnSetting.iface); } - gNetworkManager.registerNetworkInterface(this.dataNetworkInterface); + gNetworkManager.registerNetworkInterface(apnSetting.iface); - Services.obs.notifyObservers(this.dataNetworkInterface, + Services.obs.notifyObservers(apnSetting.iface, kNetworkInterfaceStateChangedTopic, null); } }, - deactivateDataCallByType: function deactivateDataCallByType(apntype) { - // If it's a shared apn type then we can only reuse the - // dataNetworkInterface in current design. - if (this.usingDefaultAPN(apntype) || - (apntype == "default" && this.usingDefaultAPN("mms")) || - (apntype == "default" && this.usingDefaultAPN("supl"))) { - this.deactivateDataCallBySharedApn(apntype); - return; - } - switch (apntype) { - case "default": - this.dataNetworkInterface.disconnect(apntype); - break; - case "mms": - this.mmsNetworkInterface.disconnect(apntype); - break; - case "supl": - this.suplNetworkInterface.disconnect(apntype); - break; - default: - if (DEBUG) this.debug("Unsupported APN type " + apntype); - break; - } - }, - getDataCallStateByType: function getDataCallStateByType(apntype) { - // If it's a shared apn type then we can only reuse the - // dataNetworkInterface in current design. - if (this.usingDefaultAPN(apntype) || - (apntype == "default" && this.usingDefaultAPN("mms")) || - (apntype == "default" && this.usingDefaultAPN("supl"))) { - if (this.dataNetworkInterface.inConnectedTypes(apntype)) { - return this.dataNetworkInterface.state; - } - return RIL.GECKO_NETWORK_STATE_UNKNOWN; + let apnSetting = this.apnSettings.byType[apntype]; + if (!apnSetting) { + return RIL.GECKO_NETWORK_STATE_UNKNOWN; } - switch (apntype) { - case "default": - return this.dataNetworkInterface.state; - case "mms": - return this.mmsNetworkInterface.state; - case "supl": - return this.suplNetworkInterface.state; - default: - return RIL.GECKO_NETWORK_STATE_UNKNOWN; + if (!apnSetting.iface.inConnectedTypes(apntype)) { + return RIL.GECKO_NETWORK_STATE_DISCONNECTED; } + return apnSetting.iface.state; }, setupDataCall: function setupDataCall(radioTech, apn, user, passwd, chappap, pdptype) { @@ -3361,9 +3352,9 @@ RadioInterface.prototype = { }, }; -function RILNetworkInterface(radioInterface, type) { +function RILNetworkInterface(radioInterface, apnSetting) { this.radioInterface = radioInterface; - this.initType = type; + this.apnSetting = apnSetting; } RILNetworkInterface.prototype = { @@ -3432,9 +3423,13 @@ RILNetworkInterface.prototype = { dns2: null, - httpProxyHost: null, + get httpProxyHost() { + return this.apnSetting.proxy || ''; + }, - httpProxyPort: null, + get httpProxyPort() { + return this.apnSetting.port || ''; + }, debug: function debug(s) { dump("-*- RILNetworkInterface[" + this.radioInterface.clientId + ":" + @@ -3444,7 +3439,7 @@ RILNetworkInterface.prototype = { // nsIRILDataCallback dataCallError: function dataCallError(message) { - if (message.apn != this.dataCallSettings.apn) { + if (message.apn != this.apnSetting.apn) { return; } if (DEBUG) this.debug("Data call error on APN: " + message.apn); @@ -3460,7 +3455,7 @@ RILNetworkInterface.prototype = { // If data call for this connection does not exist, it could be state // change for new data call. We only update data call state change // if APN name matched. - if (!this.cid && datacall.apn != this.dataCallSettings.apn) { + if (!this.cid && datacall.apn != this.apnSetting.apn) { return; } if (DEBUG) { @@ -3501,12 +3496,14 @@ RILNetworkInterface.prototype = { // In case the data setting changed while the datacall was being started or // ended, let's re-check the setting and potentially adjust the datacall // state again. - if (this == this.radioInterface.dataNetworkInterface) { + if (this.radioInterface.apnSettings.byType.default && + (this.radioInterface.apnSettings.byType.default.apn == + this.apnSetting.apn)) { this.radioInterface.updateRILNetworkInterface(); } if (this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN && - this.registeredAsNetworkInterface) { + this.registeredAsNetworkInterface) { gNetworkManager.unregisterNetworkInterface(this); this.registeredAsNetworkInterface = false; this.cid = null; @@ -3528,7 +3525,7 @@ RILNetworkInterface.prototype = { registeredAsDataCallCallback: false, registeredAsNetworkInterface: false, connecting: false, - dataCallSettings: {}, + apnSetting: {}, // APN failed connections. Retry counter apnRetryCounter: 0, @@ -3543,7 +3540,7 @@ RILNetworkInterface.prototype = { return this.state == RIL.GECKO_NETWORK_STATE_CONNECTED; }, - connect: function connect(options, apntype) { + connect: function connect(apntype) { if (apntype && !this.inConnectedTypes(apntype)) { this.connectedTypes.push(apntype); } @@ -3563,40 +3560,32 @@ RILNetworkInterface.prototype = { this.registeredAsDataCallCallback = true; } - if (options) { - // Save the APN data locally for using them in connection retries. - this.dataCallSettings = options; - } - - if (!this.dataCallSettings.apn) { + if (!this.apnSetting.apn) { if (DEBUG) this.debug("APN name is empty, nothing to do."); return; } - this.httpProxyHost = this.dataCallSettings.httpProxyHost; - this.httpProxyPort = this.dataCallSettings.httpProxyPort; - if (DEBUG) { this.debug("Going to set up data connection with APN " + - this.dataCallSettings.apn); + this.apnSetting.apn); } let radioTechType = this.radioInterface.rilContext.data.type; let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType); - let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.dataCallSettings["authtype"]); + let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnSetting.authtype); // Use the default authType if the value in database is invalid. // For the case that user might not select the authentication type. if (authType == -1) { if (DEBUG) { - this.debug("Invalid authType " + this.dataCallSettings.authtype); + this.debug("Invalid authType " + this.apnSetting.authtype); } authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT); } this.radioInterface.setupDataCall(radioTechnology, - this.dataCallSettings.apn, - this.dataCallSettings.user, - this.dataCallSettings.passwd, - authType, - "IP"); + this.apnSetting.apn, + this.apnSetting.user, + this.apnSetting.password, + authType, + "IP"); this.connecting = true; }, @@ -3641,7 +3630,8 @@ RILNetworkInterface.prototype = { } if (this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTING || - this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED) { + this.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED || + this.state == RIL.GECKO_NETWORK_STATE_UNKNOWN) { return; } let reason = RIL.DATACALL_DEACTIVATE_NO_REASON; From 93ee2195ae7dcd650eb8f7317d7698bbf5978db4 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Thu, 30 May 2013 18:04:48 +0800 Subject: [PATCH 09/30] Bug 875721 - Part 1: Move iccInfo related attribute/event from mozMobileConnection to mozIccManager (IDL). r=allstars.chh, sr=sicking --- dom/icc/interfaces/moz.build | 1 + dom/icc/interfaces/nsIDOMIccInfo.idl | 45 ++++++++++++++++ dom/icc/interfaces/nsIDOMIccManager.idl | 20 +++++-- dom/icc/interfaces/nsIIccProvider.idl | 15 ++++-- .../interfaces/nsIDOMMobileConnection.idl | 54 +------------------ .../nsIMobileConnectionProvider.idl | 11 ++-- dom/system/gonk/nsIRadioInterfaceLayer.idl | 8 +-- 7 files changed, 83 insertions(+), 71 deletions(-) create mode 100644 dom/icc/interfaces/nsIDOMIccInfo.idl diff --git a/dom/icc/interfaces/moz.build b/dom/icc/interfaces/moz.build index caf6a9d6b5c2..2c8bf33386c2 100644 --- a/dom/icc/interfaces/moz.build +++ b/dom/icc/interfaces/moz.build @@ -7,6 +7,7 @@ XPIDL_SOURCES += [ 'SimToolKit.idl', 'nsIDOMIccCardLockErrorEvent.idl', + 'nsIDOMIccInfo.idl', 'nsIDOMIccManager.idl', 'nsIIccProvider.idl', 'nsINavigatorIccManager.idl', diff --git a/dom/icc/interfaces/nsIDOMIccInfo.idl b/dom/icc/interfaces/nsIDOMIccInfo.idl new file mode 100644 index 000000000000..ce82100f2e1f --- /dev/null +++ b/dom/icc/interfaces/nsIDOMIccInfo.idl @@ -0,0 +1,45 @@ +/* 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/. */ + +#include "nsISupports.idl" + +[scriptable, uuid(a45c0fe0-c911-11e2-8b8b-0800200c9a66)] +interface nsIDOMMozIccInfo : nsISupports +{ + /** + * Integrated Circuit Card Identifier. + */ + readonly attribute DOMString iccid; + + /** + * Mobile Country Code (MCC) of the subscriber's home network. + */ + readonly attribute DOMString mcc; + + /** + * Mobile Network Code (MNC) of the subscriber's home network. + */ + readonly attribute DOMString mnc; + + /** + * Service Provider Name (SPN) of the subscriber's home network. + */ + readonly attribute DOMString spn; + + /** + * Network name must be a part of displayed carrier name. + */ + readonly attribute boolean isDisplayNetworkNameRequired; + + /** + * Service provider name must be a part of displayed carrier name. + */ + readonly attribute boolean isDisplaySpnRequired; + + /** + * Mobile Station ISDN Number (MSISDN) of the subscriber's, aka + * his phone number. + */ + readonly attribute DOMString msisdn; +}; diff --git a/dom/icc/interfaces/nsIDOMIccManager.idl b/dom/icc/interfaces/nsIDOMIccManager.idl index e5f7f4a11636..05cd35492362 100644 --- a/dom/icc/interfaces/nsIDOMIccManager.idl +++ b/dom/icc/interfaces/nsIDOMIccManager.idl @@ -5,11 +5,12 @@ #include "nsIDOMEventTarget.idl" #include "SimToolKit.idl" -interface nsIDOMEventListener; -interface nsIDOMDOMRequest; interface nsIDOMContact; +interface nsIDOMDOMRequest; +interface nsIDOMEventListener; +interface nsIDOMMozIccInfo; -[scriptable, builtinclass, uuid(5f405112-4da9-4d4d-942c-4da3cb7928e1)] +[scriptable, builtinclass, uuid(d362bf60-c910-11e2-8b8b-0800200c9a66)] interface nsIDOMMozIccManager : nsIDOMEventTarget { /** @@ -275,6 +276,19 @@ interface nsIDOMMozIccManager : nsIDOMEventTarget */ [implicit_jscontext] attribute jsval onstksessionend; + // UICC Card Information. + + /** + * Information stored in the device's ICC card. + */ + readonly attribute nsIDOMMozIccInfo iccInfo; + + /** + * The 'iccinfochange' event is notified whenever the icc info object + * changes. + */ + [implicit_jscontext] attribute jsval oniccinfochange; + // UICC Card State. /** diff --git a/dom/icc/interfaces/nsIIccProvider.idl b/dom/icc/interfaces/nsIIccProvider.idl index 6b6b00fd62b3..ac98ca81220b 100644 --- a/dom/icc/interfaces/nsIIccProvider.idl +++ b/dom/icc/interfaces/nsIIccProvider.idl @@ -4,11 +4,12 @@ #include "nsISupports.idl" -interface nsIDOMWindow; -interface nsIDOMDOMRequest; interface nsIDOMContact; +interface nsIDOMDOMRequest; +interface nsIDOMMozIccInfo; +interface nsIDOMWindow; -[scriptable, uuid(5902d9b0-c2be-11e2-8b8b-0800200c9a66)] +[scriptable, uuid(82d25440-c913-11e2-8b8b-0800200c9a66)] interface nsIIccListener : nsISupports { void notifyStkCommand(in DOMString aMessage); @@ -16,12 +17,13 @@ interface nsIIccListener : nsISupports void notifyIccCardLockError(in DOMString lockType, in unsigned long retryCount); void notifyCardStateChanged(); + void notifyIccInfoChanged(); }; /** * XPCOM component (in the content process) that provides the ICC information. */ -[scriptable, uuid(7131dfbe-9a2c-434d-b6b8-3eebf491ce1a)] +[scriptable, uuid(52fa6780-c913-11e2-8b8b-0800200c9a66)] interface nsIIccProvider : nsISupports { /** @@ -32,6 +34,11 @@ interface nsIIccProvider : nsISupports void registerIccMsg(in nsIIccListener listener); void unregisterIccMsg(in nsIIccListener listener); + /** + * UICC Information + */ + readonly attribute nsIDOMMozIccInfo iccInfo; + /** * Card State */ diff --git a/dom/network/interfaces/nsIDOMMobileConnection.idl b/dom/network/interfaces/nsIDOMMobileConnection.idl index 936a7211cd7b..bf850fcf8b17 100644 --- a/dom/network/interfaces/nsIDOMMobileConnection.idl +++ b/dom/network/interfaces/nsIDOMMobileConnection.idl @@ -6,13 +6,12 @@ interface nsIDOMEventListener; interface nsIDOMDOMRequest; -interface nsIDOMMozMobileICCInfo; interface nsIDOMMozMobileConnectionInfo; interface nsIDOMMozMobileNetworkInfo; interface nsIDOMMozMobileCellInfo; interface nsIDOMMozMobileCFInfo; -[scriptable, builtinclass, uuid(dc010230-c2bc-11e2-8b8b-0800200c9a66)] +[scriptable, builtinclass, uuid(fd26e2e0-c910-11e2-8b8b-0800200c9a66)] interface nsIDOMMozMobileConnection : nsIDOMEventTarget { const long ICC_SERVICE_CLASS_VOICE = (1 << 0); @@ -55,11 +54,6 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget */ readonly attribute long retryCount; - /** - * Information stored in the device's ICC card. - */ - readonly attribute nsIDOMMozMobileICCInfo iccInfo; - /** * Information about the voice connection. */ @@ -232,12 +226,6 @@ interface nsIDOMMozMobileConnection : nsIDOMEventTarget */ nsIDOMDOMRequest getCallWaitingOption(); - /** - * The 'iccinfochange' event is notified whenever the icc info object - * changes. - */ - [implicit_jscontext] attribute jsval oniccinfochange; - /** * The 'voicechange' event is notified whenever the voice connection object * changes. @@ -380,46 +368,6 @@ interface nsIDOMMozMobileCellInfo: nsISupports readonly attribute unsigned long gsmCellId; }; -[scriptable, uuid(10d5c5a2-d43f-4f94-8657-cf7ccabbab6e)] -interface nsIDOMMozMobileICCInfo : nsISupports -{ - /** - * Integrated Circuit Card Identifier. - */ - readonly attribute DOMString iccid; - - /** - * Mobile Country Code (MCC) of the subscriber's home network. - */ - readonly attribute DOMString mcc; - - /** - * Mobile Network Code (MNC) of the subscriber's home network. - */ - readonly attribute DOMString mnc; - - /** - * Service Provider Name (SPN) of the subscriber's home network. - */ - readonly attribute DOMString spn; - - /** - * Network name must be a part of displayed carrier name. - */ - readonly attribute boolean isDisplayNetworkNameRequired; - - /** - * Service provider name must be a part of displayed carrier name. - */ - readonly attribute boolean isDisplaySpnRequired; - - /** - * Mobile Station ISDN Number (MSISDN) of the subscriber's, aka - * his phone number. - */ - readonly attribute DOMString msisdn; -}; - [scriptable, uuid(d1b35ad8-99aa-47cc-ab49-2e72b00e39df)] interface nsIDOMMozMobileCFInfo : nsISupports { diff --git a/dom/network/interfaces/nsIMobileConnectionProvider.idl b/dom/network/interfaces/nsIMobileConnectionProvider.idl index 5703cd6e91b6..ecd20a26c7c9 100644 --- a/dom/network/interfaces/nsIMobileConnectionProvider.idl +++ b/dom/network/interfaces/nsIMobileConnectionProvider.idl @@ -4,19 +4,17 @@ #include "nsISupports.idl" -interface nsIDOMMozMobileICCInfo; +interface nsIDOMDOMRequest; +interface nsIDOMMozMobileCFInfo; interface nsIDOMMozMobileConnectionInfo; interface nsIDOMMozMobileNetworkInfo; -interface nsIDOMMozMobileCFInfo; -interface nsIDOMDOMRequest; interface nsIDOMWindow; -[scriptable, uuid(529864f0-c2be-11e2-8b8b-0800200c9a66)] +[scriptable, uuid(74361840-c913-11e2-8b8b-0800200c9a66)] interface nsIMobileConnectionListener : nsISupports { void notifyVoiceChanged(); void notifyDataChanged(); - void notifyIccInfoChanged(); void notifyUssdReceived(in DOMString message, in boolean sessionEnded); void notifyDataError(in DOMString message); @@ -32,7 +30,7 @@ interface nsIMobileConnectionListener : nsISupports * XPCOM component (in the content process) that provides the mobile * network information. */ -[scriptable, uuid(66e7ac90-c2be-11e2-8b8b-0800200c9a66)] +[scriptable, uuid(477d93f0-c913-11e2-8b8b-0800200c9a66)] interface nsIMobileConnectionProvider : nsISupports { /** @@ -44,7 +42,6 @@ interface nsIMobileConnectionProvider : nsISupports void unregisterMobileConnectionMsg(in nsIMobileConnectionListener listener); readonly attribute long retryCount; - readonly attribute nsIDOMMozMobileICCInfo iccInfo; readonly attribute nsIDOMMozMobileConnectionInfo voiceConnectionInfo; readonly attribute nsIDOMMozMobileConnectionInfo dataConnectionInfo; readonly attribute DOMString networkSelectionMode; diff --git a/dom/system/gonk/nsIRadioInterfaceLayer.idl b/dom/system/gonk/nsIRadioInterfaceLayer.idl index f5f3cc9c5b68..2e69fefc8432 100644 --- a/dom/system/gonk/nsIRadioInterfaceLayer.idl +++ b/dom/system/gonk/nsIRadioInterfaceLayer.idl @@ -4,10 +4,10 @@ #include "nsISupports.idl" +interface nsIDOMMozIccInfo; interface nsIDOMMozMobileConnectionInfo; -interface nsIDOMMozMobileICCInfo; -interface nsIMobileMessageCallback; interface nsIDOMMozSmsSegmentInfo; +interface nsIMobileMessageCallback; [scriptable, uuid(1e602d20-d066-4399-8997-daf36b3158ef)] interface nsIRILDataCallInfo : nsISupports @@ -59,7 +59,7 @@ interface nsIVoicemailInfo : nsISupports readonly attribute DOMString displayName; }; -[scriptable, uuid(2f1c8055-322e-490a-b1e1-4ccd5d546b3c)] +[scriptable, uuid(95e1be50-c912-11e2-8b8b-0800200c9a66)] interface nsIRilContext : nsISupports { readonly attribute DOMString radioState; @@ -72,7 +72,7 @@ interface nsIRilContext : nsISupports readonly attribute DOMString networkSelectionMode; - readonly attribute nsIDOMMozMobileICCInfo iccInfo; + readonly attribute nsIDOMMozIccInfo iccInfo; readonly attribute nsIDOMMozMobileConnectionInfo voice; From c7373ca1c4c635530be0a12bb4e95762df1a5404 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Thu, 30 May 2013 18:36:10 +0800 Subject: [PATCH 10/30] Bug 875721 - Part 2: Move iccInfo related attribute/event from mozMobileConnection to mozIccManager (DOM). r=smaug --- dom/icc/src/IccManager.cpp | 20 ++++++++++++++++++++ dom/network/src/MobileConnection.cpp | 22 ---------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/dom/icc/src/IccManager.cpp b/dom/icc/src/IccManager.cpp index 5a0dd8eaadaa..92709dfe8cd8 100644 --- a/dom/icc/src/IccManager.cpp +++ b/dom/icc/src/IccManager.cpp @@ -5,6 +5,7 @@ #include "mozilla/Services.h" #include "nsIDOMClassInfo.h" #include "nsIDOMIccCardLockErrorEvent.h" +#include "nsIDOMIccInfo.h" #include "GeneratedEvents.h" #include "IccManager.h" #include "SimToolKit.h" @@ -129,6 +130,18 @@ IccManager::SendStkEventDownload(const JS::Value& aEvent) return NS_OK; } +NS_IMETHODIMP +IccManager::GetIccInfo(nsIDOMMozIccInfo** aIccInfo) +{ + *aIccInfo = nullptr; + + if (!mProvider) { + return NS_ERROR_FAILURE; + } + + return mProvider->GetIccInfo(aIccInfo); +} + NS_IMETHODIMP IccManager::GetCardState(nsAString& cardState) { @@ -237,6 +250,7 @@ NS_IMPL_EVENT_HANDLER(IccManager, stkcommand) NS_IMPL_EVENT_HANDLER(IccManager, stksessionend) NS_IMPL_EVENT_HANDLER(IccManager, icccardlockerror) NS_IMPL_EVENT_HANDLER(IccManager, cardstatechange) +NS_IMPL_EVENT_HANDLER(IccManager, iccinfochange) // nsIIccListener @@ -274,4 +288,10 @@ NS_IMETHODIMP IccManager::NotifyCardStateChanged() { return DispatchTrustedEvent(NS_LITERAL_STRING("cardstatechange")); +} + +NS_IMETHODIMP +IccManager::NotifyIccInfoChanged() +{ + return DispatchTrustedEvent(NS_LITERAL_STRING("iccinfochange")); } \ No newline at end of file diff --git a/dom/network/src/MobileConnection.cpp b/dom/network/src/MobileConnection.cpp index 49ca4438fc28..cecd10614593 100644 --- a/dom/network/src/MobileConnection.cpp +++ b/dom/network/src/MobileConnection.cpp @@ -67,7 +67,6 @@ NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(MobileConnection, nsDOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(MobileConnection, nsDOMEventTargetHelper) -NS_IMPL_EVENT_HANDLER(MobileConnection, iccinfochange) NS_IMPL_EVENT_HANDLER(MobileConnection, voicechange) NS_IMPL_EVENT_HANDLER(MobileConnection, datachange) NS_IMPL_EVENT_HANDLER(MobileConnection, ussdreceived) @@ -172,17 +171,6 @@ MobileConnection::GetRetryCount(int32_t* retryCount) return mProvider->GetRetryCount(retryCount); } -NS_IMETHODIMP -MobileConnection::GetIccInfo(nsIDOMMozMobileICCInfo** aIccInfo) -{ - *aIccInfo = nullptr; - - if (!mProvider || !CheckPermission("mobileconnection")) { - return NS_OK; - } - return mProvider->GetIccInfo(aIccInfo); -} - NS_IMETHODIMP MobileConnection::GetVoice(nsIDOMMozMobileConnectionInfo** voice) { @@ -416,16 +404,6 @@ MobileConnection::NotifyDataChanged() return DispatchTrustedEvent(NS_LITERAL_STRING("datachange")); } -NS_IMETHODIMP -MobileConnection::NotifyIccInfoChanged() -{ - if (!CheckPermission("mobileconnection")) { - return NS_OK; - } - - return DispatchTrustedEvent(NS_LITERAL_STRING("iccinfochange")); -} - NS_IMETHODIMP MobileConnection::NotifyUssdReceived(const nsAString& aMessage, bool aSessionEnded) From c789340b25e1cdea087af87aecaac455bd5094da Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Thu, 30 May 2013 18:52:56 +0800 Subject: [PATCH 11/30] Bug 875721 - Part 3: GPS changes for iccInfo. r=kchen --- dom/system/gonk/GonkGPSGeolocationProvider.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dom/system/gonk/GonkGPSGeolocationProvider.cpp b/dom/system/gonk/GonkGPSGeolocationProvider.cpp index f297ed24bb6c..1cb00f262f89 100644 --- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp +++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp @@ -24,6 +24,7 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsINetworkManager.h" #include "nsIRadioInterfaceLayer.h" +#include "nsIDOMIccInfo.h" #include "nsIDOMMobileConnection.h" #include "nsJSUtils.h" #include "nsServiceManagerUtils.h" @@ -422,7 +423,7 @@ GonkGPSGeolocationProvider::RequestSetID(uint32_t flags) } if (flags & AGPS_RIL_REQUEST_SETID_MSISDN) { - nsCOMPtr iccInfo; + nsCOMPtr iccInfo; rilCtx->GetIccInfo(getter_AddRefs(iccInfo)); if (iccInfo) { type = AGPS_SETID_TYPE_MSISDN; @@ -453,7 +454,7 @@ GonkGPSGeolocationProvider::SetReferenceLocation() location.type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID; if (rilCtx) { - nsCOMPtr iccInfo; + nsCOMPtr iccInfo; rilCtx->GetIccInfo(getter_AddRefs(iccInfo)); if (iccInfo) { nsresult result; From 7038f1a6972ea36cbb6447c4b59efee2cd2a8f5c Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Thu, 30 May 2013 18:56:11 +0800 Subject: [PATCH 12/30] Bug 875721 - Part 4: Bluetooth changes for iccInfo. r=echou --- dom/bluetooth/BluetoothHfpManager.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dom/bluetooth/BluetoothHfpManager.cpp b/dom/bluetooth/BluetoothHfpManager.cpp index 4535a7365ff1..4d6f3a069457 100644 --- a/dom/bluetooth/BluetoothHfpManager.cpp +++ b/dom/bluetooth/BluetoothHfpManager.cpp @@ -21,6 +21,8 @@ #include "mozilla/StaticPtr.h" #include "nsContentUtils.h" #include "nsIAudioManager.h" +#include "nsIDOMIccInfo.h" +#include "nsIIccProvider.h" #include "nsIObserverService.h" #include "nsISettingsService.h" #include "nsITelephonyProvider.h" @@ -634,12 +636,12 @@ BluetoothHfpManager::HandleVoiceConnectionChanged() void BluetoothHfpManager::HandleIccInfoChanged() { - nsCOMPtr connection = + nsCOMPtr icc = do_GetService(NS_RILCONTENTHELPER_CONTRACTID); - NS_ENSURE_TRUE_VOID(connection); + NS_ENSURE_TRUE_VOID(icc); - nsIDOMMozMobileICCInfo* iccInfo; - connection->GetIccInfo(&iccInfo); + nsIDOMMozIccInfo* iccInfo; + icc->GetIccInfo(&iccInfo); NS_ENSURE_TRUE_VOID(iccInfo); iccInfo->GetMsisdn(mMsisdn); } From a70241c6a2b448b5b8eb5728a91c01fa3429923c Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Thu, 30 May 2013 19:14:39 +0800 Subject: [PATCH 13/30] Bug 875721 - Part 5: RIL implementation changes for iccInfo. r=allstars.chh --- dom/system/gonk/RILContentHelper.js | 25 ++++++++++++------------- dom/system/gonk/RadioInterfaceLayer.js | 4 ++-- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/dom/system/gonk/RILContentHelper.js b/dom/system/gonk/RILContentHelper.js index 70bde10fedfe..2e59eee16315 100644 --- a/dom/system/gonk/RILContentHelper.js +++ b/dom/system/gonk/RILContentHelper.js @@ -45,8 +45,8 @@ if (DEBUG) { const RILCONTENTHELPER_CID = Components.ID("{472816e1-1fd6-4405-996c-806f9ea68174}"); -const MOBILEICCINFO_CID = - Components.ID("{8649c12f-f8f4-4664-bbdd-7d115c23e2a7}"); +const ICCINFO_CID = + Components.ID("{fab2c0f0-d73a-11e2-8b8b-0800200c9a66}"); const MOBILECONNECTIONINFO_CID = Components.ID("{a35cfd39-2d93-4489-ac7d-396475dacb27}"); const MOBILENETWORKINFO_CID = @@ -135,18 +135,18 @@ MobileIccCardLockRetryCount.prototype = { success: 'r'} }; -function MobileICCInfo() {} -MobileICCInfo.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozMobileICCInfo]), - classID: MOBILEICCINFO_CID, +function IccInfo() {} +IccInfo.prototype = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozIccInfo]), + classID: ICCINFO_CID, classInfo: XPCOMUtils.generateCI({ - classID: MOBILEICCINFO_CID, - classDescription: "MobileICCInfo", + classID: ICCINFO_CID, + classDescription: "IccInfo", flags: Ci.nsIClassInfo.DOM_OBJECT, - interfaces: [Ci.nsIDOMMozMobileICCInfo] + interfaces: [Ci.nsIDOMMozIccInfo] }), - // nsIDOMMozMobileICCInfo + // nsIDOMMozIccInfo iccid: null, mcc: null, @@ -381,7 +381,7 @@ function RILContentHelper() { cardState: RIL.GECKO_CARDSTATE_UNKNOWN, retryCount: 0, networkSelectionMode: RIL.GECKO_NETWORK_SELECTION_UNKNOWN, - iccInfo: new MobileICCInfo(), + iccInfo: new IccInfo(), voiceConnectionInfo: new MobileConnectionInfo(), dataConnectionInfo: new MobileConnectionInfo() }; @@ -1337,8 +1337,7 @@ RILContentHelper.prototype = { } case "RIL:IccInfoChanged": this.updateInfo(msg.json.data, this.rilContext.iccInfo); - this._deliverEvent("_mobileConnectionListeners", - "notifyIccInfoChanged", null); + this._deliverEvent("_iccListeners", "notifyIccInfoChanged", null); break; case "RIL:VoiceInfoChanged": this.updateConnectionInfo(msg.json.data, diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js index 20464a0fa6fa..16d9bdaca00a 100644 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ b/dom/system/gonk/RadioInterfaceLayer.js @@ -2154,8 +2154,8 @@ RadioInterface.prototype = { } // RIL:IccInfoChanged corresponds to a DOM event that gets fired only // when the MCC or MNC codes have changed. - gMessageManager.sendMobileConnectionMessage("RIL:IccInfoChanged", - this.clientId, message); + gMessageManager.sendIccMessage("RIL:IccInfoChanged", + this.clientId, message); // Update lastKnownHomeNetwork. if (message.mcc && message.mnc) { From 9f039a4b951a146a6763268fb2dc893e958e00e0 Mon Sep 17 00:00:00 2001 From: Edgar Chen Date: Thu, 30 May 2013 19:20:39 +0800 Subject: [PATCH 14/30] Bug 875721 - Part 6: Fix marionette tests for iccInfo. r=allstars.chh --HG-- rename : dom/network/tests/marionette/test_mobile_iccinfo.js => dom/icc/tests/marionette/test_icc_info.js --- .../tests/marionette/test_icc_info.js} | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) rename dom/{network/tests/marionette/test_mobile_iccinfo.js => icc/tests/marionette/test_icc_info.js} (80%) diff --git a/dom/network/tests/marionette/test_mobile_iccinfo.js b/dom/icc/tests/marionette/test_icc_info.js similarity index 80% rename from dom/network/tests/marionette/test_mobile_iccinfo.js rename to dom/icc/tests/marionette/test_icc_info.js index b3c63bb53004..f3d03f69b347 100644 --- a/dom/network/tests/marionette/test_mobile_iccinfo.js +++ b/dom/icc/tests/marionette/test_icc_info.js @@ -5,9 +5,9 @@ MARIONETTE_TIMEOUT = 30000; SpecialPowers.addPermission("mobileconnection", true, document); -let connection = navigator.mozMobileConnection; -ok(connection instanceof MozMobileConnection, - "connection is instanceof " + connection.constructor); +let icc = navigator.mozIccManager; +ok(icc instanceof MozIccManager, + "icc is instanceof " + icc.constructor); let emulatorCmdPendingCount = 0; function sendEmulatorCommand(cmd, callback) { @@ -28,8 +28,8 @@ function setEmulatorMccMnc(mcc, mnc) { } function waitForIccInfoChange(callback) { - connection.addEventListener("iccinfochange", function handler() { - connection.removeEventListener("iccinfochange", handler); + icc.addEventListener("iccinfochange", function handler() { + icc.removeEventListener("iccinfochange", handler); callback(); }); } @@ -39,18 +39,20 @@ function finalize() { finish(); } +let iccInfo = icc.iccInfo; + // The emulator's hard coded iccid value. // See it here {B2G_HOME}/external/qemu/telephony/sim_card.c#L299. -is(connection.iccInfo.iccid, 89014103211118510720); +is(iccInfo.iccid, 89014103211118510720); // The emulator's hard coded mcc and mnc codes. // See it here {B2G_HOME}/external/qemu/telephony/android_modem.c#L2465. -is(connection.iccInfo.mcc, 310); -is(connection.iccInfo.mnc, 260); -is(connection.iccInfo.spn, "Android"); +is(iccInfo.mcc, 310); +is(iccInfo.mnc, 260); +is(iccInfo.spn, "Android"); // Phone number is hardcoded in MSISDN // See {B2G_HOME}/external/qemu/telephony/sim_card.c, in asimcard_io() -is(connection.iccInfo.msisdn, "15555215554"); +is(iccInfo.msisdn, "15555215554"); // Test display condition change. function testDisplayConditionChange(func, caseArray, oncomplete) { @@ -64,9 +66,9 @@ function testDisplayConditionChange(func, caseArray, oncomplete) { function testSPN(mcc, mnc, expectedIsDisplayNetworkNameRequired, expectedIsDisplaySpnRequired, callback) { waitForIccInfoChange(function() { - is(connection.iccInfo.isDisplayNetworkNameRequired, + is(iccInfo.isDisplayNetworkNameRequired, expectedIsDisplayNetworkNameRequired); - is(connection.iccInfo.isDisplaySpnRequired, + is(iccInfo.isDisplaySpnRequired, expectedIsDisplaySpnRequired); // operatorchange will be ignored if we send commands too soon. window.setTimeout(callback, 100); From 361178513837d5a02dff77ddfd9bc98eb2cfee85 Mon Sep 17 00:00:00 2001 From: Dave Camp Date: Mon, 17 Jun 2013 06:52:53 -0700 Subject: [PATCH 15/30] Bug 888528 - Add node deletion/insertion to the walker actor. r=jwalker --HG-- extra : rebase_source : 8d5b9991371a7dcdceff2cd302e7bc76c8f90ea0 --- toolkit/devtools/server/actors/inspector.js | 40 ++++++++ .../server/tests/mochitest/Makefile.in | 2 + .../mochitest/test_inspector-insert.html | 96 +++++++++++++++++++ .../mochitest/test_inspector-remove.html | 96 +++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 toolkit/devtools/server/tests/mochitest/test_inspector-insert.html create mode 100644 toolkit/devtools/server/tests/mochitest/test_inspector-remove.html diff --git a/toolkit/devtools/server/actors/inspector.js b/toolkit/devtools/server/actors/inspector.js index ac07ad103a8f..7c09a8745a85 100644 --- a/toolkit/devtools/server/actors/inspector.js +++ b/toolkit/devtools/server/actors/inspector.js @@ -1381,6 +1381,46 @@ var WalkerActor = protocol.ActorClass({ } }), + /** + * Removes a node from its parent node. + * + * @returns The node's nextSibling before it was removed. + */ + removeNode: method(function(node) { + if ((node.rawNode.ownerDocument && + node.rawNode.ownerDocument.documentElement === this.rawNode) || + node.rawNode.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) { + throw Error("Cannot remove document or document elements."); + } + let nextSibling = this.nextSibling(node); + if (node.rawNode.parentNode) { + node.rawNode.parentNode.removeChild(node.rawNode); + // Mutation events will take care of the rest. + } + return nextSibling; + }, { + request: { + node: Arg(0, "domnode") + }, + response: { + nextSibling: RetVal("domnode", { optional: true }) + } + }), + + /** + * Insert a node into the DOM. + */ + insertBefore: method(function(node, parent, sibling) { + parent.rawNode.insertBefore(node.rawNode, sibling ? sibling.rawNode : null); + }, { + request: { + node: Arg(0, "domnode"), + parent: Arg(1, "domnode"), + sibling: Arg(2, "domnode", { optional: true }) + }, + response: {} + }), + /** * Get any pending mutation records. Must be called by the client after * the `new-mutations` notification is received. Returns an array of diff --git a/toolkit/devtools/server/tests/mochitest/Makefile.in b/toolkit/devtools/server/tests/mochitest/Makefile.in index 1f0c04a776d3..b90c21f7356c 100644 --- a/toolkit/devtools/server/tests/mochitest/Makefile.in +++ b/toolkit/devtools/server/tests/mochitest/Makefile.in @@ -16,11 +16,13 @@ MOCHITEST_CHROME_FILES = \ inspector-traversal-data.html \ test_inspector-changeattrs.html \ test_inspector-changevalue.html \ + test_inspector-insert.html \ test_inspector-mutations-attr.html \ test_inspector-mutations-childlist.html \ test_inspector-mutations-frameload.html \ test_inspector-mutations-value.html \ test_inspector-release.html \ + test_inspector-remove.html \ test_inspector-retain.html \ test_inspector-pseudoclass-lock.html \ test_inspector-traversal.html \ diff --git a/toolkit/devtools/server/tests/mochitest/test_inspector-insert.html b/toolkit/devtools/server/tests/mochitest/test_inspector-insert.html new file mode 100644 index 000000000000..b20121fc0a4d --- /dev/null +++ b/toolkit/devtools/server/tests/mochitest/test_inspector-insert.html @@ -0,0 +1,96 @@ + + + + + + Test for Bug + + + + + + + +Mozilla Bug +Test Document +

+ +
+
+ + diff --git a/toolkit/devtools/server/tests/mochitest/test_inspector-remove.html b/toolkit/devtools/server/tests/mochitest/test_inspector-remove.html new file mode 100644 index 000000000000..52a330913925 --- /dev/null +++ b/toolkit/devtools/server/tests/mochitest/test_inspector-remove.html @@ -0,0 +1,96 @@ + + + + + + Test for Bug + + + + + + + +Mozilla Bug +Test Document +

+ +
+
+ + From f7ca2063a811e7955df4db2d5ca605f9a5cf93d9 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Thu, 11 Jul 2013 10:56:23 -0700 Subject: [PATCH 16/30] Bug 892100 - Script actor's source loading error reporting broken; r=past --- toolkit/devtools/server/actors/script.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js index e2460515e9f3..fa64ab587f0b 100644 --- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -2849,7 +2849,7 @@ function fetch(aURL, aOptions={ loadFromCache: true }) { try { NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) { if (!Components.isSuccessCode(aStatus)) { - deferred.reject("Request failed: " + url); + deferred.reject(new Error("Request failed: " + url)); return; } @@ -2858,7 +2858,7 @@ function fetch(aURL, aOptions={ loadFromCache: true }) { aStream.close(); }); } catch (ex) { - deferred.reject("Request failed: " + url); + deferred.reject(new Error("Request failed: " + url)); } break; @@ -2876,7 +2876,7 @@ function fetch(aURL, aOptions={ loadFromCache: true }) { let streamListener = { onStartRequest: function(aRequest, aContext, aStatusCode) { if (!Components.isSuccessCode(aStatusCode)) { - deferred.reject("Request failed: " + url); + deferred.reject(new Error("Request failed: " + url)); } }, onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) { @@ -2884,7 +2884,7 @@ function fetch(aURL, aOptions={ loadFromCache: true }) { }, onStopRequest: function(aRequest, aContext, aStatusCode) { if (!Components.isSuccessCode(aStatusCode)) { - deferred.reject("Request failed: " + url); + deferred.reject(new Error("Request failed: " + url)); return; } @@ -2934,6 +2934,7 @@ function convertToUnicode(aString, aCharset=null) { * An optional prefix for the reported error message. */ function reportError(aError, aPrefix="") { + dbg_assert(aError instanceof Error, "Must pass Error objects to reportError"); let msg = aPrefix + aError.message + ":\n" + aError.stack; Cu.reportError(msg); dumpn(msg); From 7155e76d44d1ee8c99850cb65f1f40f170a9207d Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Thu, 11 Jul 2013 15:21:41 -0400 Subject: [PATCH 17/30] Backed out changeset 817ceeb741b4 (bug 888528) for mochitest-other orange. --- toolkit/devtools/server/actors/inspector.js | 40 -------- .../server/tests/mochitest/Makefile.in | 2 - .../mochitest/test_inspector-insert.html | 96 ------------------- .../mochitest/test_inspector-remove.html | 96 ------------------- 4 files changed, 234 deletions(-) delete mode 100644 toolkit/devtools/server/tests/mochitest/test_inspector-insert.html delete mode 100644 toolkit/devtools/server/tests/mochitest/test_inspector-remove.html diff --git a/toolkit/devtools/server/actors/inspector.js b/toolkit/devtools/server/actors/inspector.js index 7c09a8745a85..ac07ad103a8f 100644 --- a/toolkit/devtools/server/actors/inspector.js +++ b/toolkit/devtools/server/actors/inspector.js @@ -1381,46 +1381,6 @@ var WalkerActor = protocol.ActorClass({ } }), - /** - * Removes a node from its parent node. - * - * @returns The node's nextSibling before it was removed. - */ - removeNode: method(function(node) { - if ((node.rawNode.ownerDocument && - node.rawNode.ownerDocument.documentElement === this.rawNode) || - node.rawNode.nodeType === Ci.nsIDOMNode.DOCUMENT_NODE) { - throw Error("Cannot remove document or document elements."); - } - let nextSibling = this.nextSibling(node); - if (node.rawNode.parentNode) { - node.rawNode.parentNode.removeChild(node.rawNode); - // Mutation events will take care of the rest. - } - return nextSibling; - }, { - request: { - node: Arg(0, "domnode") - }, - response: { - nextSibling: RetVal("domnode", { optional: true }) - } - }), - - /** - * Insert a node into the DOM. - */ - insertBefore: method(function(node, parent, sibling) { - parent.rawNode.insertBefore(node.rawNode, sibling ? sibling.rawNode : null); - }, { - request: { - node: Arg(0, "domnode"), - parent: Arg(1, "domnode"), - sibling: Arg(2, "domnode", { optional: true }) - }, - response: {} - }), - /** * Get any pending mutation records. Must be called by the client after * the `new-mutations` notification is received. Returns an array of diff --git a/toolkit/devtools/server/tests/mochitest/Makefile.in b/toolkit/devtools/server/tests/mochitest/Makefile.in index b90c21f7356c..1f0c04a776d3 100644 --- a/toolkit/devtools/server/tests/mochitest/Makefile.in +++ b/toolkit/devtools/server/tests/mochitest/Makefile.in @@ -16,13 +16,11 @@ MOCHITEST_CHROME_FILES = \ inspector-traversal-data.html \ test_inspector-changeattrs.html \ test_inspector-changevalue.html \ - test_inspector-insert.html \ test_inspector-mutations-attr.html \ test_inspector-mutations-childlist.html \ test_inspector-mutations-frameload.html \ test_inspector-mutations-value.html \ test_inspector-release.html \ - test_inspector-remove.html \ test_inspector-retain.html \ test_inspector-pseudoclass-lock.html \ test_inspector-traversal.html \ diff --git a/toolkit/devtools/server/tests/mochitest/test_inspector-insert.html b/toolkit/devtools/server/tests/mochitest/test_inspector-insert.html deleted file mode 100644 index b20121fc0a4d..000000000000 --- a/toolkit/devtools/server/tests/mochitest/test_inspector-insert.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - Test for Bug - - - - - - - -Mozilla Bug -Test Document -

- -
-
- - diff --git a/toolkit/devtools/server/tests/mochitest/test_inspector-remove.html b/toolkit/devtools/server/tests/mochitest/test_inspector-remove.html deleted file mode 100644 index 52a330913925..000000000000 --- a/toolkit/devtools/server/tests/mochitest/test_inspector-remove.html +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - Test for Bug - - - - - - - -Mozilla Bug -Test Document -

- -
-
- - From 983cf574481a307e083cac7075088ed2b9ce3d35 Mon Sep 17 00:00:00 2001 From: Anton Kovalyov Date: Thu, 11 Jul 2013 16:27:56 -0700 Subject: [PATCH 18/30] =?UTF-8?q?Bug=20888881=20-=20Use=20single=20unicode?= =?UTF-8?q?=20character=20=E2=80=A6=20instead=20of=20'...'=20in=20label=20?= =?UTF-8?q?profilerStarted;=20r=3Drobcee?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- browser/devtools/profiler/commands.js | 2 +- browser/devtools/profiler/test/browser_profiler_cmd.js | 2 +- .../en-US/chrome/browser/devtools/gclicommands.properties | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/browser/devtools/profiler/commands.js b/browser/devtools/profiler/commands.js index cbbb9282ffef..e94414bb8c91 100644 --- a/browser/devtools/profiler/commands.js +++ b/browser/devtools/profiler/commands.js @@ -69,7 +69,7 @@ gcli.addCommand({ throw gcli.lookup("profilerAlreadyStarted2"); panel.toggleRecording(); - return gcli.lookup("profilerStarted"); + return gcli.lookup("profilerStarted2"); } return gDevTools.showToolbox(context.environment.target, "jsprofiler") diff --git a/browser/devtools/profiler/test/browser_profiler_cmd.js b/browser/devtools/profiler/test/browser_profiler_cmd.js index 42e00ae30920..db0af1dc1bbc 100644 --- a/browser/devtools/profiler/test/browser_profiler_cmd.js +++ b/browser/devtools/profiler/test/browser_profiler_cmd.js @@ -48,7 +48,7 @@ function testProfilerStart() { deferred.resolve(); }); - cmd("profiler start", gcli.lookup("profilerStarted")); + cmd("profiler start", gcli.lookup("profilerStarted2")); return deferred.promise; } diff --git a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties index 5b1a9ce47e09..ceda6a70e6bd 100644 --- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties +++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties @@ -1251,9 +1251,9 @@ profilerNotFound=Profile not found # start the profiler. profilerNotStarted3=Profiler has not been started yet. Use 'profile start' to start profiling -# LOCALIZATION NOTE (profilerStarted) A very short string that indicates that +# LOCALIZATION NOTE (profilerStarted2) A very short string that indicates that # we have started recording. -profilerStarted=Recording... +profilerStarted2=Recording… # LOCALIZATION NOTE (profilerNotReady) A message that is displayed whenever # an operation cannot be completed because the profiler has not been opened yet. From dad1e71278cbd877a7d3f8a1d26e445529a516de Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 12 Jul 2013 11:03:00 +0200 Subject: [PATCH 19/30] Bug 867550 - Make browser_aboutHome.js not fail if it starts before but runs past midnight; r=mak --- .../base/content/test/browser_aboutHome.js | 119 ++++++++++-------- 1 file changed, 69 insertions(+), 50 deletions(-) diff --git a/browser/base/content/test/browser_aboutHome.js b/browser/base/content/test/browser_aboutHome.js index deb229be479e..12c3080a6b33 100644 --- a/browser/base/content/test/browser_aboutHome.js +++ b/browser/base/content/test/browser_aboutHome.js @@ -89,27 +89,8 @@ let gTests = [ }, { - desc: "Check that performing a search fires a search event.", - setup: function () { }, - run: function () { - let deferred = Promise.defer(); - let doc = gBrowser.contentDocument; - - doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) { - is(e.detail, doc.documentElement.getAttribute("searchEngineName"), "Detail is search engine name"); - - gBrowser.stop(); - deferred.resolve(); - }, true, true); - - doc.getElementById("searchText").value = "it works"; - doc.getElementById("searchSubmit").click(); - return deferred.promise; - } -}, - -{ - desc: "Check that performing a search records to Firefox Health Report.", + desc: "Check that performing a search fires a search event and records to " + + "Firefox Health Report.", setup: function () { }, run: function () { try { @@ -120,46 +101,33 @@ let gTests = [ return Promise.resolve(); } + let numSearchesBefore = 0; let deferred = Promise.defer(); let doc = gBrowser.contentDocument; // We rely on the listener in browser.js being installed and fired before // this one. If this ever changes, we should add an executeSoon() or similar. doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) { - executeSoon(gBrowser.stop.bind(gBrowser)); - let reporter = Components.classes["@mozilla.org/datareporting/service;1"] - .getService() - .wrappedJSObject - .healthReporter; - ok(reporter, "Health Reporter instance available."); + let engineName = doc.documentElement.getAttribute("searchEngineName"); + is(e.detail, engineName, "Detail is search engine name"); - reporter.onInit().then(function onInit() { - let provider = reporter.getProvider("org.mozilla.searches"); - ok(provider, "Searches provider is available."); - - let engineName = doc.documentElement.getAttribute("searchEngineName"); - let id = Services.search.getEngineByName(engineName).identifier; - - let m = provider.getMeasurement("counts", 2); - m.getValues().then(function onValues(data) { - let now = new Date(); - ok(data.days.hasDay(now), "Have data for today."); - - let day = data.days.getDay(now); - let field = id + ".abouthome"; - ok(day.has(field), "Have data for about home on this engine."); - - // Note the search from the previous test. - is(day.get(field), 2, "Have searches recorded."); - - deferred.resolve(); - }); + gBrowser.stop(); + getNumberOfSearches().then(num => { + is(num, numSearchesBefore + 1, "One more search recorded."); + deferred.resolve(); }); }, true, true); - doc.getElementById("searchText").value = "a search"; - doc.getElementById("searchSubmit").click(); + // Get the current number of recorded searches. + getNumberOfSearches().then(num => { + numSearchesBefore = num; + + info("Perform a search."); + doc.getElementById("searchText").value = "a search"; + doc.getElementById("searchSubmit").click(); + }); + return deferred.promise; } }, @@ -422,3 +390,54 @@ function promiseBrowserAttributes(aTab) return deferred.promise; } + +/** + * Retrieves the number of about:home searches recorded for the current day. + * + * @return {Promise} Returns a promise resolving to the number of searches. + */ +function getNumberOfSearches() { + let reporter = Components.classes["@mozilla.org/datareporting/service;1"] + .getService() + .wrappedJSObject + .healthReporter; + ok(reporter, "Health Reporter instance available."); + + return reporter.onInit().then(function onInit() { + let provider = reporter.getProvider("org.mozilla.searches"); + ok(provider, "Searches provider is available."); + + let m = provider.getMeasurement("counts", 2); + return m.getValues().then(data => { + let now = new Date(); + let yday = new Date(now); + yday.setDate(yday.getDate() - 1); + + // Add the number of searches recorded yesterday to the number of searches + // recorded today. This makes the test not fail intermittently when it is + // run at midnight and we accidentally compare the number of searches from + // different days. Tests are always run with an empty profile so there + // are no searches from yesterday, normally. Should the test happen to run + // past midnight we make sure to count them in as well. + return getNumberOfSearchesByDate(data, now) + + getNumberOfSearchesByDate(data, yday); + }); + }); +} + +function getNumberOfSearchesByDate(aData, aDate) { + if (aData.days.hasDay(aDate)) { + let doc = gBrowser.contentDocument; + let engineName = doc.documentElement.getAttribute("searchEngineName"); + let id = Services.search.getEngineByName(engineName).identifier; + + let day = aData.days.getDay(aDate); + let field = id + ".abouthome"; + + if (day.has(field)) { + return day.get(field) || 0; + } + } + + return 0; // No records found. +} From 70ba4e8a2798b19110537189fadfaec6aa728b3e Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 12 Jul 2013 13:35:18 +0200 Subject: [PATCH 20/30] Bug 892766 - SessionStore tests should wait for delayed startup to be finished when opening new windows; r=yoric --- .../test/browser_354894_perwindowpb.js | 147 +++++++----------- .../sessionstore/test/browser_524745.js | 55 ++++--- .../test/browser_819510_perwindowpb.js | 18 +-- .../sessionstore/test/browser_dying_cache.js | 5 +- .../sessionstore/test/browser_input.js | 2 +- .../sessionstore/test/browser_pageshow.js | 2 +- .../test/browser_windowRestore_perwindowpb.js | 4 +- browser/components/sessionstore/test/head.js | 51 +++--- 8 files changed, 115 insertions(+), 169 deletions(-) diff --git a/browser/components/sessionstore/test/browser_354894_perwindowpb.js b/browser/components/sessionstore/test/browser_354894_perwindowpb.js index 78e861ba08fe..d2814dfe7210 100644 --- a/browser/components/sessionstore/test/browser_354894_perwindowpb.js +++ b/browser/components/sessionstore/test/browser_354894_perwindowpb.js @@ -196,18 +196,13 @@ function test() { options = {private: true}; } - let newWin = OpenBrowserWindow(options); - newWin.addEventListener("load", function(aEvent) { - newWin.removeEventListener("load", arguments.callee, false); - newWin.gBrowser.addEventListener("load", function(aEvent) { - newWin.gBrowser.removeEventListener("load", arguments.callee, true); - TEST_URLS.forEach(function (url) { - newWin.gBrowser.addTab(url); - }); + whenNewWindowLoaded(options, function (newWin) { + TEST_URLS.forEach(function (url) { + newWin.gBrowser.addTab(url); + }); - executeSoon(function() testFn(newWin)); - }, true); - }, false); + executeSoon(() => testFn(newWin)); + }); } /** @@ -230,20 +225,16 @@ function test() { // Open a new window // The previously closed window should be restored - newWin = OpenBrowserWindow({}); - newWin.addEventListener("load", function() { - this.removeEventListener("load", arguments.callee, true); - executeSoon(function() { - is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1, - "Restored window in-session with otherpopup windows around"); + whenNewWindowLoaded({}, function (newWin) { + is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1, + "Restored window in-session with otherpopup windows around"); - // Cleanup - newWin.close(); + // Cleanup + newWin.close(); - // Next please - executeSoon(nextFn); - }); - }, true); + // Next please + executeSoon(nextFn); + }); }); } @@ -259,32 +250,24 @@ function test() { // Enter private browsing mode // Open a new window. // The previously closed window should NOT be restored - newWin = OpenBrowserWindow({private: true}); - newWin.addEventListener("load", function() { - this.removeEventListener("load", arguments.callee, true); - executeSoon(function() { - is(newWin.gBrowser.browsers.length, 1, - "Did not restore in private browing mode"); + whenNewWindowLoaded({private: true}, function (newWin) { + is(newWin.gBrowser.browsers.length, 1, + "Did not restore in private browing mode"); - // Cleanup - newWin.BrowserTryToCloseWindow(); + // Cleanup + newWin.BrowserTryToCloseWindow(); - // Exit private browsing mode again - newWin = OpenBrowserWindow({}); - newWin.addEventListener("load", function() { - this.removeEventListener("load", arguments.callee, true); - executeSoon(function() { - is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1, - "Restored after leaving private browsing again"); + // Exit private browsing mode again + whenNewWindowLoaded({}, function (newWin) { + is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1, + "Restored after leaving private browsing again"); - newWin.close(); + newWin.close(); - // Next please - executeSoon(nextFn); - }); - }, true); + // Next please + executeSoon(nextFn); }); - }, true); + }); }); } @@ -312,21 +295,17 @@ function test() { popup2.close(); // open a new window the previously closed window should be restored to - newWin = OpenBrowserWindow({}); - newWin.addEventListener("load", function() { - this.removeEventListener("load", arguments.callee, true); - executeSoon(function() { - is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1, - "Restored window and associated tabs in session"); + whenNewWindowLoaded({}, function (newWin) { + is(newWin.gBrowser.browsers.length, TEST_URLS.length + 1, + "Restored window and associated tabs in session"); - // Cleanup - newWin.close(); - popup.close(); + // Cleanup + newWin.close(); + popup.close(); - // Next please - executeSoon(nextFn); - }); - }, true); + // Next please + executeSoon(nextFn); + }); }, true); }, false); }); @@ -366,22 +345,18 @@ function test() { // but instead a new window is opened without restoring anything popup.close(); - let newWin = OpenBrowserWindow({}); - newWin.addEventListener("load", function() { - newWin.removeEventListener("load", arguments.callee, true); - executeSoon(function() { - isnot(newWin.gBrowser.browsers.length, 2, - "Did not restore the popup window"); - is(TEST_URLS.indexOf(newWin.gBrowser.browsers[0].currentURI.spec), -1, - "Did not restore the popup window (2)"); + whenNewWindowLoaded({}, function (newWin) { + isnot(newWin.gBrowser.browsers.length, 2, + "Did not restore the popup window"); + is(TEST_URLS.indexOf(newWin.gBrowser.browsers[0].currentURI.spec), -1, + "Did not restore the popup window (2)"); - // Cleanup - newWin.close(); + // Cleanup + newWin.close(); - // Next please - executeSoon(nextFn); - }); - }, true); + // Next please + executeSoon(nextFn); + }); }, true); }, false); }, true); @@ -402,27 +377,23 @@ function test() { newWin = undoCloseWindow(0); - newWin2 = OpenBrowserWindow({}); - newWin2.addEventListener("load", function() { - newWin2.removeEventListener("load", arguments.callee, true); - executeSoon(function() { - is(newWin2.gBrowser.browsers.length, 1, - "Did not restore, as undoCloseWindow() was last called"); - is(TEST_URLS.indexOf(newWin2.gBrowser.browsers[0].currentURI.spec), -1, - "Did not restore, as undoCloseWindow() was last called (2)"); + whenNewWindowLoaded({}, function (newWin2) { + is(newWin2.gBrowser.browsers.length, 1, + "Did not restore, as undoCloseWindow() was last called"); + is(TEST_URLS.indexOf(newWin2.gBrowser.browsers[0].currentURI.spec), -1, + "Did not restore, as undoCloseWindow() was last called (2)"); - browserWindowsCount([2, 3], "browser windows while running testOpenCloseRestoreFromPopup"); + browserWindowsCount([2, 3], "browser windows while running testOpenCloseRestoreFromPopup"); - // Cleanup - newWin.close(); - newWin2.close(); + // Cleanup + newWin.close(); + newWin2.close(); - browserWindowsCount([0, 1], "browser windows while running testOpenCloseRestoreFromPopup"); + browserWindowsCount([0, 1], "browser windows while running testOpenCloseRestoreFromPopup"); - // Next please - executeSoon(nextFn); - }); - }, true); + // Next please + executeSoon(nextFn); + }); }); }); } diff --git a/browser/components/sessionstore/test/browser_524745.js b/browser/components/sessionstore/test/browser_524745.js index b531f4c8d2fc..d984ec38b8c9 100644 --- a/browser/components/sessionstore/test/browser_524745.js +++ b/browser/components/sessionstore/test/browser_524745.js @@ -10,37 +10,34 @@ function test() { waitForExplicitFinish(); - let window_B = openDialog(location, "_blank", "chrome,all,dialog=no"); - window_B.addEventListener("load", function(aEvent) { - window_B.removeEventListener("load", arguments.callee, false); + whenNewWindowLoaded({ private: false }, function (window_B) { + waitForFocus(function() { + // Add identifying information to window_B + ss.setWindowValue(window_B, uniqKey, uniqVal); + let state = JSON.parse(ss.getBrowserState()); + let selectedWindow = state.windows[state.selectedWindow - 1]; + is(selectedWindow.extData && selectedWindow.extData[uniqKey], uniqVal, + "selectedWindow is window_B"); + // Now minimize window_B. The selected window shouldn't have the secret data + window_B.minimize(); waitForFocus(function() { - // Add identifying information to window_B - ss.setWindowValue(window_B, uniqKey, uniqVal); - let state = JSON.parse(ss.getBrowserState()); - let selectedWindow = state.windows[state.selectedWindow - 1]; - is(selectedWindow.extData && selectedWindow.extData[uniqKey], uniqVal, - "selectedWindow is window_B"); + state = JSON.parse(ss.getBrowserState()); + selectedWindow = state.windows[state.selectedWindow - 1]; + ok(!selectedWindow.extData || !selectedWindow.extData[uniqKey], + "selectedWindow is not window_B after minimizing it"); - // Now minimize window_B. The selected window shouldn't have the secret data - window_B.minimize(); - waitForFocus(function() { - state = JSON.parse(ss.getBrowserState()); - selectedWindow = state.windows[state.selectedWindow - 1]; - ok(!selectedWindow.extData || !selectedWindow.extData[uniqKey], - "selectedWindow is not window_B after minimizing it"); + // Now minimize the last open window (assumes no other tests left windows open) + window.minimize(); + state = JSON.parse(ss.getBrowserState()); + is(state.selectedWindow, 0, + "selectedWindow should be 0 when all windows are minimized"); - // Now minimize the last open window (assumes no other tests left windows open) - window.minimize(); - state = JSON.parse(ss.getBrowserState()); - is(state.selectedWindow, 0, - "selectedWindow should be 0 when all windows are minimized"); - - // Cleanup - window.restore(); - window_B.close(); - finish(); - }); - }, window_B); - }, false); + // Cleanup + window.restore(); + window_B.close(); + finish(); + }); + }, window_B); + }); } diff --git a/browser/components/sessionstore/test/browser_819510_perwindowpb.js b/browser/components/sessionstore/test/browser_819510_perwindowpb.js index 26937134c68d..087ea4f4a294 100644 --- a/browser/components/sessionstore/test/browser_819510_perwindowpb.js +++ b/browser/components/sessionstore/test/browser_819510_perwindowpb.js @@ -174,23 +174,7 @@ function forceWriteState(aCallback) { } function testOnWindow(aIsPrivate, aCallback) { - let win = OpenBrowserWindow({private: aIsPrivate}); - let gotLoad = false; - let gotActivate = false; - win.addEventListener("activate", function onActivate() { - win.removeEventListener("activate", onActivate, false); - gotActivate = true; - if (gotLoad) { - executeSoon(function() { aCallback(win) }); - } - }, false); - win.addEventListener("load", function onLoad() { - win.removeEventListener("load", onLoad, false); - gotLoad = true; - if (gotActivate) { - executeSoon(function() { aCallback(win) }); - } - }, false); + whenNewWindowLoaded({private: aIsPrivate}, aCallback); } function waitForTabLoad(aWin, aURL, aCallback) { diff --git a/browser/components/sessionstore/test/browser_dying_cache.js b/browser/components/sessionstore/test/browser_dying_cache.js index 41e22d864d3f..169a07539abe 100644 --- a/browser/components/sessionstore/test/browser_dying_cache.js +++ b/browser/components/sessionstore/test/browser_dying_cache.js @@ -14,10 +14,11 @@ function test() { function runTests() { // Open a new window. let win = OpenBrowserWindow(); - yield whenWindowLoaded(win); + yield whenDelayedStartupFinished(win, next); // Load some URL in the current tab. - win.gBrowser.selectedBrowser.loadURI("about:robots"); + let flags = Ci.nsIWebNavigation.LOAD_FLAGS_REPLACE_HISTORY; + win.gBrowser.selectedBrowser.loadURIWithFlags("about:robots", flags); yield whenBrowserLoaded(win.gBrowser.selectedBrowser); // Open a second tab and close the first one. diff --git a/browser/components/sessionstore/test/browser_input.js b/browser/components/sessionstore/test/browser_input.js index 56681ca4fe92..3c135eecec08 100644 --- a/browser/components/sessionstore/test/browser_input.js +++ b/browser/components/sessionstore/test/browser_input.js @@ -19,7 +19,7 @@ function runTests() { // because we always collect data for tabs of active windows no matter if // the window is dirty or not. let win = OpenBrowserWindow(); - yield waitForLoad(win); + yield whenDelayedStartupFinished(win, next); // Create a tab with some form fields. let tab = gBrowser.selectedTab = gBrowser.addTab(URL); diff --git a/browser/components/sessionstore/test/browser_pageshow.js b/browser/components/sessionstore/test/browser_pageshow.js index 0130288e3689..3560b61af59c 100644 --- a/browser/components/sessionstore/test/browser_pageshow.js +++ b/browser/components/sessionstore/test/browser_pageshow.js @@ -23,7 +23,7 @@ function runTests() { // because we always collect data for tabs of active windows no matter if // the window is dirty or not. let win = OpenBrowserWindow(); - yield waitForLoad(win); + yield whenDelayedStartupFinished(win, next); // Create a tab with two history entries. let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank"); diff --git a/browser/components/sessionstore/test/browser_windowRestore_perwindowpb.js b/browser/components/sessionstore/test/browser_windowRestore_perwindowpb.js index 3ee34513816d..ebe774b5b16d 100644 --- a/browser/components/sessionstore/test/browser_windowRestore_perwindowpb.js +++ b/browser/components/sessionstore/test/browser_windowRestore_perwindowpb.js @@ -13,9 +13,7 @@ function test() { // Load a private window, then close it // and verify it doesn't get remembered for restoring - var win = OpenBrowserWindow({private: true}); - - whenWindowLoaded(win, function onload() { + whenNewWindowLoaded({private: true}, function (win) { info("The private window got loaded"); win.addEventListener("SSWindowClosing", function onclosing() { win.removeEventListener("SSWindowClosing", onclosing, false); diff --git a/browser/components/sessionstore/test/head.js b/browser/components/sessionstore/test/head.js index 85c62a9a1722..ac2849b581b4 100644 --- a/browser/components/sessionstore/test/head.js +++ b/browser/components/sessionstore/test/head.js @@ -289,39 +289,34 @@ function closeAllButPrimaryWindow() { } } +/** + * When opening a new window it is not sufficient to wait for its load event. + * We need to use whenDelayedStartupFinshed() here as the browser window's + * delayedStartup() routine is executed one tick after the window's load event + * has been dispatched. browser-delayed-startup-finished might be deferred even + * further if parts of the window's initialization process take more time than + * expected (e.g. reading a big session state from disk). + */ function whenNewWindowLoaded(aOptions, aCallback) { let win = OpenBrowserWindow(aOptions); - let gotLoad = false; - let gotActivate = (Cc["@mozilla.org/focus-manager;1"].getService(Ci.nsIFocusManager).activeWindow == win); - - function maybeRunCallback() { - if (gotLoad && gotActivate) { - win.BrowserChromeTest.runWhenReady(function() { - executeSoon(function() { aCallback(win); }); - }); - } - } - - if (!gotActivate) { - win.addEventListener("activate", function onActivate() { - info("Got activate."); - win.removeEventListener("activate", onActivate, false); - gotActivate = true; - maybeRunCallback(); - }, false); - } else { - info("Was activated."); - } - - win.addEventListener("load", function onLoad() { - info("Got load"); - win.removeEventListener("load", onLoad, false); - gotLoad = true; - maybeRunCallback(); - }, false); + whenDelayedStartupFinished(win, () => aCallback(win)); return win; } +/** + * This waits for the browser-delayed-startup-finished notification of a given + * window. It indicates that the windows has loaded completely and is ready to + * be used for testing. + */ +function whenDelayedStartupFinished(aWindow, aCallback) { + Services.obs.addObserver(function observer(aSubject, aTopic) { + if (aWindow == aSubject) { + Services.obs.removeObserver(observer, aTopic); + executeSoon(aCallback); + } + }, "browser-delayed-startup-finished", false); +} + /** * The test runner that controls the execution flow of our tests. */ From 6b014f1dd8e99f097ac642b2b1dbbc77147babdc Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 12 Jul 2013 13:46:14 +0200 Subject: [PATCH 21/30] Bug 891360 - Move SessionStore I/O logic to a dedicated worker; r=yoric --- .../sessionstore/src/SessionStore.jsm | 20 +- .../sessionstore/src/SessionWorker.js | 221 +++++++++++++++ .../sessionstore/src/_SessionFile.jsm | 253 +++++------------- browser/components/sessionstore/src/moz.build | 1 + .../test/browser_833286_atomic_backup.js | 6 +- .../sessionstore/test/unit/test_backup.js | 6 +- 6 files changed, 313 insertions(+), 194 deletions(-) create mode 100644 browser/components/sessionstore/src/SessionWorker.js diff --git a/browser/components/sessionstore/src/SessionStore.jsm b/browser/components/sessionstore/src/SessionStore.jsm index 11932edd82a9..8e92478278bd 100644 --- a/browser/components/sessionstore/src/SessionStore.jsm +++ b/browser/components/sessionstore/src/SessionStore.jsm @@ -460,7 +460,11 @@ let SessionStoreInternal = { // A Lazy getter for the sessionstore.js backup promise. XPCOMUtils.defineLazyGetter(this, "_backupSessionFileOnce", function () { - return _SessionFile.createBackupCopy(); + // We're creating a backup of sessionstore.js by moving it to .bak + // because that's a lot faster than creating a copy. sessionstore.js + // would be overwritten shortly afterwards anyway so we can save time + // and just move instead of copy. + return _SessionFile.moveToBackupPath(); }); // at this point, we've as good as resumed the session, so we can @@ -504,12 +508,12 @@ let SessionStoreInternal = { return Task.spawn(function task() { try { // Perform background backup - yield _SessionFile.createUpgradeBackupCopy("-" + buildID); + yield _SessionFile.createBackupCopy("-" + buildID); this._prefBranch.setCharPref(PREF_UPGRADE, buildID); // In case of success, remove previous backup. - yield _SessionFile.removeUpgradeBackup("-" + latestBackup); + yield _SessionFile.removeBackupCopy("-" + latestBackup); } catch (ex) { debug("Could not perform upgrade backup " + ex); debug(ex.stack); @@ -772,12 +776,12 @@ let SessionStoreInternal = { this._restoreCount = this._initialState.windows ? this._initialState.windows.length : 0; this.restoreWindow(aWindow, this._initialState, this._isCmdLineEmpty(aWindow, this._initialState)); - - // _loadState changed from "stopped" to "running" - // force a save operation so that crashes happening during startup are correctly counted - this._initialState.session.state = STATE_RUNNING_STR; - this._saveStateObject(this._initialState); this._initialState = null; + + // _loadState changed from "stopped" to "running". Save the session's + // load state immediately so that crashes happening during startup + // are correctly counted. + _SessionFile.writeLoadStateOnceAfterStartup(STATE_RUNNING_STR); } } else { diff --git a/browser/components/sessionstore/src/SessionWorker.js b/browser/components/sessionstore/src/SessionWorker.js new file mode 100644 index 000000000000..c0d988261ebb --- /dev/null +++ b/browser/components/sessionstore/src/SessionWorker.js @@ -0,0 +1,221 @@ +/* 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/. */ + +/** + * A worker dedicated to handle I/O for Session Store. + */ + +"use strict"; + +importScripts("resource://gre/modules/osfile.jsm"); + +let File = OS.File; +let Encoder = new TextEncoder(); +let Decoder = new TextDecoder(); + +/** + * Communications with the controller. + * + * Accepts messages: + * {fun:function_name, args:array_of_arguments_or_null, id: custom_id} + * + * Sends messages: + * {ok: result, id: custom_id} / {fail: serialized_form_of_OS.File.Error, + * id: custom_id} + */ +self.onmessage = function (msg) { + let data = msg.data; + if (!(data.fun in Agent)) { + throw new Error("Cannot find method " + data.fun); + } + + let result; + let id = data.id; + + try { + result = Agent[data.fun].apply(Agent, data.args); + } catch (ex if ex instanceof OS.File.Error) { + // Instances of OS.File.Error know how to serialize themselves + // (deserialization ensures that we end up with OS-specific + // instances of |OS.File.Error|) + self.postMessage({fail: OS.File.Error.toMsg(ex), id: id}); + return; + } + + // Other exceptions do not, and should be propagated through DOM's + // built-in mechanism for uncaught errors, although this mechanism + // may lose interesting information. + self.postMessage({ok: result, id: id}); +}; + +let Agent = { + // The initial session string as read from disk. + initialState: null, + + // Boolean that tells whether we already wrote + // the loadState to disk once after startup. + hasWrittenLoadStateOnce: false, + + // The path to sessionstore.js + path: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"), + + // The path to sessionstore.bak + backupPath: OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.bak"), + + /** + * This method is only intended to be called by _SessionFile.syncRead() and + * can be removed when we're not supporting synchronous SessionStore + * initialization anymore. When sessionstore.js is read from disk + * synchronously the state string must be supplied to the worker manually by + * calling this method. + */ + setInitialState: function (aState) { + // _SessionFile.syncRead() should not be called after startup has finished. + // Thus we also don't support any setInitialState() calls after we already + // wrote the loadState to disk. + if (this.hasWrittenLoadStateOnce) { + throw new Error("writeLoadStateOnceAfterStartup() must only be called once."); + } + + // Initial state might have been filled by read() already but yet we might + // be called by _SessionFile.syncRead() before SessionStore.jsm had a chance + // to call writeLoadStateOnceAfterStartup(). It's safe to ignore + // setInitialState() calls if this happens. + if (!this.initialState) { + this.initialState = aState; + } + }, + + /** + * Read the session from disk. + * In case sessionstore.js does not exist, attempt to read sessionstore.bak. + */ + read: function () { + for (let path of [this.path, this.backupPath]) { + try { + return this.initialState = Decoder.decode(File.read(path)); + } catch (ex if isNoSuchFileEx(ex)) { + // Ignore exceptions about non-existent files. + } + } + + // No sessionstore data files found. Return an empty string. + return ""; + }, + + /** + * Write the session to disk. + */ + write: function (stateString) { + let bytes = Encoder.encode(stateString); + return File.writeAtomic(this.path, bytes, {tmpPath: this.path + ".tmp"}); + }, + + /** + * Writes the session state to disk again but changes session.state to + * 'running' before doing so. This is intended to be called only once, shortly + * after startup so that we detect crashes on startup correctly. + */ + writeLoadStateOnceAfterStartup: function (loadState) { + if (this.hasWrittenLoadStateOnce) { + throw new Error("writeLoadStateOnceAfterStartup() must only be called once."); + } + + if (!this.initialState) { + throw new Error("writeLoadStateOnceAfterStartup() must not be called " + + "without a valid session state or before it has been " + + "read from disk."; + } + + // Make sure we can't call this function twice. + this.hasWrittenLoadStateOnce = true; + + let state; + try { + state = JSON.parse(this.initialState); + } finally { + this.initialState = null; + } + + state.session = state.session || {}; + state.session.state = loadState; + return this.write(JSON.stringify(state)); + }, + + /** + * Moves sessionstore.js to sessionstore.bak. + */ + moveToBackupPath: function () { + try { + return File.move(this.path, this.backupPath); + } catch (ex if isNoSuchFileEx(ex)) { + // Ignore exceptions about non-existent files. + return true; + } + }, + + /** + * Creates a copy of sessionstore.js. + */ + createBackupCopy: function (ext) { + try { + return File.copy(this.path, this.backupPath + ext); + } catch (ex if isNoSuchFileEx(ex)) { + // Ignore exceptions about non-existent files. + return true; + } + }, + + /** + * Removes a backup copy. + */ + removeBackupCopy: function (ext) { + try { + return File.remove(this.backupPath + ext); + } catch (ex if isNoSuchFileEx(ex)) { + // Ignore exceptions about non-existent files. + return true; + } + }, + + /** + * Wipes all files holding session data from disk. + */ + wipe: function () { + let exn; + + // Erase session state file + try { + File.remove(this.path); + } catch (ex if isNoSuchFileEx(ex)) { + // Ignore exceptions about non-existent files. + } catch (ex) { + // Don't stop immediately. + exn = ex; + } + + // Erase any backup, any file named "sessionstore.bak[-buildID]". + let iter = new File.DirectoryIterator(OS.Constants.Path.profileDir); + for (let entry in iter) { + if (!entry.isDir && entry.path.startsWith(this.backupPath)) { + try { + File.remove(entry.path); + } catch (ex) { + // Don't stop immediately. + exn = exn || ex; + } + } + } + + if (exn) { + throw exn; + } + + return true; + } +}; + +function isNoSuchFileEx(aReason) { + return aReason instanceof OS.File.Error && aReason.becauseNoSuchFile; +} diff --git a/browser/components/sessionstore/src/_SessionFile.jsm b/browser/components/sessionstore/src/_SessionFile.jsm index 83afb92d4f47..4a69b36be470 100644 --- a/browser/components/sessionstore/src/_SessionFile.jsm +++ b/browser/components/sessionstore/src/_SessionFile.jsm @@ -32,6 +32,7 @@ const Ci = Components.interfaces; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/osfile.jsm"); +Cu.import("resource://gre/modules/osfile/_PromiseWorker.jsm", this); Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js"); XPCOMUtils.defineLazyModuleGetter(this, "TelemetryStopwatch", @@ -44,66 +45,62 @@ XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "Telemetry", "@mozilla.org/base/telemetry;1", "nsITelemetry"); - -// An encoder to UTF-8. -XPCOMUtils.defineLazyGetter(this, "gEncoder", function () { - return new TextEncoder(); -}); -// A decoder. -XPCOMUtils.defineLazyGetter(this, "gDecoder", function () { - return new TextDecoder(); -}); +XPCOMUtils.defineLazyModuleGetter(this, "Deprecated", + "resource://gre/modules/Deprecated.jsm"); this._SessionFile = { - /** - * A promise fulfilled once initialization (either synchronous or - * asynchronous) is complete. - */ - promiseInitialized: function SessionFile_initialized() { - return SessionFileInternal.promiseInitialized; - }, /** * Read the contents of the session file, asynchronously. */ - read: function SessionFile_read() { + read: function () { return SessionFileInternal.read(); }, /** * Read the contents of the session file, synchronously. */ - syncRead: function SessionFile_syncRead() { + syncRead: function () { + Deprecated.warning( + "syncRead is deprecated and will be removed in a future version", + "https://bugzilla.mozilla.org/show_bug.cgi?id=532150") return SessionFileInternal.syncRead(); }, /** * Write the contents of the session file, asynchronously. */ - write: function SessionFile_write(aData) { + write: function (aData) { return SessionFileInternal.write(aData); }, + /** + * Writes the initial state to disk again only to change the session's load + * state. This must only be called once, it will throw an error otherwise. + */ + writeLoadStateOnceAfterStartup: function (aLoadState) { + return SessionFileInternal.writeLoadStateOnceAfterStartup(aLoadState); + }, /** * Create a backup copy, asynchronously. */ - createBackupCopy: function SessionFile_createBackupCopy() { - return SessionFileInternal.createBackupCopy(); + moveToBackupPath: function () { + return SessionFileInternal.moveToBackupPath(); }, /** * Create a backup copy, asynchronously. * This is designed to perform backup on upgrade. */ - createUpgradeBackupCopy: function(ext) { - return SessionFileInternal.createUpgradeBackupCopy(ext); + createBackupCopy: function (ext) { + return SessionFileInternal.createBackupCopy(ext); }, /** * Remove a backup copy, asynchronously. * This is designed to clean up a backup on upgrade. */ - removeUpgradeBackup: function(ext) { - return SessionFileInternal.removeUpgradeBackup(ext); + removeBackupCopy: function (ext) { + return SessionFileInternal.removeBackupCopy(ext); }, /** * Wipe the contents of the session file, asynchronously. */ - wipe: function SessionFile_wipe() { + wipe: function () { return SessionFileInternal.wipe(); } }; @@ -147,11 +144,6 @@ const TaskUtils = { }; let SessionFileInternal = { - /** - * A promise fulfilled once initialization is complete - */ - promiseInitialized: Promise.defer(), - /** * The path to sessionstore.js */ @@ -168,7 +160,7 @@ let SessionFileInternal = { * A path to read the file from. * @returns string if successful, undefined otherwise. */ - readAuxSync: function ssfi_readAuxSync(aPath) { + readAuxSync: function (aPath) { let text; try { let file = new FileUtils.File(aPath); @@ -197,7 +189,7 @@ let SessionFileInternal = { * happened between backup and write), attempt to read the sessionstore.bak * instead. */ - syncRead: function ssfi_syncRead() { + syncRead: function () { // Start measuring the duration of the synchronous read. TelemetryStopwatch.start("FX_SESSION_RESTORE_SYNC_READ_FILE_MS"); // First read the sessionstore.js. @@ -208,83 +200,26 @@ let SessionFileInternal = { } // Finish the telemetry probe and return an empty string. TelemetryStopwatch.finish("FX_SESSION_RESTORE_SYNC_READ_FILE_MS"); - return text || ""; + text = text || ""; + + // The worker needs to know the initial state read from + // disk so that writeLoadStateOnceAfterStartup() works. + SessionWorker.post("setInitialState", [text]); + return text; }, - /** - * Utility function to safely read a file asynchronously. - * @param aPath - * A path to read the file from. - * @param aReadOptions - * Read operation options. - * |outExecutionDuration| option will be reused and can be - * incrementally updated by the worker process. - * @returns string if successful, undefined otherwise. - */ - readAux: function ssfi_readAux(aPath, aReadOptions) { - let self = this; - return TaskUtils.spawn(function () { - let text; - try { - let bytes = yield OS.File.read(aPath, undefined, aReadOptions); - text = gDecoder.decode(bytes); - // If the file is read successfully, add a telemetry probe based on - // the updated duration value of the |outExecutionDuration| option. - let histogram = Telemetry.getHistogramById( - "FX_SESSION_RESTORE_READ_FILE_MS"); - histogram.add(aReadOptions.outExecutionDuration); - } catch (ex if self._isNoSuchFile(ex)) { - // Ignore exceptions about non-existent files. - } catch (ex) { - Cu.reportError(ex); - } - throw new Task.Result(text); - }); + read: function () { + return SessionWorker.post("read").then(msg => msg.ok); }, - /** - * Read the sessionstore file asynchronously. - * - * In case sessionstore.js file does not exist or is corrupted (something - * happened between backup and write), attempt to read the sessionstore.bak - * instead. - */ - read: function ssfi_read() { - let self = this; - return TaskUtils.spawn(function task() { - // Specify |outExecutionDuration| option to hold the combined duration of - // the asynchronous reads off the main thread (of both sessionstore.js and - // sessionstore.bak, if necessary). If sessionstore.js does not exist or - // is corrupted, |outExecutionDuration| will register the time it took to - // attempt to read the file. It will then be subsequently incremented by - // the read time of sessionsore.bak. - let readOptions = { - outExecutionDuration: null - }; - // First read the sessionstore.js. - let text = yield self.readAux(self.path, readOptions); - if (typeof text === "undefined") { - // If sessionstore.js does not exist or is corrupted, read the - // sessionstore.bak. - text = yield self.readAux(self.backupPath, readOptions); - } - // Return either the content of the sessionstore.bak if it was read - // successfully or an empty string otherwise. - throw new Task.Result(text || ""); - }); - }, - - write: function ssfi_write(aData) { + write: function (aData) { let refObj = {}; - let self = this; return TaskUtils.spawn(function task() { TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj); TelemetryStopwatch.start("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj); - let bytes = gEncoder.encode(aData); - try { - let promise = OS.File.writeAtomic(self.path, bytes, {tmpPath: self.path + ".tmp"}); + let promise = SessionWorker.post("write", [aData]); // At this point, we measure how long we stop the main thread TelemetryStopwatch.finish("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj); @@ -294,93 +229,51 @@ let SessionFileInternal = { } catch (ex) { TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_LONGEST_OP_MS", refObj); TelemetryStopwatch.cancel("FX_SESSION_RESTORE_WRITE_FILE_MS", refObj); - Cu.reportError("Could not write session state file " + self.path - + ": " + aReason); - } - }); - }, - - createBackupCopy: function ssfi_createBackupCopy() { - let backupCopyOptions = { - outExecutionDuration: null - }; - let self = this; - return TaskUtils.spawn(function task() { - try { - yield OS.File.move(self.path, self.backupPath, backupCopyOptions); - Telemetry.getHistogramById("FX_SESSION_RESTORE_BACKUP_FILE_MS").add( - backupCopyOptions.outExecutionDuration); - } catch (ex if self._isNoSuchFile(ex)) { - // Ignore exceptions about non-existent files. - } catch (ex) { - Cu.reportError("Could not backup session state file: " + ex); - throw ex; - } - }); - }, - - createUpgradeBackupCopy: function(ext) { - return TaskUtils.spawn(function task() { - try { - yield OS.File.copy(this.path, this.backupPath + ext); - } catch (ex if this._isNoSuchFile(ex)) { - // Ignore exceptions about non-existent files. - } catch (ex) { - Cu.reportError("Could not backup session state file to " + - dest + ": " + ex); - throw ex; + Cu.reportError("Could not write session state file " + this.path + + ": " + ex); } }.bind(this)); }, - removeUpgradeBackup: function(ext) { - return TaskUtils.spawn(function task() { - try { - yield OS.File.remove(this.backupPath + ext); - } catch (ex if this._isNoSuchFile(ex)) { - // Ignore exceptions about non-existent files. - } - }.bind(this)); + writeLoadStateOnceAfterStartup: function (aLoadState) { + return SessionWorker.post("writeLoadStateOnceAfterStartup", [aLoadState]); }, - wipe: function ssfi_wipe() { - let self = this; - return TaskUtils.spawn(function task() { - let exn; - // Erase session state file - try { - yield OS.File.remove(self.path); - } catch (ex if self._isNoSuchFile(ex)) { - // Ignore exceptions about non-existent files. - } catch (ex) { - // Report error, don't stop immediately - Cu.reportError("Could not remove session state file: " + ex); - exn = ex; - } - - // Erase any backup, any file named "sessionstore.bak[-buildID]". - let iterator = new OS.File.DirectoryIterator(OS.Constants.Path.profileDir); - for (let promise of iterator) { - let entry = yield promise; - if (!entry.isDir && entry.path.startsWith(self.backupPath)) { - try { - yield OS.File.remove(entry.path); - } catch (ex) { - // Report error, don't stop immediately - Cu.reportError("Could not remove backup file " + entry.path + " : " + ex); - exn = exn || ex; - } - } - } - - if (exn) { - throw exn; - } - }); - + moveToBackupPath: function () { + return SessionWorker.post("moveToBackupPath"); }, - _isNoSuchFile: function ssfi_isNoSuchFile(aReason) { - return aReason instanceof OS.File.Error && aReason.becauseNoSuchFile; + createBackupCopy: function (ext) { + return SessionWorker.post("createBackupCopy", [ext]); + }, + + removeBackupCopy: function (ext) { + return SessionWorker.post("removeBackupCopy", [ext]); + }, + + wipe: function () { + return SessionWorker.post("wipe"); } }; + +// Interface to a dedicated thread handling I/O +let SessionWorker = (function () { + let worker = new PromiseWorker("resource:///modules/sessionstore/SessionWorker.js", + OS.Shared.LOG.bind("SessionWorker")); + return { + post: function post(...args) { + let promise = worker.post.apply(worker, args); + return promise.then( + null, + function onError(error) { + // Decode any serialized error + if (error instanceof PromiseWorker.WorkerError) { + throw OS.File.Error.fromMsg(error.data); + } else { + throw error; + } + } + ); + } + }; +})(); diff --git a/browser/components/sessionstore/src/moz.build b/browser/components/sessionstore/src/moz.build index bdd2ee4c1040..41e67e1b7658 100644 --- a/browser/components/sessionstore/src/moz.build +++ b/browser/components/sessionstore/src/moz.build @@ -16,6 +16,7 @@ EXTRA_JS_MODULES = [ 'DocumentUtils.jsm', 'SessionMigration.jsm', 'SessionStorage.jsm', + 'SessionWorker.js', 'XPathGenerator.jsm', '_SessionFile.jsm', ] diff --git a/browser/components/sessionstore/test/browser_833286_atomic_backup.js b/browser/components/sessionstore/test/browser_833286_atomic_backup.js index bc21ae399838..a04a6ed8ce5c 100644 --- a/browser/components/sessionstore/test/browser_833286_atomic_backup.js +++ b/browser/components/sessionstore/test/browser_833286_atomic_backup.js @@ -78,9 +78,9 @@ function testWriteNoBackup() { let array = yield OS.File.read(path); gSSData = gDecoder.decode(array); - // Manually trigger _SessionFile.createBackupCopy since the backup once + // Manually trigger _SessionFile.moveToBackupPath since the backup once // promise is already resolved and backup would not be triggered again. - yield _SessionFile.createBackupCopy(); + yield _SessionFile.moveToBackupPath(); nextTest(testWriteBackup); } @@ -140,4 +140,4 @@ function testNoWriteBackup() { is(ssBakData, gSSBakData, "sessionstore.bak is unchanged."); executeSoon(finish); -} \ No newline at end of file +} diff --git a/browser/components/sessionstore/test/unit/test_backup.js b/browser/components/sessionstore/test/unit/test_backup.js index 5efa4358c72e..9e25b966cf91 100644 --- a/browser/components/sessionstore/test/unit/test_backup.js +++ b/browser/components/sessionstore/test/unit/test_backup.js @@ -19,7 +19,7 @@ function pathBackup(ext) { // Ensure that things proceed smoothly if there is no file to back up add_task(function test_nothing_to_backup() { - yield _SessionFile.createUpgradeBackupCopy(""); + yield _SessionFile.createBackupCopy(""); }); // Create a file, back it up, remove it @@ -29,14 +29,14 @@ add_task(function test_do_backup() { yield OS.File.writeAtomic(pathStore, content, {tmpPath: pathStore + ".tmp"}); do_print("Ensuring that the backup is created"); - yield _SessionFile.createUpgradeBackupCopy(ext); + yield _SessionFile.createBackupCopy(ext); do_check_true((yield OS.File.exists(pathBackup(ext)))); let data = yield OS.File.read(pathBackup(ext)); do_check_eq((new TextDecoder()).decode(data), content); do_print("Ensuring that we can remove the backup"); - yield _SessionFile.removeUpgradeBackup(ext); + yield _SessionFile.removeBackupCopy(ext); do_check_false((yield OS.File.exists(pathBackup(ext)))); }); From 7b669f895b1e0f890a14c1ab4d31ac5b3515f184 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 12 Jul 2013 14:00:00 +0200 Subject: [PATCH 22/30] Bug 891360 - Follow-up to fix syntax error; r=bustage --- browser/components/sessionstore/src/SessionWorker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/components/sessionstore/src/SessionWorker.js b/browser/components/sessionstore/src/SessionWorker.js index c0d988261ebb..a4d17813ce9d 100644 --- a/browser/components/sessionstore/src/SessionWorker.js +++ b/browser/components/sessionstore/src/SessionWorker.js @@ -125,7 +125,7 @@ let Agent = { if (!this.initialState) { throw new Error("writeLoadStateOnceAfterStartup() must not be called " + "without a valid session state or before it has been " + - "read from disk."; + "read from disk."); } // Make sure we can't call this function twice. From ae97627a6479974282d825f2cfae80ac05652b5c Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Fri, 12 Jul 2013 14:59:18 +0200 Subject: [PATCH 23/30] Bug 890409 - Disable browser_aboutHome.js for intermittent failures; rs=mak --- browser/base/content/test/Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/base/content/test/Makefile.in b/browser/base/content/test/Makefile.in index 1dc05eaed6d6..cbed37e69219 100644 --- a/browser/base/content/test/Makefile.in +++ b/browser/base/content/test/Makefile.in @@ -51,6 +51,7 @@ endif # The following tests are disabled because they are unreliable: # browser_bug423833.js is bug 428712 # browser_sanitize-download-history.js is bug 432425 +# browser_aboutHome.js is bug 890409 # # browser_sanitizeDialog_treeView.js is disabled until the tree view is added # back to the clear recent history dialog (sanitize.xul), if it ever is (bug @@ -71,7 +72,6 @@ MOCHITEST_BROWSER_FILES = \ blockPluginVulnerableNoUpdate.xml \ blockPluginVulnerableUpdatable.xml \ browser_aboutHealthReport.js \ - browser_aboutHome.js \ browser_aboutSyncProgress.js \ browser_addKeywordSearch.js \ browser_addon_bar_aomlistener.js \ From 9a12bc256f11fed9a3733fa411ddbab012db1a0b Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Fri, 12 Jul 2013 09:33:50 -0400 Subject: [PATCH 24/30] Bug 886897 - Call VideoFrameContainer::ClearCurrentFrame() before camera hw close. r=mikeh --- dom/camera/CameraPreviewMediaStream.cpp | 14 ++++++++++++++ dom/camera/CameraPreviewMediaStream.h | 1 + dom/camera/DOMCameraPreview.cpp | 2 ++ 3 files changed, 17 insertions(+) diff --git a/dom/camera/CameraPreviewMediaStream.cpp b/dom/camera/CameraPreviewMediaStream.cpp index 787d84d3215e..ad2dd967f816 100644 --- a/dom/camera/CameraPreviewMediaStream.cpp +++ b/dom/camera/CameraPreviewMediaStream.cpp @@ -121,4 +121,18 @@ CameraPreviewMediaStream::SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Imag } } +void +CameraPreviewMediaStream::ClearCurrentFrame() +{ + MutexAutoLock lock(mMutex); + + for (uint32_t i = 0; i < mVideoOutputs.Length(); ++i) { + VideoFrameContainer* output = mVideoOutputs[i]; + output->ClearCurrentFrame(); + nsCOMPtr event = + NS_NewRunnableMethod(output, &VideoFrameContainer::Invalidate); + NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL); + } +} + } diff --git a/dom/camera/CameraPreviewMediaStream.h b/dom/camera/CameraPreviewMediaStream.h index abdd4c7db69a..c5615164b45b 100644 --- a/dom/camera/CameraPreviewMediaStream.h +++ b/dom/camera/CameraPreviewMediaStream.h @@ -42,6 +42,7 @@ public: // Call these on any thread. void SetCurrentFrame(const gfxIntSize& aIntrinsicSize, Image* aImage); + void ClearCurrentFrame(); void SetFrameCallback(CameraPreviewFrameCallback* aCallback) { mFrameCallback = aCallback; diff --git a/dom/camera/DOMCameraPreview.cpp b/dom/camera/DOMCameraPreview.cpp index bcee68293370..189130c2988e 100644 --- a/dom/camera/DOMCameraPreview.cpp +++ b/dom/camera/DOMCameraPreview.cpp @@ -287,6 +287,8 @@ DOMCameraPreview::Stopped(bool aForced) return; } + mInput->ClearCurrentFrame(); + DOM_CAMERA_LOGI("Dispatching preview stream stopped\n"); nsCOMPtr stopped = new PreviewControl(this, PreviewControl::STOPPED); nsresult rv = NS_DispatchToMainThread(stopped); From 51a4d89fe27db4f04c2a2e34217aec2a2c72a85b Mon Sep 17 00:00:00 2001 From: Gaia Pushbot Date: Fri, 12 Jul 2013 07:05:23 -0700 Subject: [PATCH 25/30] Bumping gaia.json for 2 gaia-central revision(s) ======== https://hg.mozilla.org/integration/gaia-central/rev/d3bf1e5466f0 Author: Fabien Cazenave Desc: Merge pull request #10943 from fabi1cazenave/mmsAttachmentContainers-bug889899 Bug 889899: use
instead of