зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound. a=merge
This commit is contained in:
Коммит
e8471bb514
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
|
@ -131,10 +131,10 @@
|
|||
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="197cd9492b9fadaa915c5daf36ff557f8f4a8d1c"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
|
||||
<project name="libnfcemu" path="external/libnfcemu" remote="b2g" revision="125ccf9bd5986c7728ea44508b3e1d1185ac028b"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d259117b4976decbe2f76eeed85218bf0109190f"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c5f8d282efe4a4e8b1e31a37300944e338e60e4f"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d872fc1462d367eb67833de6942c297d6c4dc874"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a28a47cf4de9cc676e8a14d58826f7927d77f5d5"/>
|
||||
<project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
|
||||
<project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
|
||||
</manifest>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -151,7 +151,7 @@
|
|||
<project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/>
|
||||
<project name="platform/system/core" path="system/core" revision="350eac5403124dacb2a5fd9e28ac290a59fc3b8e"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d872fc1462d367eb67833de6942c297d6c4dc874"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a28a47cf4de9cc676e8a14d58826f7927d77f5d5"/>
|
||||
<project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/>
|
||||
<project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/>
|
||||
<project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="7704e16da545f4207812e593743d6743e1afb9c5"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
|
@ -145,7 +145,7 @@
|
|||
<project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
|
||||
<project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
|
||||
<project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d872fc1462d367eb67833de6942c297d6c4dc874"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a28a47cf4de9cc676e8a14d58826f7927d77f5d5"/>
|
||||
<project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
|
||||
<project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
|
||||
<project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "ce8e42aa3688f56113d68bc82409a7fea055547b",
|
||||
"revision": "2bf3274b9e149c6a0ffc13be4c7d3a2f7236e311",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="9f6b7471c881ee689183d681658cf2ba3dfc5610"/>
|
||||
|
@ -129,7 +129,7 @@
|
|||
<project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
|
||||
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
|
||||
<project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="d872fc1462d367eb67833de6942c297d6c4dc874"/>
|
||||
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="a28a47cf4de9cc676e8a14d58826f7927d77f5d5"/>
|
||||
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
|
||||
<project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="3ec94f448bb5c1c9c264896685c6ef77ab718c87"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="82174cee5ede9f23aedad8a39f8b8cdc1ae710c4"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="73d68c9c91bc568ce7c888ac057b3f44bd1b2e79"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
|
|
@ -2576,8 +2576,8 @@ let BrowserOnClick = {
|
|||
TabCrashReporter.submitCrashReport(browser);
|
||||
}
|
||||
#endif
|
||||
|
||||
TabCrashReporter.reloadCrashedTab(browser);
|
||||
let tab = gBrowser.getTabForBrowser(browser);
|
||||
SessionStore.reviveCrashedTab(tab);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -44,7 +44,8 @@ const WINDOW_HIDEABLE_FEATURES = [
|
|||
"menubar", "toolbar", "locationbar", "personalbar", "statusbar", "scrollbars"
|
||||
];
|
||||
|
||||
const MESSAGES = [
|
||||
// Messages that will be received via the Frame Message Manager.
|
||||
const FMM_MESSAGES = [
|
||||
// The content script gives us a reference to an object that performs
|
||||
// synchronous collection of session data.
|
||||
"SessionStore:setupSyncHandler",
|
||||
|
@ -73,6 +74,16 @@ const MESSAGES = [
|
|||
"SessionStore:reloadPendingTab",
|
||||
];
|
||||
|
||||
// Messages that will be received via the Parent Process Message Manager.
|
||||
const PPMM_MESSAGES = [
|
||||
// A tab is being revived from the crashed state. The sender of this
|
||||
// message should actually be running in the parent process, since this
|
||||
// will be the crashed tab interface. We use the Child and Parent Process
|
||||
// Message Managers because the message is sent during framescript unload
|
||||
// when the Frame Message Manager is not available.
|
||||
"SessionStore:RemoteTabRevived",
|
||||
];
|
||||
|
||||
// These are tab events that we listen to.
|
||||
const TAB_EVENTS = [
|
||||
"TabOpen", "TabClose", "TabSelect", "TabShow", "TabHide", "TabPinned",
|
||||
|
@ -97,7 +108,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "gScreenManager",
|
|||
"@mozilla.org/gfx/screenmanager;1", "nsIScreenManager");
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "Telemetry",
|
||||
"@mozilla.org/base/telemetry;1", "nsITelemetry");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageListenerManager");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "console",
|
||||
"resource://gre/modules/devtools/Console.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow",
|
||||
|
@ -263,6 +276,10 @@ this.SessionStore = {
|
|||
return SessionStoreInternal.getCurrentState(aUpdateAll);
|
||||
},
|
||||
|
||||
reviveCrashedTab(aTab) {
|
||||
return SessionStoreInternal.reviveCrashedTab(aTab);
|
||||
},
|
||||
|
||||
/**
|
||||
* Backstage pass to implementation details, used for testing purpose.
|
||||
* Controlled by preference "browser.sessionstore.testmode".
|
||||
|
@ -297,6 +314,11 @@ let SessionStoreInternal = {
|
|||
// For each <browser> element being restored, records the current epoch.
|
||||
_browserEpochs: new WeakMap(),
|
||||
|
||||
// Any browsers that fires the oop-browser-crashed event gets stored in
|
||||
// here - that way we know which browsers to ignore messages from (until
|
||||
// they get restored).
|
||||
_crashedBrowsers: new WeakSet(),
|
||||
|
||||
// whether a setBrowserState call is in progress
|
||||
_browserSetState: false,
|
||||
|
||||
|
@ -383,6 +405,8 @@ let SessionStoreInternal = {
|
|||
Services.obs.addObserver(this, aTopic, true);
|
||||
}, this);
|
||||
|
||||
PPMM_MESSAGES.forEach(msg => ppmm.addMessageListener(msg, this));
|
||||
|
||||
this._initPrefs();
|
||||
this._initialized = true;
|
||||
},
|
||||
|
@ -509,6 +533,8 @@ let SessionStoreInternal = {
|
|||
|
||||
// Make sure to cancel pending saves.
|
||||
SessionSaver.cancel();
|
||||
|
||||
PPMM_MESSAGES.forEach(msg => ppmm.removeMessageListener(msg, this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -551,9 +577,18 @@ let SessionStoreInternal = {
|
|||
|
||||
/**
|
||||
* This method handles incoming messages sent by the session store content
|
||||
* script and thus enables communication with OOP tabs.
|
||||
* script via the Frame Message Manager or Parent Process Message Manager,
|
||||
* and thus enables communication with OOP tabs.
|
||||
*/
|
||||
receiveMessage: function ssi_receiveMessage(aMessage) {
|
||||
receiveMessage(aMessage) {
|
||||
// We'll deal with any Parent Process Message Manager messages first...
|
||||
if (aMessage.name == "SessionStore:RemoteTabRevived") {
|
||||
this._crashedBrowsers.delete(aMessage.objects.browser.permanentKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we got here, that means we're dealing with a frame message
|
||||
// manager message, so the target will be a <xul:browser>.
|
||||
var browser = aMessage.target;
|
||||
var win = browser.ownerDocument.defaultView;
|
||||
let tab = this._getTabForBrowser(browser);
|
||||
|
@ -567,6 +602,11 @@ let SessionStoreInternal = {
|
|||
TabState.setSyncHandler(browser, aMessage.objects.handler);
|
||||
break;
|
||||
case "SessionStore:update":
|
||||
if (this._crashedBrowsers.has(browser.permanentKey)) {
|
||||
// Ignore messages from <browser> elements that have crashed
|
||||
// and not yet been revived.
|
||||
return;
|
||||
}
|
||||
this.recordTelemetry(aMessage.data.telemetry);
|
||||
TabState.update(browser, aMessage.data);
|
||||
this.saveStateDelayed(win);
|
||||
|
@ -651,7 +691,7 @@ let SessionStoreInternal = {
|
|||
}
|
||||
break;
|
||||
default:
|
||||
debug("received unknown message '" + aMessage.name + "'");
|
||||
debug(`received unknown message '${aMessage.name}'`);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
@ -675,7 +715,6 @@ let SessionStoreInternal = {
|
|||
*/
|
||||
handleEvent: function ssi_handleEvent(aEvent) {
|
||||
var win = aEvent.currentTarget.ownerDocument.defaultView;
|
||||
let browser;
|
||||
switch (aEvent.type) {
|
||||
case "TabOpen":
|
||||
this.onTabAdd(win, aEvent.originalTarget);
|
||||
|
@ -700,6 +739,9 @@ let SessionStoreInternal = {
|
|||
case "SwapDocShells":
|
||||
this.saveStateDelayed(win);
|
||||
break;
|
||||
case "oop-browser-crashed":
|
||||
this._crashedBrowsers.add(aEvent.originalTarget.permanentKey);
|
||||
break;
|
||||
}
|
||||
this._clearRestoringWindows();
|
||||
},
|
||||
|
@ -738,7 +780,7 @@ let SessionStoreInternal = {
|
|||
aWindow.__SSi = this._generateWindowID();
|
||||
|
||||
let mm = aWindow.getGroupMessageManager("browsers");
|
||||
MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
|
||||
FMM_MESSAGES.forEach(msg => mm.addMessageListener(msg, this));
|
||||
|
||||
// Load the frame script after registering listeners.
|
||||
mm.loadFrameScript("chrome://browser/content/content-sessionStore.js", true);
|
||||
|
@ -1067,7 +1109,7 @@ let SessionStoreInternal = {
|
|||
DyingWindowCache.set(aWindow, winData);
|
||||
|
||||
let mm = aWindow.getGroupMessageManager("browsers");
|
||||
MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
|
||||
FMM_MESSAGES.forEach(msg => mm.removeMessageListener(msg, this));
|
||||
|
||||
delete aWindow.__SSi;
|
||||
},
|
||||
|
@ -1260,6 +1302,7 @@ let SessionStoreInternal = {
|
|||
onTabAdd: function ssi_onTabAdd(aWindow, aTab, aNoNotification) {
|
||||
let browser = aTab.linkedBrowser;
|
||||
browser.addEventListener("SwapDocShells", this);
|
||||
browser.addEventListener("oop-browser-crashed", this);
|
||||
if (!aNoNotification) {
|
||||
this.saveStateDelayed(aWindow);
|
||||
}
|
||||
|
@ -1278,6 +1321,7 @@ let SessionStoreInternal = {
|
|||
let browser = aTab.linkedBrowser;
|
||||
delete browser.__SS_data;
|
||||
browser.removeEventListener("SwapDocShells", this);
|
||||
browser.removeEventListener("oop-browser-crashed", this);
|
||||
|
||||
// If this tab was in the middle of restoring or still needs to be restored,
|
||||
// we need to reset that state. If the tab was restoring, we will attempt to
|
||||
|
@ -1908,6 +1952,35 @@ let SessionStoreInternal = {
|
|||
LastSession.clear();
|
||||
},
|
||||
|
||||
/**
|
||||
* Revive a crashed tab and restore its state from before it crashed.
|
||||
*
|
||||
* @param aTab
|
||||
* A <xul:tab> linked to a crashed browser. This is a no-op if the
|
||||
* browser hasn't actually crashed, or is not associated with a tab.
|
||||
* This function will also throw if the browser happens to be remote.
|
||||
*/
|
||||
reviveCrashedTab(aTab) {
|
||||
if (!aTab) {
|
||||
throw new Error("SessionStore.reviveCrashedTab expected a tab, but got null.");
|
||||
}
|
||||
|
||||
let browser = aTab.linkedBrowser;
|
||||
if (!this._crashedBrowsers.has(browser.permanentKey)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sanity check - the browser to be revived should not be remote
|
||||
// at this point.
|
||||
if (browser.isRemoteBrowser) {
|
||||
throw new Error("SessionStore.reviveCrashedTab: " +
|
||||
"Somehow a crashed browser is still remote.")
|
||||
}
|
||||
|
||||
let data = TabState.collect(aTab);
|
||||
this.restoreTab(aTab, data);
|
||||
},
|
||||
|
||||
/**
|
||||
* See if aWindow is usable for use when restoring a previous session via
|
||||
* restoreLastSession. If usable, prepare it for use.
|
||||
|
|
|
@ -29,6 +29,10 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "SessionStorage",
|
||||
"resource:///modules/sessionstore/SessionStorage.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsISyncMessageSender");
|
||||
|
||||
Cu.import("resource:///modules/sessionstore/FrameTree.jsm", this);
|
||||
let gFrameTree = new FrameTree(this);
|
||||
|
||||
|
@ -711,7 +715,42 @@ ScrollPositionListener.init();
|
|||
DocShellCapabilitiesListener.init();
|
||||
PrivacyListener.init();
|
||||
|
||||
function handleRevivedTab() {
|
||||
if (!content) {
|
||||
removeEventListener("pagehide", handleRevivedTab);
|
||||
return;
|
||||
}
|
||||
|
||||
if (content.document.documentURI.startsWith("about:tabcrashed")) {
|
||||
if (Services.appinfo.processType != Services.appinfo.PROCESS_TYPE_DEFAULT) {
|
||||
// Sanity check - we'd better be loading this in a non-remote browser.
|
||||
throw new Error("We seem to be navigating away from about:tabcrashed in " +
|
||||
"a non-remote browser. This should really never happen.");
|
||||
}
|
||||
|
||||
removeEventListener("pagehide", handleRevivedTab);
|
||||
|
||||
// We can't send a message using the frame message manager because by
|
||||
// the time we reach the unload event handler, it's "too late", and messages
|
||||
// won't be sent or received. The child-process message manager works though,
|
||||
// despite the fact that we're really running in the parent process.
|
||||
let browser = docShell.chromeEventHandler;
|
||||
cpmm.sendSyncMessage("SessionStore:RemoteTabRevived", null, {browser: browser});
|
||||
}
|
||||
}
|
||||
|
||||
// If we're browsing from the tab crashed UI to a blacklisted URI that keeps
|
||||
// this browser non-remote, we'll handle that in a pagehide event.
|
||||
addEventListener("pagehide", handleRevivedTab);
|
||||
|
||||
addEventListener("unload", () => {
|
||||
// If we're browsing from the tab crashed UI to a URI that causes the tab
|
||||
// to go remote again, we catch this in the unload event handler, because
|
||||
// swapping out the non-remote browser for a remote one in
|
||||
// tabbrowser.xml's updateBrowserRemoteness doesn't cause the pagehide
|
||||
// event to be fired.
|
||||
handleRevivedTab();
|
||||
|
||||
// Remove all registered nsIObservers.
|
||||
PageStyleListener.uninit();
|
||||
SessionStorageListener.uninit();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
[DEFAULT]
|
||||
skip-if = e10s # Most of these tests fail due to Bug ?????? - SessionStore is disabled in e10s
|
||||
support-files =
|
||||
dummy_page.html
|
||||
head.js
|
||||
|
@ -23,6 +22,7 @@ skip-if = buildapp == 'mulet'
|
|||
[browser_tabview_bug587990.js]
|
||||
[browser_tabview_bug588265.js]
|
||||
[browser_tabview_bug589324.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug590606.js]
|
||||
[browser_tabview_bug591706.js]
|
||||
[browser_tabview_bug593283.js]
|
||||
|
@ -36,6 +36,7 @@ skip-if = buildapp == 'mulet'
|
|||
[browser_tabview_bug595930.js]
|
||||
[browser_tabview_bug595943.js]
|
||||
[browser_tabview_bug595965.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug596781.js]
|
||||
[browser_tabview_bug597360.js]
|
||||
[browser_tabview_bug597399.js]
|
||||
|
@ -48,6 +49,7 @@ skip-if = true # Bug 711907
|
|||
skip-if = os == 'linux' || e10s # Disabled on Linux: Bug 939620, much fail, so amaze; Disabled for e10s: Bug ??????
|
||||
[browser_tabview_bug600645.js]
|
||||
[browser_tabview_bug600812.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug602432.js]
|
||||
skip-if = true # Bug 704417
|
||||
[browser_tabview_bug604098.js]
|
||||
|
@ -56,6 +58,7 @@ skip-if = true # Bug 704417
|
|||
[browser_tabview_bug607108.js]
|
||||
skip-if = os == 'linux' # Bug 947521
|
||||
[browser_tabview_bug608037.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug608153.js]
|
||||
[browser_tabview_bug608158.js]
|
||||
[browser_tabview_bug608184.js]
|
||||
|
@ -67,6 +70,7 @@ skip-if = true # Bug 736036
|
|||
[browser_tabview_bug613541.js]
|
||||
skip-if = os == "win" # Bug 951477
|
||||
[browser_tabview_bug616729.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug616967.js]
|
||||
[browser_tabview_bug618816.js]
|
||||
[browser_tabview_bug618828.js]
|
||||
|
@ -74,12 +78,14 @@ skip-if = buildapp == 'mulet'
|
|||
[browser_tabview_bug619937.js]
|
||||
[browser_tabview_bug622835.js]
|
||||
[browser_tabview_bug623768.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug624265_perwindowpb.js]
|
||||
skip-if = true # Bug 921984, hopefully fixed by bug 930202
|
||||
[browser_tabview_bug624692.js]
|
||||
[browser_tabview_bug624727_perwindowpb.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
[browser_tabview_bug624847.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug624931.js]
|
||||
[browser_tabview_bug624953.js]
|
||||
[browser_tabview_bug625195.js]
|
||||
|
@ -87,7 +93,9 @@ skip-if = buildapp == 'mulet'
|
|||
[browser_tabview_bug625424.js]
|
||||
[browser_tabview_bug625955.js]
|
||||
[browser_tabview_bug626368.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug626455.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug626525.js]
|
||||
[browser_tabview_bug626791.js]
|
||||
skip-if = buildapp == 'mulet'
|
||||
|
@ -133,6 +141,7 @@ skip-if = true # Bug 754222
|
|||
[browser_tabview_bug656778.js]
|
||||
skip-if = os == "mac" # Bug 946918
|
||||
[browser_tabview_bug656913.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_bug659594.js]
|
||||
skip-if = os == "mac" || e10s # mac: Bug 939617; e10s - Bug ?????? - "leaked until shutdown [nsGlobalWindow #82 about:blank]"
|
||||
[browser_tabview_bug662266.js]
|
||||
|
@ -173,6 +182,7 @@ skip-if = buildapp == 'mulet'
|
|||
skip-if = os == "mac" || os == "win" # Bug 945687
|
||||
[browser_tabview_launch.js]
|
||||
[browser_tabview_multiwindow_search.js]
|
||||
skip-if = e10s # Bug 1086190
|
||||
[browser_tabview_pending_tabs.js]
|
||||
[browser_tabview_privatebrowsing_perwindowpb.js]
|
||||
skip-if = os == 'linux' || e10s # linux: Bug 944300; e10s: bug ?????? - "leaked until shutdown [nsGlobalWindow #82 about:blank]"
|
||||
|
|
|
@ -63,9 +63,8 @@ function endGame() {
|
|||
}
|
||||
|
||||
function newWindowWithTabView(callback, completeCallback) {
|
||||
let charsetArg = "charset=" + window.content.document.characterSet;
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no,height=800,width=800",
|
||||
"about:blank", charsetArg, null, null, true);
|
||||
"about:blank", null, null, null, true);
|
||||
let onLoad = function() {
|
||||
win.removeEventListener("load", onLoad, false);
|
||||
let onShown = function() {
|
||||
|
|
|
@ -10,9 +10,8 @@ function animateZoom() prefsBranch.getBoolPref("animate_zoom");
|
|||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
let charsetArg = "charset=" + window.content.document.characterSet;
|
||||
let win = window.openDialog(getBrowserURL(), "_blank", "chrome,all,dialog=no",
|
||||
"about:blank", charsetArg, null, null, true);
|
||||
"about:blank", null, null, null, true);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
prefsBranch.setBoolPref("animate_zoom", true);
|
||||
|
|
|
@ -103,7 +103,7 @@ loop-call-button3.label = Hello
|
|||
loop-call-button3.tooltiptext = Start a conversation
|
||||
|
||||
social-share-button.label = Share This Page
|
||||
social-share-button.tooltiptext = Share This Page
|
||||
social-share-button.tooltiptext = Share this page
|
||||
|
||||
panic-button.label = Forget
|
||||
panic-button.tooltiptext = Forget about some browsing history
|
||||
|
|
|
@ -87,18 +87,6 @@ this.TabCrashReporter = {
|
|||
}
|
||||
},
|
||||
|
||||
reloadCrashedTab: function (browser) {
|
||||
if (browser.isRemoteBrowser)
|
||||
return;
|
||||
|
||||
let doc = browser.contentDocument;
|
||||
if (!doc.documentURI.startsWith("about:tabcrashed"))
|
||||
return;
|
||||
|
||||
let url = browser.currentURI.spec;
|
||||
browser.loadURIWithFlags(url, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
|
||||
},
|
||||
|
||||
onAboutTabCrashedLoad: function (aBrowser) {
|
||||
if (!this.childMap)
|
||||
return;
|
||||
|
|
|
@ -1937,6 +1937,10 @@ toolbarbutton[sdk-button="true"][cui-areatype="toolbar"] > .toolbarbutton-icon {
|
|||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
#urlbar[readonly] {
|
||||
background-color: -moz-field;
|
||||
}
|
||||
|
||||
@media (-moz-mac-lion-theme) {
|
||||
#urlbar,
|
||||
.searchbar-textbox {
|
||||
|
|
|
@ -1536,7 +1536,6 @@ if test "$GNU_CXX"; then
|
|||
# -Wreturn-type - catches missing returns, zero false positives
|
||||
# -Wsequence-point - catches undefined order behavior like `a = a++`
|
||||
# -Wsign-compare - catches comparison of signed and unsigned types
|
||||
# -Wswitch - catches switches without all enum cases or default case
|
||||
# -Wtrigraphs - catches unlikely use of trigraphs
|
||||
# -Wtype-limits - catches overflow bugs, few false positives
|
||||
# -Wunused-label - catches unused goto labels
|
||||
|
@ -1555,7 +1554,6 @@ if test "$GNU_CXX"; then
|
|||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=pointer-arith"
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=sequence-point"
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=switch"
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label"
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs"
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=type-limits"
|
||||
|
|
|
@ -143,6 +143,11 @@ public:
|
|||
return mConsumer.get();
|
||||
}
|
||||
|
||||
SocketBase* GetSocketBase()
|
||||
{
|
||||
return GetConsumer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
|
||||
* directly from main thread. All non-main-thread accesses should happen with
|
||||
|
@ -661,7 +666,8 @@ BluetoothSocket::SendSocketData(UnixSocketRawData* aData)
|
|||
MOZ_ASSERT(!mImpl->IsShutdownOnMainThread());
|
||||
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
FROM_HERE, new SocketIOSendTask<DroidSocketImpl>(mImpl, aData));
|
||||
FROM_HERE,
|
||||
new SocketIOSendTask<DroidSocketImpl, UnixSocketRawData>(mImpl, aData));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -143,6 +143,11 @@ public:
|
|||
return mConsumer.get();
|
||||
}
|
||||
|
||||
SocketBase* GetSocketBase()
|
||||
{
|
||||
return GetConsumer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Consumer pointer. Non-thread safe RefPtr, so should only be manipulated
|
||||
* directly from main thread. All non-main-thread accesses should happen with
|
||||
|
@ -661,7 +666,7 @@ BluetoothSocket::SendSocketData(UnixSocketRawData* aData)
|
|||
MOZ_ASSERT(!mImpl->IsShutdownOnMainThread());
|
||||
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
FROM_HERE, new SocketIOSendTask<DroidSocketImpl>(mImpl, aData));
|
||||
FROM_HERE, new SocketIOSendTask<DroidSocketImpl, UnixSocketRawData>(mImpl, aData));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ let FormAssistant = {
|
|||
'range'
|
||||
]),
|
||||
|
||||
isKeyboardOpened: false,
|
||||
isHandlingFocus: false,
|
||||
selectionStart: -1,
|
||||
selectionEnd: -1,
|
||||
textBeforeCursor: "",
|
||||
|
@ -304,7 +304,7 @@ let FormAssistant = {
|
|||
});
|
||||
});
|
||||
if (del && element === self.focusedElement) {
|
||||
self.hideKeyboard();
|
||||
self.unhandleFocus();
|
||||
self.selectionStart = -1;
|
||||
self.selectionEnd = -1;
|
||||
}
|
||||
|
@ -351,7 +351,7 @@ let FormAssistant = {
|
|||
if (this._editing) {
|
||||
return;
|
||||
}
|
||||
this.sendKeyboardState(this.focusedElement);
|
||||
this.sendInputState(this.focusedElement);
|
||||
},
|
||||
|
||||
handleEvent: function fa_handleEvent(evt) {
|
||||
|
@ -379,13 +379,13 @@ let FormAssistant = {
|
|||
}
|
||||
|
||||
if (isContentEditable(target)) {
|
||||
this.showKeyboard(this.getTopLevelEditable(target));
|
||||
this.handleFocus(this.getTopLevelEditable(target));
|
||||
this.updateSelection();
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.isFocusableElement(target)) {
|
||||
this.showKeyboard(target);
|
||||
this.handleFocus(target);
|
||||
this.updateSelection();
|
||||
}
|
||||
break;
|
||||
|
@ -406,14 +406,14 @@ let FormAssistant = {
|
|||
|
||||
case "blur":
|
||||
if (this.focusedElement) {
|
||||
this.hideKeyboard();
|
||||
this.unhandleFocus();
|
||||
this.selectionStart = -1;
|
||||
this.selectionEnd = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case "resize":
|
||||
if (!this.isKeyboardOpened)
|
||||
if (!this.isHandlingFocus)
|
||||
return;
|
||||
|
||||
if (this.scrollIntoViewTimeout) {
|
||||
|
@ -672,7 +672,7 @@ let FormAssistant = {
|
|||
|
||||
},
|
||||
|
||||
showKeyboard: function fa_showKeyboard(target) {
|
||||
handleFocus: function fa_handleFocus(target) {
|
||||
if (this.focusedElement === target)
|
||||
return;
|
||||
|
||||
|
@ -682,18 +682,17 @@ let FormAssistant = {
|
|||
this.setFocusedElement(target);
|
||||
|
||||
let count = this._focusCounter;
|
||||
this.waitForNextTick(function fa_showKeyboardSync() {
|
||||
this.waitForNextTick(function fa_handleFocusSync() {
|
||||
if (count !== this._focusCounter) {
|
||||
return;
|
||||
}
|
||||
|
||||
let kbOpened = this.sendKeyboardState(target);
|
||||
if (this.isTextInputElement(target))
|
||||
this.isKeyboardOpened = kbOpened;
|
||||
let isHandlingFocus = this.sendInputState(target);
|
||||
this.isHandlingFocus = isHandlingFocus;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
hideKeyboard: function fa_hideKeyboard() {
|
||||
unhandleFocus: function fa_unhandleFocus() {
|
||||
this.setFocusedElement(null);
|
||||
|
||||
let count = this._focusCounter;
|
||||
|
@ -701,13 +700,13 @@ let FormAssistant = {
|
|||
// Wait for the next tick before unset the focused element and etc.
|
||||
// If the user move from one input from another,
|
||||
// the remote process should get one Forms:Input message instead of two.
|
||||
this.waitForNextTick(function fa_hideKeyboardSync() {
|
||||
this.waitForNextTick(function fa_unhandleFocusSync() {
|
||||
if (count !== this._focusCounter ||
|
||||
!this.isKeyboardOpened) {
|
||||
!this.isHandlingFocus) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isKeyboardOpened = false;
|
||||
this.isHandlingFocus = false;
|
||||
sendAsyncMessage("Forms:Input", { "type": "blur" });
|
||||
}.bind(this));
|
||||
},
|
||||
|
@ -725,12 +724,6 @@ let FormAssistant = {
|
|||
!this.ignoredInputTypes.has(element.type));
|
||||
},
|
||||
|
||||
isTextInputElement: function fa_isTextInputElement(element) {
|
||||
return element instanceof HTMLInputElement ||
|
||||
element instanceof HTMLTextAreaElement ||
|
||||
isContentEditable(element);
|
||||
},
|
||||
|
||||
getTopLevelEditable: function fa_getTopLevelEditable(element) {
|
||||
function retrieveTopLevelEditable(element) {
|
||||
while (element && !isContentEditable(element))
|
||||
|
@ -742,7 +735,7 @@ let FormAssistant = {
|
|||
return retrieveTopLevelEditable(element) || element;
|
||||
},
|
||||
|
||||
sendKeyboardState: function(element) {
|
||||
sendInputState: function(element) {
|
||||
// FIXME/bug 729623: work around apparent bug in the IME manager
|
||||
// in gecko.
|
||||
let readonly = element.getAttribute("readonly");
|
||||
|
|
|
@ -24,3 +24,4 @@ support-files =
|
|||
[test_delete_focused_element.html]
|
||||
[test_sendkey_cancel.html]
|
||||
[test_two_inputs.html]
|
||||
[test_two_selects.html]
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1079728
|
||||
-->
|
||||
<head>
|
||||
<title>Test switching between two inputs</title>
|
||||
<script type="application/javascript;version=1.7" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript;version=1.7" src="inputmethod_common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1079728">Mozilla Bug 1079728</a>
|
||||
<p id="display"></p>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.7">
|
||||
|
||||
inputmethod_setup(function() {
|
||||
runTest();
|
||||
});
|
||||
|
||||
let appFrameScript = function appFrameScript() {
|
||||
let select1 = content.document.body.firstElementChild;
|
||||
let select2 = content.document.body.children[1];
|
||||
|
||||
let i = 1;
|
||||
|
||||
select1.focus();
|
||||
|
||||
addMessageListener('test:next', function() {
|
||||
i++;
|
||||
switch (i) {
|
||||
case 2:
|
||||
select2.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 3:
|
||||
select2.blur();
|
||||
select2.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 4:
|
||||
select2.blur();
|
||||
|
||||
break;
|
||||
|
||||
case 5:
|
||||
select2.focus();
|
||||
select2.blur();
|
||||
|
||||
select1.focus();
|
||||
|
||||
break;
|
||||
|
||||
case 6:
|
||||
select1.blur();
|
||||
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function runTest() {
|
||||
let im = navigator.mozInputMethod;
|
||||
|
||||
let i = 0;
|
||||
im.oninputcontextchange = function(evt) {
|
||||
var inputcontext = navigator.mozInputMethod.inputcontext;
|
||||
|
||||
i++;
|
||||
switch (i) {
|
||||
// focus on the first input receives the first input context.
|
||||
case 1:
|
||||
ok(!!inputcontext, 'Receving the first input context');
|
||||
is(inputcontext.textAfterCursor, 'First');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// focus on the second input (implicitly blur the first input)
|
||||
// results the second input context.
|
||||
case 2:
|
||||
ok(!!inputcontext, 'Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// blur and re-focus on the second input results updated
|
||||
// input context for the second input.
|
||||
case 3:
|
||||
ok(!!inputcontext, 'Receving the second input context');
|
||||
is(inputcontext.textAfterCursor, 'Second');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// blur on the second input results null input context
|
||||
case 4:
|
||||
is(inputcontext, null, 'Receving null inputcontext');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// focus and blur on the second input sends no message;
|
||||
// focus on the first input receives the first input context.
|
||||
case 5:
|
||||
ok(!!inputcontext, 'Receving the first input context');
|
||||
is(inputcontext.textAfterCursor, 'First');
|
||||
|
||||
mm.sendAsyncMessage('test:next');
|
||||
break;
|
||||
|
||||
// blur on the first input results null input context
|
||||
case 6:
|
||||
is(inputcontext, null, 'Receving null inputcontext');
|
||||
|
||||
inputmethod_cleanup();
|
||||
break;
|
||||
|
||||
default:
|
||||
ok(false, 'Receving extra inputcontextchange calls');
|
||||
inputmethod_cleanup();
|
||||
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// Set current page as an input method.
|
||||
SpecialPowers.wrap(im).setActive(true);
|
||||
|
||||
let iframe = document.createElement('iframe');
|
||||
iframe.src = 'data:text/html,<html><body><select><option>First</option></select><select><option>Second</option></select></html>';
|
||||
iframe.setAttribute('mozbrowser', true);
|
||||
document.body.appendChild(iframe);
|
||||
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
|
||||
iframe.addEventListener('mozbrowserloadend', function() {
|
||||
mm.loadFrameScript('data:,(' + encodeURIComponent(appFrameScript.toString()) + ')();', false);
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
namespace mozilla {
|
||||
|
||||
#define NFCD_MAJOR_VERSION 1
|
||||
#define NFCD_MINOR_VERSION 12
|
||||
#define NFCD_MINOR_VERSION 13
|
||||
|
||||
enum NfcRequest {
|
||||
ConfigReq = 0,
|
||||
|
|
|
@ -25,36 +25,24 @@ this.DEBUG_NFC = false || DEBUG_ALL;
|
|||
// nfcd error codes
|
||||
this.NFC_SUCCESS = 0;
|
||||
this.NFC_ERROR_IO = -1;
|
||||
this.NFC_ERROR_CANCELLED = -2;
|
||||
this.NFC_ERROR_TIMEOUT = -3;
|
||||
this.NFC_ERROR_BUSY = -4;
|
||||
this.NFC_ERROR_CONNECT = -5;
|
||||
this.NFC_ERROR_DISCONNECT = -6;
|
||||
this.NFC_ERROR_READ = -7;
|
||||
this.NFC_ERROR_WRITE = -8;
|
||||
this.NFC_ERROR_INVALID_PARAM = -9;
|
||||
this.NFC_ERROR_INSUFFICIENT_RESOURCES = -10;
|
||||
this.NFC_ERROR_SOCKET_CREATION = -11;
|
||||
this.NFC_ERROR_SOCKET_NOT_CONNECTED = -12;
|
||||
this.NFC_ERROR_BUFFER_TOO_SMALL = -13;
|
||||
this.NFC_ERROR_SAP_USED = -14;
|
||||
this.NFC_ERROR_SERVICE_NAME_USED = -15;
|
||||
this.NFC_ERROR_SOCKET_OPTIONS = -16;
|
||||
this.NFC_ERROR_FAIL_ENABLE_DISCOVERY = -17;
|
||||
this.NFC_ERROR_FAIL_DISABLE_DISCOVERY = -18;
|
||||
this.NFC_ERROR_NOT_INITIALIZED = -19;
|
||||
this.NFC_ERROR_INITIALIZE_FAIL = -20;
|
||||
this.NFC_ERROR_DEINITIALIZE_FAIL = -21;
|
||||
this.NFC_ERROR_SE_CONNECTED = -22;
|
||||
this.NFC_ERROR_NO_SE_CONNECTED = -23;
|
||||
this.NFC_ERROR_NOT_SUPPORTED = -24;
|
||||
this.NFC_ERROR_BAD_SESSION_ID = -25;
|
||||
this.NFC_ERROR_LOST_TECH = -26;
|
||||
this.NFC_ERROR_BAD_TECH_TYPE = -27;
|
||||
this.NFC_ERROR_SELECT_SE_FAIL = -28;
|
||||
this.NFC_ERROR_DESELECT_SE_FAIL = -29;
|
||||
this.NFC_ERROR_FAIL_ENABLE_LOW_POWER_MODE = -30;
|
||||
this.NFC_ERROR_FAIL_DISABLE_LOW_POWER_MODE = -31;
|
||||
this.NFC_ERROR_TIMEOUT = -2;
|
||||
this.NFC_ERROR_BUSY = -3;
|
||||
this.NFC_ERROR_CONNECT = -4;
|
||||
this.NFC_ERROR_DISCONNECT = -5;
|
||||
this.NFC_ERROR_READ = -6;
|
||||
this.NFC_ERROR_WRITE = -7;
|
||||
this.NFC_ERROR_INVALID_PARAM = -8;
|
||||
this.NFC_ERROR_INSUFFICIENT_RESOURCES = -9;
|
||||
this.NFC_ERROR_SOCKET_CREATION = -10;
|
||||
this.NFC_ERROR_FAIL_ENABLE_DISCOVERY = -11;
|
||||
this.NFC_ERROR_FAIL_DISABLE_DISCOVERY = -12;
|
||||
this.NFC_ERROR_NOT_INITIALIZED = -13;
|
||||
this.NFC_ERROR_INITIALIZE_FAIL = -14;
|
||||
this.NFC_ERROR_DEINITIALIZE_FAIL = -15;
|
||||
this.NFC_ERROR_NOT_SUPPORTED = -16;
|
||||
this.NFC_ERROR_BAD_SESSION_ID = -17,
|
||||
this.NFC_ERROR_FAIL_ENABLE_LOW_POWER_MODE = -18;
|
||||
this.NFC_ERROR_FAIL_DISABLE_LOW_POWER_MODE = -19;
|
||||
|
||||
// Gecko specific error codes
|
||||
this.NFC_GECKO_ERROR_GENERIC_FAILURE = 1;
|
||||
|
@ -64,7 +52,6 @@ this.NFC_GECKO_ERROR_SEND_FILE_FAILED = 4;
|
|||
|
||||
this.NFC_ERROR_MSG = {};
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_IO] = "NfcIoError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_CANCELLED] = "NfcCancelledError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_TIMEOUT] = "NfcTimeoutError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_BUSY] = "NfcBusyError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_CONNECT] = "NfcConnectError";
|
||||
|
@ -74,24 +61,13 @@ this.NFC_ERROR_MSG[this.NFC_ERROR_WRITE] = "NfcWriteError";
|
|||
this.NFC_ERROR_MSG[this.NFC_ERROR_INVALID_PARAM] = "NfcInvalidParamError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_INSUFFICIENT_RESOURCES] = "NfcInsufficentResourcesError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_SOCKET_CREATION] = "NfcSocketCreationError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_SOCKET_NOT_CONNECTED] = "NfcSocketNotConntectedError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_BUFFER_TOO_SMALL] = "NfcBufferTooSmallError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_SAP_USED] = "NfcSapUsedError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_SERVICE_NAME_USED] = "NfcServiceNameUsedError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_SOCKET_OPTIONS] = "NfcSocketOptionsError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_FAIL_ENABLE_DISCOVERY] = "NfcFailEnableDiscoveryError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_FAIL_DISABLE_DISCOVERY] = "NfcFailDisableDiscoveryError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_NOT_INITIALIZED] = "NfcNotInitializedError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_INITIALIZE_FAIL] = "NfcInitializeFailError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_DEINITIALIZE_FAIL] = "NfcDeinitializeFailError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_SE_CONNECTED] = "NfcSeConnectedError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_NO_SE_CONNECTED] = "NfcNoSeConnectedError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_NOT_SUPPORTED] = "NfcNotSupportedError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_BAD_SESSION_ID] = "NfcBadSessionIdError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_LOST_TECH] = "NfcLostTechError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_BAD_TECH_TYPE] = "NfcBadTechTypeError";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_SELECT_SE_FAIL] = "SelectSecureElementFailed";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_DESELECT_SE_FAIL] = "DeselectSecureElementFailed";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_FAIL_ENABLE_LOW_POWER_MODE] = "EnableLowPowerModeFail";
|
||||
this.NFC_ERROR_MSG[this.NFC_ERROR_FAIL_DISABLE_LOW_POWER_MODE] = "DisableLowPowerModeFail";
|
||||
this.NFC_ERROR_MSG[this.NFC_GECKO_ERROR_GENERIC_FAILURE] = "NfcGenericFailureError";
|
||||
|
|
|
@ -704,7 +704,9 @@ let SettingsRequestManager = {
|
|||
removeObserver: function(aMsgMgr) {
|
||||
if (DEBUG) {
|
||||
let principal = this.mmPrincipals.get(aMsgMgr);
|
||||
debug("Remove observer for " + principal.origin);
|
||||
if (principal) {
|
||||
debug("Remove observer for " + principal.origin);
|
||||
}
|
||||
}
|
||||
let index = this.children.indexOf(aMsgMgr);
|
||||
if (index != -1) {
|
||||
|
@ -745,26 +747,31 @@ let SettingsRequestManager = {
|
|||
|
||||
removeMessageManager: function(aMsgMgr, aPrincipal) {
|
||||
if (DEBUG) debug("Removing message manager");
|
||||
let msgMgrPrincipal = this.mmPrincipals.get(aMsgMgr);
|
||||
this.removeObserver(aMsgMgr);
|
||||
let closedLockIDs = [];
|
||||
|
||||
let lockIDs = Object.keys(this.lockInfo);
|
||||
for (let i in lockIDs) {
|
||||
let lock = this.lockInfo[lockIDs[i]];
|
||||
if (lock._mm == aMsgMgr) {
|
||||
let lockId = lockIDs[i];
|
||||
let lock = this.lockInfo[lockId];
|
||||
if (lock._mm === aMsgMgr && msgMgrPrincipal === aPrincipal) {
|
||||
let is_finalizing = false;
|
||||
for (let task_index in lock.tasks) {
|
||||
if (lock.tasks[task_index].operation === "finalize") {
|
||||
let task_index;
|
||||
// Go in reverse order because finalize should be the last one
|
||||
for (task_index = lock.tasks.length; task_index >= 0; task_index--) {
|
||||
if (lock.tasks[task_index]
|
||||
&& lock.tasks[task_index].operation === "finalize") {
|
||||
is_finalizing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!is_finalizing) {
|
||||
this.queueTask("finalize", {lockID: lockIDs[i]}, aPrincipal).then(
|
||||
this.queueTask("finalize", {lockID: lockId}, aPrincipal).then(
|
||||
function() {
|
||||
if (DEBUG) debug("Lock " + lockIDs[i] + " with dead message manager finalized");
|
||||
if (DEBUG) debug("Lock " + lockId + " with dead message manager finalized");
|
||||
},
|
||||
function(error) {
|
||||
if (DEBUG) debug("Lock " + lockIDs[i] + " with dead message manager NOT FINALIZED due to error: " + error);
|
||||
if (DEBUG) debug("Lock " + lockId + " with dead message manager NOT FINALIZED due to error: " + error);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,3 +23,5 @@ EXTRA_JS_MODULES += [
|
|||
]
|
||||
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
"use strict";
|
||||
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsIMessageSender");
|
||||
|
||||
let principal = Services.scriptSecurityManager.getSystemPrincipal();
|
||||
let lockID = "{435d2192-4f21-48d4-90b7-285f147a56be}";
|
||||
|
||||
// Helper to start the Settings Request Manager
|
||||
function startSettingsRequestManager() {
|
||||
Cu.import("resource://gre/modules/SettingsRequestManager.jsm");
|
||||
}
|
||||
|
||||
// Helper function to add a listener, send message and treat the reply
|
||||
function addAndSend(msg, reply, callback, payload, runNext = true) {
|
||||
let handler = {
|
||||
receiveMessage: function(message) {
|
||||
if (message.name === reply) {
|
||||
cpmm.removeMessageListener(reply, handler);
|
||||
callback(message);
|
||||
if (runNext) {
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
cpmm.addMessageListener(reply, handler);
|
||||
cpmm.sendAsyncMessage(msg, payload, undefined, principal);
|
||||
}
|
||||
|
||||
// We need to trigger a Settings:Run message to make the queue progress
|
||||
function send_settingsRun() {
|
||||
let msg = {lockID: lockID, isServiceLock: true};
|
||||
cpmm.sendAsyncMessage("Settings:Run", msg, undefined, principal);
|
||||
}
|
||||
|
||||
function kill_child() {
|
||||
let msg = {lockID: lockID, isServiceLock: true};
|
||||
cpmm.sendAsyncMessage("child-process-shutdown", msg, undefined, principal);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_get_profile();
|
||||
startSettingsRequestManager();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_createLock() {
|
||||
let msg = {lockID: lockID, isServiceLock: true};
|
||||
cpmm.sendAsyncMessage("Settings:CreateLock", msg, undefined, principal);
|
||||
cpmm.sendAsyncMessage(
|
||||
"Settings:RegisterForMessages", undefined, undefined, principal);
|
||||
ok(true);
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_get_empty() {
|
||||
let requestID = 10;
|
||||
let msgReply = "Settings:Get:OK";
|
||||
let msgHandler = function(message) {
|
||||
equal(requestID, message.data.requestID);
|
||||
equal(lockID, message.data.lockID);
|
||||
ok(Object.keys(message.data.settings).length >= 0);
|
||||
};
|
||||
|
||||
addAndSend("Settings:Get", msgReply, msgHandler, {
|
||||
requestID: requestID,
|
||||
lockID: lockID,
|
||||
name: "language.current"
|
||||
});
|
||||
|
||||
send_settingsRun();
|
||||
});
|
||||
|
||||
add_test(function test_set_get_nonempty() {
|
||||
let settings = { "language.current": "fr-FR:XPC" };
|
||||
let requestIDSet = 20;
|
||||
let msgReplySet = "Settings:Set:OK";
|
||||
let msgHandlerSet = function(message) {
|
||||
equal(requestIDSet, message.data.requestID);
|
||||
equal(lockID, message.data.lockID);
|
||||
};
|
||||
|
||||
addAndSend("Settings:Set", msgReplySet, msgHandlerSet, {
|
||||
requestID: requestIDSet,
|
||||
lockID: lockID,
|
||||
settings: settings
|
||||
}, false);
|
||||
|
||||
let requestIDGet = 25;
|
||||
let msgReplyGet = "Settings:Get:OK";
|
||||
let msgHandlerGet = function(message) {
|
||||
equal(requestIDGet, message.data.requestID);
|
||||
equal(lockID, message.data.lockID);
|
||||
for(let p in settings) {
|
||||
equal(settings[p], message.data.settings[p]);
|
||||
}
|
||||
};
|
||||
|
||||
addAndSend("Settings:Get", msgReplyGet, msgHandlerGet, {
|
||||
requestID: requestIDGet,
|
||||
lockID: lockID,
|
||||
name: Object.keys(settings)[0]
|
||||
});
|
||||
|
||||
// Set and Get have been push into the queue, let's run
|
||||
send_settingsRun();
|
||||
});
|
||||
|
||||
// This test exposes bug 1076597 behavior
|
||||
add_test(function test_wait_for_finalize() {
|
||||
let settings = { "language.current": "en-US:XPC" };
|
||||
let requestIDSet = 30;
|
||||
let msgReplySet = "Settings:Set:OK";
|
||||
let msgHandlerSet = function(message) {
|
||||
equal(requestIDSet, message.data.requestID);
|
||||
equal(lockID, message.data.lockID);
|
||||
};
|
||||
|
||||
addAndSend("Settings:Set", msgReplySet, msgHandlerSet, {
|
||||
requestID: requestIDSet,
|
||||
lockID: lockID,
|
||||
settings: settings
|
||||
}, false);
|
||||
|
||||
let requestIDGet = 35;
|
||||
let msgReplyGet = "Settings:Get:OK";
|
||||
let msgHandlerGet = function(message) {
|
||||
equal(requestIDGet, message.data.requestID);
|
||||
equal(lockID, message.data.lockID);
|
||||
for(let p in settings) {
|
||||
equal(settings[p], message.data.settings[p]);
|
||||
}
|
||||
};
|
||||
|
||||
addAndSend("Settings:Get", msgReplyGet, msgHandlerGet, {
|
||||
requestID: requestIDGet,
|
||||
lockID: lockID,
|
||||
name: Object.keys(settings)[0]
|
||||
});
|
||||
|
||||
// We simulate a child death, which will force previous requests to be set
|
||||
// into finalize state
|
||||
kill_child();
|
||||
|
||||
// Then when we issue Settings:Run, those finalized should be triggered
|
||||
send_settingsRun();
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
[DEFAULT]
|
||||
head =
|
||||
tail =
|
||||
|
||||
[test_settingsrequestmanager_messages.js]
|
||||
skip-if = ((buildapp != 'b2g') || ((toolkit == 'gonk') && debug)) # bug 1080377: for some reason, this is not working on emulator-b2g debug build
|
|
@ -348,7 +348,7 @@ function RilObject(aContext) {
|
|||
|
||||
this.telephonyRequestQueue = new TelephonyRequestQueue(this);
|
||||
this.currentCalls = {};
|
||||
this.currentConference = {state: null, participants: {}};
|
||||
this.currentConferenceState = CALL_STATE_UNKNOWN;
|
||||
this.currentDataCalls = {};
|
||||
this._pendingSentSmsMap = {};
|
||||
this.pendingNetworkType = {};
|
||||
|
@ -375,9 +375,9 @@ RilObject.prototype = {
|
|||
currentCalls: null,
|
||||
|
||||
/**
|
||||
* Existing conference call and its participants.
|
||||
* Call state of current conference group.
|
||||
*/
|
||||
currentConference: null,
|
||||
currentConferenceState: null,
|
||||
|
||||
/**
|
||||
* Existing data calls.
|
||||
|
@ -1919,24 +1919,11 @@ RilObject.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
// Flag indicating whether user has requested making a conference call.
|
||||
_hasConferenceRequest: false,
|
||||
|
||||
conferenceCall: function(options) {
|
||||
if (this._isCdma) {
|
||||
options.featureStr = "";
|
||||
this.sendCdmaFlashCommand(options);
|
||||
} else {
|
||||
// Only accept one conference request at a time..
|
||||
if (this._hasConferenceRequest) {
|
||||
options.success = false;
|
||||
options.errorName = "addError";
|
||||
options.errorMsg = GECKO_ERROR_GENERIC_FAILURE;
|
||||
this.sendChromeMessage(options);
|
||||
return;
|
||||
}
|
||||
|
||||
this._hasConferenceRequest = true;
|
||||
this.telephonyRequestQueue.push(REQUEST_CONFERENCE,
|
||||
this.sendRilRequestConference, options);
|
||||
}
|
||||
|
@ -3833,171 +3820,184 @@ RilObject.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Helpers for processing call state and handle the active call.
|
||||
* Classify new calls into three groups: (removed, remained, added).
|
||||
*/
|
||||
_processCalls: function(newCalls) {
|
||||
let conferenceChanged = false;
|
||||
let clearConferenceRequest = false;
|
||||
_classifyCalls: function(newCalls) {
|
||||
newCalls = newCalls || {};
|
||||
|
||||
let removedCalls = [];
|
||||
let remainedCalls = [];
|
||||
let addedCalls = [];
|
||||
|
||||
// Go through the calls we currently have on file and see if any of them
|
||||
// changed state. Remove them from the newCalls map as we deal with them
|
||||
// so that only new calls remain in the map after we're done.
|
||||
for each (let currentCall in this.currentCalls) {
|
||||
let newCall;
|
||||
if (newCalls) {
|
||||
newCall = newCalls[currentCall.callIndex];
|
||||
delete newCalls[currentCall.callIndex];
|
||||
}
|
||||
|
||||
// Call is no longer reported by the radio. Remove from our map and send
|
||||
// disconnected state change.
|
||||
let newCall = newCalls[currentCall.callIndex];
|
||||
if (!newCall) {
|
||||
if (this.currentConference.participants[currentCall.callIndex]) {
|
||||
conferenceChanged = true;
|
||||
}
|
||||
this._removeVoiceCall(currentCall,
|
||||
currentCall.hangUpLocal ?
|
||||
GECKO_CALL_ERROR_NORMAL_CALL_CLEARING : null);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Call is still valid.
|
||||
if (newCall.state == currentCall.state &&
|
||||
newCall.isMpty == currentCall.isMpty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// State has changed.
|
||||
if (newCall.state == CALL_STATE_INCOMING &&
|
||||
currentCall.state == CALL_STATE_WAITING) {
|
||||
// Update the call internally but we don't notify chrome since these two
|
||||
// states are viewed as the same one there.
|
||||
currentCall.state = newCall.state;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!currentCall.started && newCall.state == CALL_STATE_ACTIVE) {
|
||||
currentCall.started = new Date().getTime();
|
||||
}
|
||||
|
||||
if (currentCall.isMpty == newCall.isMpty &&
|
||||
newCall.state != currentCall.state) {
|
||||
currentCall.state = newCall.state;
|
||||
if (currentCall.isConference) {
|
||||
conferenceChanged = true;
|
||||
}
|
||||
this._handleChangedCallState(currentCall);
|
||||
continue;
|
||||
}
|
||||
|
||||
// '.isMpty' becomes false when the conference call is put on hold.
|
||||
// We need to introduce additional 'isConference' to correctly record the
|
||||
// real conference status
|
||||
|
||||
// Update a possible conference participant when .isMpty changes.
|
||||
if (!currentCall.isMpty && newCall.isMpty) {
|
||||
if (this._hasConferenceRequest) {
|
||||
conferenceChanged = true;
|
||||
clearConferenceRequest = true;
|
||||
currentCall.state = newCall.state;
|
||||
currentCall.isMpty = newCall.isMpty;
|
||||
currentCall.isConference = true;
|
||||
this.currentConference.participants[currentCall.callIndex] = currentCall;
|
||||
this._handleChangedCallState(currentCall);
|
||||
} else if (currentCall.isConference) {
|
||||
// The case happens when resuming a held conference call.
|
||||
conferenceChanged = true;
|
||||
currentCall.state = newCall.state;
|
||||
currentCall.isMpty = newCall.isMpty;
|
||||
this.currentConference.participants[currentCall.callIndex] = currentCall;
|
||||
this._handleChangedCallState(currentCall);
|
||||
} else {
|
||||
// Weird. This sometimes happens when we switch two calls, but it is
|
||||
// not a conference call.
|
||||
currentCall.state = newCall.state;
|
||||
this._handleChangedCallState(currentCall);
|
||||
}
|
||||
} else if (currentCall.isMpty && !newCall.isMpty) {
|
||||
if (!this.currentConference.participants[newCall.callIndex]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// '.isMpty' of a conference participant is set to false by rild when
|
||||
// the conference call is put on hold. We don't actually know if the call
|
||||
// still attends the conference until updating all calls finishes. We
|
||||
// cache it for further determination.
|
||||
if (newCall.state != CALL_STATE_HOLDING) {
|
||||
delete this.currentConference.participants[newCall.callIndex];
|
||||
currentCall.state = newCall.state;
|
||||
currentCall.isMpty = newCall.isMpty;
|
||||
currentCall.isConference = false;
|
||||
conferenceChanged = true;
|
||||
this._handleChangedCallState(currentCall);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.currentConference.cache) {
|
||||
this.currentConference.cache = {};
|
||||
}
|
||||
this.currentConference.cache[currentCall.callIndex] = newCall;
|
||||
currentCall.state = newCall.state;
|
||||
currentCall.isMpty = newCall.isMpty;
|
||||
conferenceChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
// We have a successful dialing request. Check whether we could find a new
|
||||
// call for it.
|
||||
if (this.pendingMO) {
|
||||
let options = this.pendingMO.options;
|
||||
this.pendingMO = null;
|
||||
|
||||
// Find the callIndex of the new outgoing call.
|
||||
let callIndex = -1;
|
||||
for (let i in newCalls) {
|
||||
if (newCalls[i].state !== CALL_STATE_INCOMING) {
|
||||
callIndex = newCalls[i].callIndex;
|
||||
newCalls[i].isEmergency = options.isEmergency;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (callIndex === -1) {
|
||||
// The call doesn't exist.
|
||||
options.success = false;
|
||||
options.errorMsg = GECKO_CALL_ERROR_UNSPECIFIED;
|
||||
this.sendChromeMessage(options);
|
||||
removedCalls.push(currentCall);
|
||||
} else {
|
||||
options.success = true;
|
||||
options.callIndex = callIndex;
|
||||
this.sendChromeMessage(options);
|
||||
remainedCalls.push(newCall);
|
||||
delete newCalls[currentCall.callIndex];
|
||||
}
|
||||
}
|
||||
|
||||
// Go through any remaining calls that are new to us.
|
||||
for each (let newCall in newCalls) {
|
||||
if (!newCall.isVoice) {
|
||||
if (newCall.isVoice) {
|
||||
addedCalls.push(newCall);
|
||||
}
|
||||
}
|
||||
|
||||
return [removedCalls, remainedCalls, addedCalls];
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the calls in addedCalls and assign an appropriate one to pendingMO.
|
||||
* Also update the |isEmergency| on that call.
|
||||
*/
|
||||
_assignPendingMO: function(addedCalls) {
|
||||
let options = this.pendingMO.options;
|
||||
this.pendingMO = null;
|
||||
|
||||
for (let call of addedCalls) {
|
||||
if (call.state !== CALL_STATE_INCOMING) {
|
||||
call.isEmergency = options.isEmergency;
|
||||
options.success = true;
|
||||
options.callIndex = call.callIndex;
|
||||
this.sendChromeMessage(options);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The call doesn't exist.
|
||||
options.success = false;
|
||||
options.errorMsg = GECKO_CALL_ERROR_UNSPECIFIED;
|
||||
this.sendChromeMessage(options);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check the currentCalls and identify the conference group.
|
||||
* Return the conference state and the group as a set.
|
||||
*/
|
||||
_detectConference: function() {
|
||||
// There are some difficuties to identify the conference by |.isMpty| so we
|
||||
// don't rely on this flag.
|
||||
// - |.isMpty| becomes false when the conference call is put on hold.
|
||||
// - |.isMpty| may remain true when other participants left the conference.
|
||||
|
||||
// All the calls in the conference should have the same state and it is
|
||||
// either ACTIVE or HOLDING. That means, if we find a group of call with
|
||||
// the same state and its size is larger than 2, it must be a conference.
|
||||
let activeCalls = new Set();
|
||||
let holdingCalls = new Set();
|
||||
|
||||
for each (let call in this.currentCalls) {
|
||||
if (call.state === CALL_STATE_ACTIVE) {
|
||||
activeCalls.add(call);
|
||||
} else if (call.state === CALL_STATE_HOLDING) {
|
||||
holdingCalls.add(call);
|
||||
}
|
||||
}
|
||||
|
||||
if (activeCalls.size >= 2) {
|
||||
return [CALL_STATE_ACTIVE, activeCalls];
|
||||
} else if (holdingCalls.size >= 2) {
|
||||
return [CALL_STATE_HOLDING, holdingCalls];
|
||||
}
|
||||
|
||||
return [CALL_STATE_UNKNOWN, new Set()];
|
||||
},
|
||||
|
||||
/**
|
||||
* Helpers for processing call state changes.
|
||||
*/
|
||||
_processClassifiedCalls: function(removedCalls, remainedCalls, addedCalls,
|
||||
failCause) {
|
||||
// Handle removed calls.
|
||||
for (let call of removedCalls) {
|
||||
this._removeVoiceCall(call, call.hangUpLocal ?
|
||||
GECKO_CALL_ERROR_NORMAL_CALL_CLEARING : failCause);
|
||||
}
|
||||
|
||||
let changedCalls = new Set();
|
||||
|
||||
// Handle remained calls.
|
||||
for (let newCall of remainedCalls) {
|
||||
let oldCall = this.currentCalls[newCall.callIndex];
|
||||
if (oldCall.state == newCall.state) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (newCall.isMpty) {
|
||||
conferenceChanged = true;
|
||||
if (oldCall.state == CALL_STATE_WAITING &&
|
||||
newCall.state == CALL_STATE_INCOMING) {
|
||||
// Update the call internally but we don't notify chrome since these two
|
||||
// states are viewed as the same one there.
|
||||
oldCall.state = newCall.state;
|
||||
continue;
|
||||
}
|
||||
|
||||
this._addNewVoiceCall(newCall);
|
||||
if (!oldCall.started && newCall.state == CALL_STATE_ACTIVE) {
|
||||
oldCall.started = new Date().getTime();
|
||||
}
|
||||
|
||||
oldCall.state = newCall.state;
|
||||
changedCalls.add(oldCall);
|
||||
}
|
||||
|
||||
if (clearConferenceRequest) {
|
||||
this._hasConferenceRequest = false;
|
||||
}
|
||||
if (conferenceChanged) {
|
||||
this._ensureConference();
|
||||
// Handle pendingMO.
|
||||
if (this.pendingMO) {
|
||||
this._assignPendingMO(addedCalls);
|
||||
}
|
||||
|
||||
// Update audio state.
|
||||
let message = {rilMessageType: "audioStateChanged",
|
||||
state: this._detectAudioState()};
|
||||
this.sendChromeMessage(message);
|
||||
// Handle added calls.
|
||||
for (let call of addedCalls) {
|
||||
this._addVoiceCall(call);
|
||||
changedCalls.add(call);
|
||||
}
|
||||
|
||||
// Detect conference and update isConference flag.
|
||||
let [newConferenceState, conference] = this._detectConference();
|
||||
for each (let call in this.currentCalls) {
|
||||
let isConference = conference.has(call);
|
||||
if (call.isConference != isConference) {
|
||||
call.isConference = isConference;
|
||||
changedCalls.add(call);
|
||||
}
|
||||
}
|
||||
|
||||
// Update audio state. We have to send the message before callstatechange
|
||||
// to make sure that the audio state is ready first.
|
||||
this.sendChromeMessage({
|
||||
rilMessageType: "audioStateChanged",
|
||||
state: this._detectAudioState()
|
||||
});
|
||||
|
||||
// Notify call state change.
|
||||
for (let call of changedCalls) {
|
||||
this._handleChangedCallState(call);
|
||||
}
|
||||
|
||||
// Notify conference state change.
|
||||
if (this.currentConferenceState != newConferenceState) {
|
||||
this.currentConferenceState = newConferenceState;
|
||||
let message = {rilMessageType: "conferenceCallStateChanged",
|
||||
state: newConferenceState};
|
||||
this.sendChromeMessage(message);
|
||||
}
|
||||
},
|
||||
|
||||
_processCalls: function(newCalls) {
|
||||
let [removed, remained, added] = this._classifyCalls(newCalls);
|
||||
|
||||
// Let's get the failCause first if there are removed calls. Otherwise, we
|
||||
// need to trigger another async request when removing call and it cause
|
||||
// the order of callDisconnected and conferenceCallStateChanged
|
||||
// unpredictable.
|
||||
if (removed.length) {
|
||||
this.getFailCauseCode((function(removed, remained, added, failCause) {
|
||||
this._processClassifiedCalls(removed, remained, added, failCause);
|
||||
}).bind(this, removed, remained, added));
|
||||
} else {
|
||||
this._processClassifiedCalls(removed, remained, added);
|
||||
}
|
||||
},
|
||||
|
||||
_detectAudioState: function() {
|
||||
|
@ -4015,90 +4015,23 @@ RilObject.prototype = {
|
|||
return AUDIO_STATE_IN_CALL;
|
||||
},
|
||||
|
||||
_addNewVoiceCall: function(newCall) {
|
||||
_addVoiceCall: function(newCall) {
|
||||
// Format international numbers appropriately.
|
||||
if (newCall.number && newCall.toa == TOA_INTERNATIONAL &&
|
||||
newCall.number[0] != "+") {
|
||||
newCall.number = "+" + newCall.number;
|
||||
}
|
||||
|
||||
if (newCall.state == CALL_STATE_INCOMING) {
|
||||
newCall.isOutgoing = false;
|
||||
} else if (newCall.state == CALL_STATE_DIALING) {
|
||||
newCall.isOutgoing = true;
|
||||
}
|
||||
newCall.isOutgoing = !(newCall.state == CALL_STATE_INCOMING);
|
||||
newCall.isConference = false;
|
||||
|
||||
// Set flag for conference.
|
||||
newCall.isConference = newCall.isMpty ? true : false;
|
||||
|
||||
// Add to our map.
|
||||
if (newCall.isMpty) {
|
||||
this.currentConference.participants[newCall.callIndex] = newCall;
|
||||
}
|
||||
this._handleChangedCallState(newCall);
|
||||
this.currentCalls[newCall.callIndex] = newCall;
|
||||
},
|
||||
|
||||
_removeVoiceCall: function(removedCall, failCause) {
|
||||
if (this.currentConference.participants[removedCall.callIndex]) {
|
||||
removedCall.isConference = false;
|
||||
delete this.currentConference.participants[removedCall.callIndex];
|
||||
delete this.currentCalls[removedCall.callIndex];
|
||||
// We don't query the fail cause here as it triggers another asynchrouns
|
||||
// request that leads to a problem of updating all conferece participants
|
||||
// in one task.
|
||||
this._handleDisconnectedCall(removedCall);
|
||||
} else {
|
||||
delete this.currentCalls[removedCall.callIndex];
|
||||
if (failCause) {
|
||||
removedCall.failCause = failCause;
|
||||
this._handleDisconnectedCall(removedCall);
|
||||
} else {
|
||||
this.getFailCauseCode((function(call, failCause) {
|
||||
call.failCause = failCause;
|
||||
this._handleDisconnectedCall(call);
|
||||
}).bind(this, removedCall));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_ensureConference: function() {
|
||||
let oldState = this.currentConference.state;
|
||||
let remaining = Object.keys(this.currentConference.participants);
|
||||
|
||||
if (remaining.length == 1) {
|
||||
// Remove that if only does one remain in a conference call.
|
||||
let call = this.currentCalls[remaining[0]];
|
||||
call.isConference = false;
|
||||
this._handleChangedCallState(call);
|
||||
delete this.currentConference.participants[call.callIndex];
|
||||
} else if (remaining.length > 1) {
|
||||
for each (let call in this.currentConference.cache) {
|
||||
call.isConference = true;
|
||||
this.currentConference.participants[call.callIndex] = call;
|
||||
this.currentCalls[call.callIndex] = call;
|
||||
this._handleChangedCallState(call);
|
||||
}
|
||||
}
|
||||
delete this.currentConference.cache;
|
||||
|
||||
// Update the conference call's state.
|
||||
let state = CALL_STATE_UNKNOWN;
|
||||
for each (let call in this.currentConference.participants) {
|
||||
if (state != CALL_STATE_UNKNOWN && state != call.state) {
|
||||
// Each participant should have the same state, otherwise something
|
||||
// wrong happens.
|
||||
state = CALL_STATE_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
state = call.state;
|
||||
}
|
||||
if (oldState != state) {
|
||||
this.currentConference.state = state;
|
||||
let message = {rilMessageType: "conferenceCallStateChanged",
|
||||
state: state};
|
||||
this.sendChromeMessage(message);
|
||||
}
|
||||
_removeVoiceCall: function(call, failCause) {
|
||||
delete this.currentCalls[call.callIndex];
|
||||
call.failCause = failCause;
|
||||
this._handleDisconnectedCall(call);
|
||||
},
|
||||
|
||||
_handleChangedCallState: function(changedCall) {
|
||||
|
@ -5528,7 +5461,6 @@ RilObject.prototype[REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = function REQ
|
|||
RilObject.prototype[REQUEST_CONFERENCE] = function REQUEST_CONFERENCE(length, options) {
|
||||
options.success = (options.rilRequestError === 0);
|
||||
if (!options.success) {
|
||||
this._hasConferenceRequest = false;
|
||||
options.errorName = "addError";
|
||||
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
|
||||
this.sendChromeMessage(options);
|
||||
|
|
|
@ -495,6 +495,11 @@ Telephony::CallStateChanged(uint32_t aServiceId, uint32_t aCallIndex,
|
|||
modifiedCall->UpdateMergeable(aIsMergeable);
|
||||
|
||||
if (modifiedCall->CallState() != aCallState) {
|
||||
if (aCallState == nsITelephonyService::CALL_STATE_DISCONNECTED) {
|
||||
modifiedCall->ChangeStateInternal(aCallState, true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// We don't fire the statechange event on a call in conference here.
|
||||
// Instead, the event will be fired later in
|
||||
// TelephonyCallGroup::ChangeState(). Thus the sequence of firing the
|
||||
|
|
|
@ -227,15 +227,26 @@ let emulator = (function() {
|
|||
is(call.state, state, "call state");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient helper to compare two call lists. Size should be the same and
|
||||
* order is not important.
|
||||
*/
|
||||
function checkCalls(actualCalls, expectedCalls) {
|
||||
if (actualCalls.length == expectedCalls.length) {
|
||||
let expectedSet = new Set(expectedCalls);
|
||||
for (let i = 0; i < actualCalls.length; ++i) {
|
||||
ok(expectedSet.has(actualCalls[i]), "should contain the call");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient helper to check mozTelephony.active and mozTelephony.calls.
|
||||
*/
|
||||
function checkTelephonyActiveAndCalls(active, calls) {
|
||||
is(telephony.active, active, "telephony.active");
|
||||
is(telephony.calls.length, calls.length, "telephony.calls");
|
||||
for (let i = 0; i < calls.length; ++i) {
|
||||
is(telephony.calls[i], calls[i]);
|
||||
}
|
||||
checkCalls(telephony.calls, calls);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -245,9 +256,7 @@ let emulator = (function() {
|
|||
function checkConferenceStateAndCalls(state, calls) {
|
||||
is(conference.state, state, "conference.state");
|
||||
is(conference.calls.length, calls.length, "conference.calls");
|
||||
for (let i = 0; i < calls.length; i++) {
|
||||
is(conference.calls[i], calls[i]);
|
||||
}
|
||||
checkCalls(conference.calls, calls);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,10 +15,10 @@ namespace mozilla {
|
|||
namespace ipc {
|
||||
|
||||
//
|
||||
// UnixSocketRawData
|
||||
// UnixSocketIOBuffer
|
||||
//
|
||||
|
||||
UnixSocketRawData::UnixSocketRawData(const void* aData, size_t aSize)
|
||||
UnixSocketIOBuffer::UnixSocketIOBuffer(const void* aData, size_t aSize)
|
||||
: mSize(aSize)
|
||||
, mOffset(0)
|
||||
, mAvailableSpace(aSize)
|
||||
|
@ -29,14 +29,90 @@ UnixSocketRawData::UnixSocketRawData(const void* aData, size_t aSize)
|
|||
memcpy(mData, aData, mSize);
|
||||
}
|
||||
|
||||
UnixSocketRawData::UnixSocketRawData(size_t aSize)
|
||||
UnixSocketIOBuffer::UnixSocketIOBuffer(size_t aAvailableSpace)
|
||||
: mSize(0)
|
||||
, mOffset(0)
|
||||
, mAvailableSpace(aSize)
|
||||
, mAvailableSpace(aAvailableSpace)
|
||||
{
|
||||
mData = new uint8_t[mAvailableSpace];
|
||||
}
|
||||
|
||||
UnixSocketIOBuffer::~UnixSocketIOBuffer()
|
||||
{ }
|
||||
|
||||
const uint8_t*
|
||||
UnixSocketIOBuffer::Consume(size_t aLen)
|
||||
{
|
||||
if (NS_WARN_IF(GetSize() < aLen)) {
|
||||
return nullptr;
|
||||
}
|
||||
uint8_t* data = mData + mOffset;
|
||||
mOffset += aLen;
|
||||
return data;
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnixSocketIOBuffer::Read(void* aValue, size_t aLen)
|
||||
{
|
||||
const uint8_t* data = Consume(aLen);
|
||||
if (!data) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(aValue, data, aLen);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
UnixSocketIOBuffer::Append(size_t aLen)
|
||||
{
|
||||
if (((mAvailableSpace - mSize) < aLen)) {
|
||||
size_t availableSpace = mAvailableSpace + std::max(mAvailableSpace, aLen);
|
||||
uint8_t* data = new uint8_t[availableSpace];
|
||||
memcpy(data, mData, mSize);
|
||||
mData = data;
|
||||
mAvailableSpace = availableSpace;
|
||||
}
|
||||
uint8_t* data = mData + mSize;
|
||||
mSize += aLen;
|
||||
return data;
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnixSocketIOBuffer::Write(const void* aValue, size_t aLen)
|
||||
{
|
||||
uint8_t* data = Append(aLen);
|
||||
if (!data) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(data, aValue, aLen);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
UnixSocketIOBuffer::CleanupLeadingSpace()
|
||||
{
|
||||
if (GetLeadingSpace()) {
|
||||
if (GetSize() <= GetLeadingSpace()) {
|
||||
memcpy(mData, GetData(), GetSize());
|
||||
} else {
|
||||
memmove(mData, GetData(), GetSize());
|
||||
}
|
||||
mOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// UnixSocketRawData
|
||||
//
|
||||
|
||||
UnixSocketRawData::UnixSocketRawData(const void* aData, size_t aSize)
|
||||
: UnixSocketIOBuffer(aData, aSize)
|
||||
{ }
|
||||
|
||||
UnixSocketRawData::UnixSocketRawData(size_t aSize)
|
||||
: UnixSocketIOBuffer(aSize)
|
||||
{ }
|
||||
|
||||
ssize_t
|
||||
UnixSocketRawData::Receive(int aFd)
|
||||
{
|
||||
|
@ -45,12 +121,7 @@ UnixSocketRawData::Receive(int aFd)
|
|||
return -1; /* buffer is full */
|
||||
}
|
||||
/* free up space at the end of data buffer */
|
||||
if (GetSize() <= GetLeadingSpace()) {
|
||||
memcpy(mData, GetData(), GetSize());
|
||||
} else {
|
||||
memmove(mData, GetData(), GetSize());
|
||||
}
|
||||
mOffset = 0;
|
||||
CleanupLeadingSpace();
|
||||
}
|
||||
|
||||
ssize_t res =
|
||||
|
@ -64,7 +135,7 @@ UnixSocketRawData::Receive(int aFd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
mSize += res;
|
||||
Append(res); /* mark read data as 'valid' */
|
||||
|
||||
return res;
|
||||
}
|
||||
|
@ -94,16 +165,16 @@ UnixSocketRawData::Send(int aFd)
|
|||
}
|
||||
|
||||
//
|
||||
// SocketConsumerBase
|
||||
// SocketBase
|
||||
//
|
||||
|
||||
SocketConsumerBase::~SocketConsumerBase()
|
||||
SocketBase::~SocketBase()
|
||||
{
|
||||
MOZ_ASSERT(mConnectionStatus == SOCKET_DISCONNECTED);
|
||||
}
|
||||
|
||||
SocketConnectionStatus
|
||||
SocketConsumerBase::GetConnectionStatus() const
|
||||
SocketBase::GetConnectionStatus() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -111,7 +182,7 @@ SocketConsumerBase::GetConnectionStatus() const
|
|||
}
|
||||
|
||||
int
|
||||
SocketConsumerBase::GetSuggestedConnectDelayMs() const
|
||||
SocketBase::GetSuggestedConnectDelayMs() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -119,7 +190,7 @@ SocketConsumerBase::GetSuggestedConnectDelayMs() const
|
|||
}
|
||||
|
||||
void
|
||||
SocketConsumerBase::NotifySuccess()
|
||||
SocketBase::NotifySuccess()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -129,7 +200,7 @@ SocketConsumerBase::NotifySuccess()
|
|||
}
|
||||
|
||||
void
|
||||
SocketConsumerBase::NotifyError()
|
||||
SocketBase::NotifyError()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -140,7 +211,7 @@ SocketConsumerBase::NotifyError()
|
|||
}
|
||||
|
||||
void
|
||||
SocketConsumerBase::NotifyDisconnect()
|
||||
SocketBase::NotifyDisconnect()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -151,7 +222,7 @@ SocketConsumerBase::NotifyDisconnect()
|
|||
}
|
||||
|
||||
uint32_t
|
||||
SocketConsumerBase::CalculateConnectDelayMs() const
|
||||
SocketBase::CalculateConnectDelayMs() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
|
@ -170,19 +241,25 @@ SocketConsumerBase::CalculateConnectDelayMs() const
|
|||
return connectDelayMs;
|
||||
}
|
||||
|
||||
SocketConsumerBase::SocketConsumerBase()
|
||||
SocketBase::SocketBase()
|
||||
: mConnectionStatus(SOCKET_DISCONNECTED)
|
||||
, mConnectTimestamp(0)
|
||||
, mConnectDelayMs(0)
|
||||
{ }
|
||||
|
||||
void
|
||||
SocketConsumerBase::SetConnectionStatus(
|
||||
SocketConnectionStatus aConnectionStatus)
|
||||
SocketBase::SetConnectionStatus(SocketConnectionStatus aConnectionStatus)
|
||||
{
|
||||
mConnectionStatus = aConnectionStatus;
|
||||
}
|
||||
|
||||
//
|
||||
// SocketConsumerBase
|
||||
//
|
||||
|
||||
SocketConsumerBase::~SocketConsumerBase()
|
||||
{ }
|
||||
|
||||
//
|
||||
// SocketIOBase
|
||||
//
|
||||
|
|
|
@ -22,11 +22,153 @@ using namespace mozilla::tasktracer;
|
|||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
//
|
||||
// UnixSocketIOBuffer
|
||||
//
|
||||
|
||||
class UnixSocketIOBuffer
|
||||
{
|
||||
public:
|
||||
const uint8_t* GetData() const
|
||||
{
|
||||
return mData + mOffset;
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
return mSize - mOffset;
|
||||
}
|
||||
|
||||
const uint8_t* Consume(size_t aLen);
|
||||
|
||||
nsresult Read(void* aValue, size_t aLen);
|
||||
|
||||
nsresult Read(int8_t& aValue)
|
||||
{
|
||||
return Read(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Read(uint8_t& aValue)
|
||||
{
|
||||
return Read(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Read(int16_t& aValue)
|
||||
{
|
||||
return Read(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Read(uint16_t& aValue)
|
||||
{
|
||||
return Read(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Read(int32_t& aValue)
|
||||
{
|
||||
return Read(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Read(uint32_t& aValue)
|
||||
{
|
||||
return Read(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
uint8_t* Append(size_t aLen);
|
||||
|
||||
nsresult Write(const void* aValue, size_t aLen);
|
||||
|
||||
nsresult Write(int8_t aValue)
|
||||
{
|
||||
return Write(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Write(uint8_t aValue)
|
||||
{
|
||||
return Write(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Write(int16_t aValue)
|
||||
{
|
||||
return Write(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Write(uint16_t aValue)
|
||||
{
|
||||
return Write(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Write(int32_t aValue)
|
||||
{
|
||||
return Write(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
nsresult Write(uint32_t aValue)
|
||||
{
|
||||
return Write(&aValue, sizeof(aValue));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/* This constructor copies aData of aSize bytes length into the
|
||||
* new instance of |UnixSocketIOBuffer|.
|
||||
*/
|
||||
UnixSocketIOBuffer(const void* aData, size_t aSize);
|
||||
|
||||
/* This constructor reserves aAvailableSpace bytes of space.
|
||||
*/
|
||||
UnixSocketIOBuffer(size_t aAvailableSpace);
|
||||
|
||||
~UnixSocketIOBuffer();
|
||||
|
||||
size_t GetLeadingSpace() const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
size_t GetTrailingSpace() const
|
||||
{
|
||||
return mAvailableSpace - mSize;
|
||||
}
|
||||
|
||||
size_t GetAvailableSpace() const
|
||||
{
|
||||
return mAvailableSpace;
|
||||
}
|
||||
|
||||
void* GetTrailingBytes()
|
||||
{
|
||||
return mData + mSize;
|
||||
}
|
||||
|
||||
uint8_t* GetData(size_t aOffset)
|
||||
{
|
||||
MOZ_ASSERT(aOffset <= mSize);
|
||||
|
||||
return mData + aOffset;
|
||||
}
|
||||
|
||||
void SetRange(size_t aOffset, size_t aSize)
|
||||
{
|
||||
MOZ_ASSERT((aOffset + aSize) <= mAvailableSpace);
|
||||
|
||||
mOffset = aOffset;
|
||||
mSize = mOffset + aSize;
|
||||
}
|
||||
|
||||
void CleanupLeadingSpace();
|
||||
|
||||
private:
|
||||
size_t mSize;
|
||||
size_t mOffset;
|
||||
size_t mAvailableSpace;
|
||||
nsAutoArrayPtr<uint8_t> mData;
|
||||
};
|
||||
|
||||
//
|
||||
// UnixSocketRawData
|
||||
//
|
||||
|
||||
class UnixSocketRawData
|
||||
class UnixSocketRawData MOZ_FINAL : public UnixSocketIOBuffer
|
||||
{
|
||||
public:
|
||||
/* This constructor copies aData of aSize bytes length into the
|
||||
|
@ -51,51 +193,6 @@ public:
|
|||
* is the number of bytes written, or a negative value on error.
|
||||
*/
|
||||
ssize_t Send(int aFd);
|
||||
|
||||
const uint8_t* GetData() const
|
||||
{
|
||||
return mData + mOffset;
|
||||
}
|
||||
|
||||
size_t GetSize() const
|
||||
{
|
||||
return mSize;
|
||||
}
|
||||
|
||||
void Consume(size_t aSize)
|
||||
{
|
||||
MOZ_ASSERT(aSize <= mSize);
|
||||
|
||||
mSize -= aSize;
|
||||
mOffset += aSize;
|
||||
}
|
||||
|
||||
protected:
|
||||
size_t GetLeadingSpace() const
|
||||
{
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
size_t GetTrailingSpace() const
|
||||
{
|
||||
return mAvailableSpace - (mOffset + mSize);
|
||||
}
|
||||
|
||||
size_t GetAvailableSpace() const
|
||||
{
|
||||
return mAvailableSpace;
|
||||
}
|
||||
|
||||
void* GetTrailingBytes()
|
||||
{
|
||||
return mData + mOffset + mSize;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t mSize;
|
||||
size_t mOffset;
|
||||
size_t mAvailableSpace;
|
||||
nsAutoArrayPtr<uint8_t> mData;
|
||||
};
|
||||
|
||||
enum SocketConnectionStatus {
|
||||
|
@ -106,15 +203,15 @@ enum SocketConnectionStatus {
|
|||
};
|
||||
|
||||
//
|
||||
// SocketConsumerBase
|
||||
// SocketBase
|
||||
//
|
||||
|
||||
class SocketConsumerBase
|
||||
class SocketBase
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketConsumerBase)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SocketBase)
|
||||
|
||||
virtual ~SocketConsumerBase();
|
||||
virtual ~SocketBase();
|
||||
|
||||
SocketConnectionStatus GetConnectionStatus() const;
|
||||
|
||||
|
@ -126,24 +223,6 @@ public:
|
|||
*/
|
||||
virtual void CloseSocket() = 0;
|
||||
|
||||
/**
|
||||
* Function to be called whenever data is received. This is only called on the
|
||||
* main thread.
|
||||
*
|
||||
* @param aMessage Data received from the socket.
|
||||
*/
|
||||
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage) = 0;
|
||||
|
||||
/**
|
||||
* Queue data to be sent to the socket on the IO thread. Can only be called on
|
||||
* originating thread.
|
||||
*
|
||||
* @param aMessage Data to be sent to socket
|
||||
*
|
||||
* @return true if data is queued, false otherwise (i.e. not connected)
|
||||
*/
|
||||
virtual bool SendSocketData(UnixSocketRawData* aMessage) = 0;
|
||||
|
||||
/**
|
||||
* Callback for socket connect/accept success. Called after connect/accept has
|
||||
* finished. Will be run on main thread, before any reads take place.
|
||||
|
@ -176,7 +255,7 @@ public:
|
|||
void NotifyDisconnect();
|
||||
|
||||
protected:
|
||||
SocketConsumerBase();
|
||||
SocketBase();
|
||||
|
||||
void SetConnectionStatus(SocketConnectionStatus aConnectionStatus);
|
||||
|
||||
|
@ -188,6 +267,34 @@ private:
|
|||
uint32_t mConnectDelayMs;
|
||||
};
|
||||
|
||||
//
|
||||
// SocketConsumerBase
|
||||
//
|
||||
|
||||
class SocketConsumerBase : public SocketBase
|
||||
{
|
||||
public:
|
||||
virtual ~SocketConsumerBase();
|
||||
|
||||
/**
|
||||
* Function to be called whenever data is received. This is only called on the
|
||||
* main thread.
|
||||
*
|
||||
* @param aMessage Data received from the socket.
|
||||
*/
|
||||
virtual void ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage) = 0;
|
||||
|
||||
/**
|
||||
* Queue data to be sent to the socket on the IO thread. Can only be called on
|
||||
* originating thread.
|
||||
*
|
||||
* @param aMessage Data to be sent to socket
|
||||
*
|
||||
* @return true if data is queued, false otherwise (i.e. not connected)
|
||||
*/
|
||||
virtual bool SendSocketData(UnixSocketRawData* aMessage) = 0;
|
||||
};
|
||||
|
||||
//
|
||||
// Socket I/O runnables
|
||||
//
|
||||
|
@ -249,15 +356,15 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
SocketConsumerBase* consumer = io->GetConsumer();
|
||||
MOZ_ASSERT(consumer);
|
||||
SocketBase* base = io->GetSocketBase();
|
||||
MOZ_ASSERT(base);
|
||||
|
||||
if (mEvent == CONNECT_SUCCESS) {
|
||||
consumer->NotifySuccess();
|
||||
base->NotifySuccess();
|
||||
} else if (mEvent == CONNECT_ERROR) {
|
||||
consumer->NotifyError();
|
||||
base->NotifyError();
|
||||
} else if (mEvent == DISCONNECT) {
|
||||
consumer->NotifyDisconnect();
|
||||
base->NotifyDisconnect();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
@ -325,10 +432,10 @@ public:
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
SocketConsumerBase* consumer = io->GetConsumer();
|
||||
MOZ_ASSERT(consumer);
|
||||
SocketBase* base = io->GetSocketBase();
|
||||
MOZ_ASSERT(base);
|
||||
|
||||
consumer->CloseSocket();
|
||||
base->CloseSocket();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -453,14 +560,14 @@ private:
|
|||
/* |SocketIOTask| holds a reference to a Socket I/O object. It's
|
||||
* supposed to run on the I/O thread.
|
||||
*/
|
||||
template <typename T>
|
||||
template<typename Tio>
|
||||
class SocketIOTask : public CancelableTask
|
||||
{
|
||||
public:
|
||||
virtual ~SocketIOTask()
|
||||
{ }
|
||||
|
||||
T* GetIO() const
|
||||
Tio* GetIO() const
|
||||
{
|
||||
return mIO;
|
||||
}
|
||||
|
@ -476,25 +583,26 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
SocketIOTask(T* aIO)
|
||||
SocketIOTask(Tio* aIO)
|
||||
: mIO(aIO)
|
||||
{
|
||||
MOZ_ASSERT(mIO);
|
||||
}
|
||||
|
||||
private:
|
||||
T* mIO;
|
||||
Tio* mIO;
|
||||
};
|
||||
|
||||
/* |SocketIOSendTask| transfers an instance of |UnixSocketRawData| to
|
||||
* the I/O thread and queues it up for sending the contained data.
|
||||
/* |SocketIOSendTask| transfers an instance of |Tdata|, such as
|
||||
* |UnixSocketRawData|, to the I/O thread and queues it up for
|
||||
* sending the contained data.
|
||||
*/
|
||||
template <typename T>
|
||||
class SocketIOSendTask MOZ_FINAL : public SocketIOTask<T>
|
||||
template<typename Tio, typename Tdata>
|
||||
class SocketIOSendTask MOZ_FINAL : public SocketIOTask<Tio>
|
||||
{
|
||||
public:
|
||||
SocketIOSendTask(T* aIO, UnixSocketRawData* aData)
|
||||
: SocketIOTask<T>(aIO)
|
||||
SocketIOSendTask(Tio* aIO, Tdata* aData)
|
||||
: SocketIOTask<Tio>(aIO)
|
||||
, mData(aData)
|
||||
{
|
||||
MOZ_ASSERT(aData);
|
||||
|
@ -503,34 +611,34 @@ public:
|
|||
void Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
MOZ_ASSERT(!SocketIOTask<T>::IsCanceled());
|
||||
MOZ_ASSERT(!SocketIOTask<Tio>::IsCanceled());
|
||||
|
||||
T* io = SocketIOTask<T>::GetIO();
|
||||
Tio* io = SocketIOTask<Tio>::GetIO();
|
||||
MOZ_ASSERT(!io->IsShutdownOnIOThread());
|
||||
|
||||
io->Send(mData);
|
||||
}
|
||||
|
||||
private:
|
||||
UnixSocketRawData* mData;
|
||||
Tdata* mData;
|
||||
};
|
||||
|
||||
/* |SocketIOShutdownTask| signals shutdown to the Socket I/O object on
|
||||
* the I/O thread and sends it to the main thread for destruction.
|
||||
*/
|
||||
template <typename T>
|
||||
class SocketIOShutdownTask MOZ_FINAL : public SocketIOTask<T>
|
||||
template<typename Tio>
|
||||
class SocketIOShutdownTask MOZ_FINAL : public SocketIOTask<Tio>
|
||||
{
|
||||
public:
|
||||
SocketIOShutdownTask(T* aIO)
|
||||
: SocketIOTask<T>(aIO)
|
||||
SocketIOShutdownTask(Tio* aIO)
|
||||
: SocketIOTask<Tio>(aIO)
|
||||
{ }
|
||||
|
||||
void Run() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
T* io = SocketIOTask<T>::GetIO();
|
||||
Tio* io = SocketIOTask<Tio>::GetIO();
|
||||
|
||||
// At this point, there should be no new events on the I/O thread
|
||||
// after this one with the possible exception of an accept task,
|
||||
|
@ -539,7 +647,7 @@ public:
|
|||
// |io| safely knowing that it's not reference any longer.
|
||||
io->ShutdownOnIOThread();
|
||||
|
||||
nsRefPtr<nsRunnable> r = new SocketIODeleteInstanceRunnable<T>(io);
|
||||
nsRefPtr<nsRunnable> r = new SocketIODeleteInstanceRunnable<Tio>(io);
|
||||
nsresult rv = NS_DispatchToMainThread(r);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
|
||||
void GetSocketAddr(nsAString& aAddrStr) const;
|
||||
SocketConsumerBase* GetConsumer();
|
||||
SocketBase* GetSocketBase();
|
||||
|
||||
// Shutdown state
|
||||
//
|
||||
|
@ -157,6 +158,12 @@ UnixSocketConsumerIO::GetConsumer()
|
|||
return mConsumer.get();
|
||||
}
|
||||
|
||||
SocketBase*
|
||||
UnixSocketConsumerIO::GetSocketBase()
|
||||
{
|
||||
return GetConsumer();
|
||||
}
|
||||
|
||||
bool
|
||||
UnixSocketConsumerIO::IsShutdownOnMainThread() const
|
||||
{
|
||||
|
@ -548,7 +555,8 @@ UnixSocketConsumer::SendSocketData(UnixSocketRawData* aData)
|
|||
|
||||
MOZ_ASSERT(!mIO->IsShutdownOnMainThread());
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
FROM_HERE, new SocketIOSendTask<UnixSocketConsumerIO>(mIO, aData));
|
||||
FROM_HERE,
|
||||
new SocketIOSendTask<UnixSocketConsumerIO, UnixSocketRawData>(mIO, aData));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ function init() {
|
|||
|
||||
// Fill "Last visited site" input with most recent history entry URL.
|
||||
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
|
||||
aData = aData.substring(0, 200);
|
||||
document.getElementById("last-url").value = aData;
|
||||
// Enable the parent div iff the URL is valid.
|
||||
if (aData.length != 0) {
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
<h1 class="header">&sad.header;</h1>
|
||||
<form>
|
||||
<div class="message">&sad.message;</div>
|
||||
<textarea class="description" placeholder="&sad.placeholder;" rows="4" required="true"/>
|
||||
<textarea class="description" placeholder="&sad.placeholder;" rows="4" required="true" maxlength="10000"/>
|
||||
<div class="message" id="last-url-div">
|
||||
<span>&sad.lastSite2;</span>
|
||||
<input id="last-checkbox" type="checkbox" checked="checked"/>
|
||||
|
|
Загрузка…
Ссылка в новой задаче