Merge m-c to inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-09-29 16:00:57 -04:00
commit c9810a7fcf
83 changed files with 2024 additions and 589 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>

View File

@ -19,13 +19,13 @@
<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="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
@ -97,7 +97,7 @@
<project name="platform/system/netd" path="system/netd" revision="3d298fde142bee3fc4f07f63f16f2d8ce42339c0"/>
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
<!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="9abf0ab68376afae3e1c7beefa3e9cbee2fde202"/>
<project name="android-development" path="development" remote="b2g" revision="c99e41d49f0b98eade30814e52c1de9e818def68"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="0d5c43228006bae775c4cb57a6d3908484d41718"/>
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>

View File

@ -17,10 +17,10 @@
</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="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>

View File

@ -19,13 +19,13 @@
<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="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
@ -97,7 +97,7 @@
<project name="platform/system/netd" path="system/netd" revision="3d298fde142bee3fc4f07f63f16f2d8ce42339c0"/>
<project name="platform/system/vold" path="system/vold" revision="919829940468066a32f403980b43f6ebfee5d314"/>
<!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="9abf0ab68376afae3e1c7beefa3e9cbee2fde202"/>
<project name="android-development" path="development" remote="b2g" revision="c99e41d49f0b98eade30814e52c1de9e818def68"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="0d5c43228006bae775c4cb57a6d3908484d41718"/>
<project name="platform/external/iproute2" path="external/iproute2" revision="c66c5716d5335e450f7a7b71ccc6a604fb2f41d2"/>
<project name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="d2685281e2e54ca14d1df304867aa82c37b27162"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -23,7 +23,7 @@
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
<project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>

View File

@ -17,10 +17,10 @@
</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="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "4c52c3164207370c4b9180608f73970dcc6bdb78",
"revision": "fb5a4aa15e266e9aa0e44281241ad081b528c75b",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,12 +17,12 @@
<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="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,10 +17,10 @@
</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="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->

View File

@ -17,12 +17,12 @@
<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="4d663b1f7d63e4d3d69c181a58f21b38145044b2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="77ef35f5429bc3dfe9ca192b9aacc3c0bf8857de"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="5883a99b6528ced9dafaed8d3ca2405fb285537e"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0fcf2e913d737e341f7a03f6e1951a5e13bd9d59"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0f7792c39ad26aedecf457117c21b16cc1aee879"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>

View File

@ -160,7 +160,6 @@
#endif
#ifdef MOZ_B2G_RIL
@BINPATH@/components/dom_icc.xpt
@BINPATH@/components/dom_cellbroadcast.xpt
@BINPATH@/components/dom_wappush.xpt
@BINPATH@/components/dom_mobileconnection.xpt
#endif
@ -192,6 +191,7 @@
@BINPATH@/components/dom_settings.xpt
@BINPATH@/components/dom_permissionsettings.xpt
@BINPATH@/components/dom_sidebar.xpt
@BINPATH@/components/dom_cellbroadcast.xpt
@BINPATH@/components/dom_mobilemessage.xpt
@BINPATH@/components/dom_storage.xpt
@BINPATH@/components/dom_stylesheets.xpt
@ -437,6 +437,8 @@
; RIL
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
@BINPATH@/components/CellBroadcastService.js
@BINPATH@/components/CellBroadcastService.manifest
@BINPATH@/components/MmsService.js
@BINPATH@/components/MmsService.manifest
@BINPATH@/components/MobileConnectionService.js

View File

@ -515,6 +515,9 @@ var gPopupBlockerObserver = {
var perm = shouldBlock ? pm.DENY_ACTION : pm.ALLOW_ACTION;
pm.add(gBrowser.currentURI, "popup", perm);
if (!shouldBlock)
this.showAllBlockedPopups(gBrowser.selectedBrowser);
gBrowser.getNotificationBox().removeCurrentNotification();
},
@ -569,6 +572,7 @@ var gPopupBlockerObserver = {
// xxxdz this should make the option say "Show file picker" and do it (Bug 590306)
if (!blockedPopup.popupWindowURI)
continue;
var popupURIspec = blockedPopup.popupWindowURI.spec;
// Sometimes the popup URI that we get back from the blockedPopup
@ -591,9 +595,6 @@ var gPopupBlockerObserver = {
var label = gNavigatorBundle.getFormattedString("popupShowPopupPrefix",
[popupURIspec]);
menuitem.setAttribute("label", label);
menuitem.setAttribute("popupWindowURI", popupURIspec);
menuitem.setAttribute("popupWindowFeatures", blockedPopup.popupWindowFeatures);
menuitem.setAttribute("popupWindowName", blockedPopup.popupWindowName);
menuitem.setAttribute("oncommand", "gPopupBlockerObserver.showBlockedPopup(event);");
menuitem.setAttribute("popupReportIndex", i);
menuitem.popupReportBrowser = browser;
@ -640,6 +641,18 @@ var gPopupBlockerObserver = {
browser.unblockPopup(popupReportIndex);
},
showAllBlockedPopups: function (aBrowser)
{
let popups = aBrowser.blockedPopups;
if (!popups)
return;
for (let i = 0; i < popups.length; i++) {
if (popups[i].popupWindowURI)
aBrowser.unblockPopup(i);
}
},
editPopupSettings: function ()
{
var host = "";

View File

@ -331,13 +331,23 @@ input[type=button] {
#newtab-search-logo {
display: -moz-box;
width: 77px; /* 65 image width + 6 left "padding" + 6 right "padding" */
width: 38px;
height: 38px; /* 26 image height + 6 top "padding" + 6 bottom "padding" */
border: 1px solid transparent;
-moz-margin-end: 8px;
background-repeat: no-repeat;
background-position: center;
background-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon);
background-size: 26px 26px;
}
#newtab-search-logo[type="logo"] {
background-size: 65px 26px;
width: 77px; /* 65 image width + 6 left "padding" + 6 right "padding" */
}
#newtab-search-logo[type="favicon"] {
background-size: 16px 16px;
}
#newtab-search-logo[hidden] {

View File

@ -160,6 +160,14 @@ let gSearch = {
}
},
// Converts favicon array buffer into data URI of the right size and dpi.
_getFaviconURIFromBuffer: function (buffer) {
let blob = new Blob([buffer]);
let dpiSize = Math.round(16 * window.devicePixelRatio);
let sizeStr = dpiSize + "," + dpiSize;
return URL.createObjectURL(blob) + "#-moz-resolution=" + sizeStr;
},
_makePanelEngine: function (panel, engine) {
let box = document.createElementNS(XUL_NAMESPACE, "hbox");
box.className = "newtab-search-panel-engine";
@ -173,10 +181,7 @@ let gSearch = {
let image = document.createElementNS(XUL_NAMESPACE, "image");
if (engine.iconBuffer) {
let blob = new Blob([engine.iconBuffer]);
let size = Math.round(16 * window.devicePixelRatio);
let sizeStr = size + "," + size;
let uri = URL.createObjectURL(blob) + "#-moz-resolution=" + sizeStr;
let uri = this._getFaviconURIFromBuffer(engine.iconBuffer);
image.setAttribute("src", uri);
}
box.appendChild(image);
@ -191,17 +196,27 @@ let gSearch = {
_setCurrentEngine: function (engine) {
this.currentEngineName = engine.name;
// Set the logo.
let logoBuf = window.devicePixelRatio == 2 ? engine.logo2xBuffer :
let type = "";
let uri;
let logoBuf = window.devicePixelRatio >= 2 ?
engine.logo2xBuffer || engine.logoBuffer :
engine.logoBuffer || engine.logo2xBuffer;
if (logoBuf) {
this._nodes.logo.hidden = false;
let uri = URL.createObjectURL(new Blob([logoBuf]));
uri = URL.createObjectURL(new Blob([logoBuf]));
type = "logo";
}
else if (engine.iconBuffer) {
uri = this._getFaviconURIFromBuffer(engine.iconBuffer);
type = "favicon";
}
this._nodes.logo.setAttribute("type", type);
if (uri) {
this._nodes.logo.style.backgroundImage = "url(" + uri + ")";
this._nodes.text.placeholder = "";
}
else {
this._nodes.logo.hidden = true;
this._nodes.logo.style.backgroundImage = "";
this._nodes.text.placeholder = engine.name;
}

View File

@ -65,6 +65,7 @@ support-files =
offlineQuotaNotification.html
page_style_sample.html
parsingTestHelpers.jsm
popup_blocker.html
print_postdata.sjs
redirect_bug623155.sjs
searchSuggestionEngine.sjs
@ -109,6 +110,8 @@ skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliabil
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux
[browser_addKeywordSearch.js]
skip-if = e10s
[browser_search_favicon.js]
skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliability on Linux
[browser_alltabslistener.js]
skip-if = os == "linux" || e10s # Linux: Intermittent failures, bug 951680; e10s: Bug ?????? - notifications don't work correctly.
[browser_autocomplete_a11y_label.js]
@ -369,6 +372,7 @@ skip-if = asan # Disabled because it takes a long time (see test for more inform
skip-if = e10s # Bug ?????? - test directly manipulates content (creates and fetches elements directly from content document)
[browser_popupUI.js]
skip-if = buildapp == 'mulet' || e10s # Bug ?????? - test directly manipulates content (tries to get a popup element directly from content)
[browser_popup_blocker.js]
[browser_printpreview.js]
skip-if = buildapp == 'mulet' || e10s # Bug ?????? - timeout after logging "Error: Channel closing: too late to send/recv, messages will be lost"
[browser_private_browsing_window.js]

View File

@ -0,0 +1,64 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const baseURL = "http://example.com/browser/browser/base/content/test/general/";
function test() {
waitForExplicitFinish();
Task.spawn(function* () {
// Enable the popup blocker.
yield pushPrefs(["dom.disable_open_during_load", true]);
// Open the test page.
let tab = gBrowser.loadOneTab(baseURL + "popup_blocker.html", { inBackground: false });
yield promiseTabLoaded(tab);
// Wait for the popup-blocked notification.
let notification;
yield promiseWaitForCondition(() =>
notification = gBrowser.getNotificationBox().getNotificationWithValue("popup-blocked"));
// Show the menu.
let popupShown = promiseWaitForEvent(window, "popupshown");
notification.querySelector("button").doCommand();
let popup_event = yield popupShown;
let menu = popup_event.target;
is(menu.id, "blockedPopupOptions", "Blocked popup menu shown");
// Check the menu contents.
let sep = menu.querySelector("menuseparator");
let popupCount = 0;
for (let i = sep.nextElementSibling; i; i = i.nextElementSibling) {
popupCount++;
}
is(popupCount, 2, "Two popups were blocked");
// Pressing "allow" should open all blocked popups.
let popupTabs = [];
function onTabOpen(event) {
popupTabs.push(event.target);
}
gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen);
// Press the button.
let allow = menu.querySelector("[observes='blockedPopupAllowSite']");
allow.doCommand();
yield promiseWaitForCondition(() =>
popupTabs.length == 2 &&
popupTabs.every(tab => tab.linkedBrowser.currentURI.spec != "about:blank"));
gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen);
is(popupTabs[0].linkedBrowser.currentURI.spec, "data:text/plain;charset=utf-8,a", "Popup a");
is(popupTabs[1].linkedBrowser.currentURI.spec, "data:text/plain;charset=utf-8,b", "Popup b");
// Clean up.
gBrowser.removeTab(tab);
for (let popup of popupTabs) {
gBrowser.removeTab(popup);
}
clearAllPermissionsByPrefix("popup");
finish();
});
}

View File

@ -0,0 +1,121 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
let gOriginalEngine;
let gEngine;
let gUnifiedCompletePref = "browser.urlbar.unifiedcomplete";
/**
* Asynchronously adds visits to a page.
*
* @param aPlaceInfo
* Can be an nsIURI, in such a case a single LINK visit will be added.
* Otherwise can be an object describing the visit to add, or an array
* of these objects:
* { uri: nsIURI of the page,
* transition: one of the TRANSITION_* from nsINavHistoryService,
* [optional] title: title of the page,
* [optional] visitDate: visit date in microseconds from the epoch
* [optional] referrer: nsIURI of the referrer for this visit
* }
*
* @return {Promise}
* @resolves When all visits have been added successfully.
* @rejects JavaScript exception.
*/
function promiseAddVisits(aPlaceInfo) {
return new Promise((resolve, reject) => {
let places = [];
if (aPlaceInfo instanceof Ci.nsIURI) {
places.push({ uri: aPlaceInfo });
}
else if (Array.isArray(aPlaceInfo)) {
places = places.concat(aPlaceInfo);
} else {
places.push(aPlaceInfo)
}
// Create mozIVisitInfo for each entry.
let now = Date.now();
for (let i = 0, len = places.length; i < len; ++i) {
if (!places[i].title) {
places[i].title = "test visit for " + places[i].uri.spec;
}
places[i].visits = [{
transitionType: places[i].transition === undefined ? Ci.nsINavHistoryService.TRANSITION_LINK
: places[i].transition,
visitDate: places[i].visitDate || (now++) * 1000,
referrerURI: places[i].referrer
}];
}
PlacesUtils.asyncHistory.updatePlaces(
places,
{
handleError: function AAV_handleError(aResultCode, aPlaceInfo) {
let ex = new Components.Exception("Unexpected error in adding visits.",
aResultCode);
reject(ex);
},
handleResult: function () {},
handleCompletion: function UP_handleCompletion() {
resolve();
}
}
);
});
}
function* promiseAutocompleteResultPopup(inputText) {
gURLBar.focus();
gURLBar.value = inputText.slice(0, -1);
EventUtils.synthesizeKey(inputText.slice(-1) , {});
yield promiseSearchComplete();
return gURLBar.popup.richlistbox.children;
}
registerCleanupFunction(() => {
Services.prefs.clearUserPref(gUnifiedCompletePref);
Services.search.currentEngine = gOriginalEngine;
Services.search.removeEngine(gEngine);
return promiseClearHistory();
});
add_task(function*() {
Services.prefs.setBoolPref(gUnifiedCompletePref, true);
});
add_task(function*() {
Services.search.addEngineWithDetails("SearchEngine", "", "", "",
"GET", "http://s.example.com/search");
gEngine = Services.search.getEngineByName("SearchEngine");
gEngine.addParam("q", "{searchTerms}", null);
gOriginalEngine = Services.search.currentEngine;
Services.search.currentEngine = gEngine;
let uri = NetUtil.newURI("http://s.example.com/search?q=foo&client=1");
yield promiseAddVisits({ uri: uri, title: "Foo - SearchEngine Search" });
// The first autocomplete result has the action searchengine, while
// the second result is the "search favicon" element.
let result = yield promiseAutocompleteResultPopup("foo");
result = result[1];
isnot(result, null, "Expect a search result");
is(result.getAttribute("type"), "search favicon", "Expect correct `type` attribute");
is_element_visible(result._title, "Title element should be visible");
is_element_visible(result._extraBox, "Extra box element should be visible");
is(result._extraBox.pack, "start", "Extra box element should start after the title");
let iconElem = result._extraBox.nextSibling;
is_element_visible(iconElem,
"The element containing the magnifying glass icon should be visible");
ok(iconElem.classList.contains("ac-result-type-keyword"),
"That icon should have the same class use for `keyword` results");
is_element_visible(result._url, "URL element should be visible");
is(result._url.textContent, "Search with SearchEngine");
});

View File

@ -150,15 +150,25 @@ function setTestPluginEnabledState(newEnabledState, pluginName) {
// after a test is done using the plugin doorhanger, we should just clear
// any permissions that may have crept in
function clearAllPluginPermissions() {
clearAllPermissionsByPrefix("plugin");
}
function clearAllPermissionsByPrefix(aPrefix) {
let perms = Services.perms.enumerator;
while (perms.hasMoreElements()) {
let perm = perms.getNext();
if (perm.type.startsWith('plugin')) {
if (perm.type.startsWith(aPrefix)) {
Services.perms.remove(perm.host, perm.type);
}
}
}
function pushPrefs(...aPrefs) {
let deferred = Promise.defer();
SpecialPowers.pushPrefEnv({"set": aPrefs}, deferred.resolve);
return deferred.promise;
}
function updateBlocklist(aCallback) {
var blocklistNotifier = Cc["@mozilla.org/extensions/blocklist;1"]
.getService(Ci.nsITimerCallback);

View File

@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Page creating two popups</title>
</head>
<body>
<script type="text/javascript">
window.open("data:text/plain;charset=utf-8,a", "a");
window.open("data:text/plain;charset=utf-8,b", "b");
</script>
</body>
</html>

View File

@ -35,6 +35,7 @@ support-files =
[browser_newtab_search.js]
support-files =
searchEngineNoLogo.xml
searchEngineFavicon.xml
searchEngine1xLogo.xml
searchEngine2xLogo.xml
searchEngine1x2xLogo.xml

View File

@ -4,11 +4,45 @@
// See browser/components/search/test/browser_*_behavior.js for tests of actual
// searches.
const ENGINE_NO_LOGO = "searchEngineNoLogo.xml";
const ENGINE_1X_LOGO = "searchEngine1xLogo.xml";
const ENGINE_2X_LOGO = "searchEngine2xLogo.xml";
const ENGINE_1X_2X_LOGO = "searchEngine1x2xLogo.xml";
const ENGINE_SUGGESTIONS = "searchSuggestionEngine.xml";
Cu.import("resource://gre/modules/Task.jsm");
const ENGINE_NO_LOGO = {
name: "searchEngineNoLogo.xml",
numLogos: 0,
};
const ENGINE_FAVICON = {
name: "searchEngineFavicon.xml",
logoPrefix1x: "data:image/png;base64,AAABAAIAICAAAAEAIACoEAAAJgAAABAQAAABACAAaAQAAM4QAAAoAAAAIAAAAEAAAAABACAAAAAAAAAQAAATCwAAEwsA",
numLogos: 1,
};
ENGINE_FAVICON.logoPrefix2x = ENGINE_FAVICON.logoPrefix1x;
const ENGINE_1X_LOGO = {
name: "searchEngine1xLogo.xml",
logoPrefix1x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAIAAABn3KYmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADEw",
numLogos: 1,
};
ENGINE_1X_LOGO.logoPrefix2x = ENGINE_1X_LOGO.logoPrefix1x;
const ENGINE_2X_LOGO = {
name: "searchEngine2xLogo.xml",
logoPrefix2x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAIAAADJ8nfCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADMU",
numLogos: 1,
};
ENGINE_2X_LOGO.logoPrefix1x = ENGINE_2X_LOGO.logoPrefix2x;
const ENGINE_1X_2X_LOGO = {
name: "searchEngine1x2xLogo.xml",
logoPrefix1x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEEAAAAaCAIAAABn3KYmAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADIG",
logoPrefix2x: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAA0CAIAAADJ8nfCAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gkTADMo",
numLogos: 2,
};
const ENGINE_SUGGESTIONS = {
name: "searchSuggestionEngine.xml",
numLogos: 0,
};
const SERVICE_EVENT_NAME = "ContentSearchService";
@ -28,9 +62,14 @@ var gExpectedSearchEventQueue = [];
var gNewEngines = [];
function runTests() {
runTaskifiedTests().then(TestRunner.next, TestRunner.next);
yield;
}
let runTaskifiedTests = Task.async(function* () {
let oldCurrentEngine = Services.search.currentEngine;
yield addNewTabPageTab();
yield addNewTabPageTabPromise();
// The tab is removed at the end of the test, so there's no need to remove
// this listener at the end of the test.
@ -45,66 +84,40 @@ function runTests() {
panel.setAttribute("animate", "false");
// Add the engine without any logos and switch to it.
let noLogoEngine = null;
yield promiseNewSearchEngine(ENGINE_NO_LOGO, 0).then(engine => {
noLogoEngine = engine;
TestRunner.next();
});
ok(!noLogoEngine.getIconURLBySize(...LOGO_1X_DPI_SIZE),
"Sanity check: engine should not have 1x logo");
ok(!noLogoEngine.getIconURLBySize(...LOGO_2X_DPI_SIZE),
"Sanity check: engine should not have 2x logo");
let noLogoEngine = yield promiseNewSearchEngine(ENGINE_NO_LOGO);
Services.search.currentEngine = noLogoEngine;
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
yield checkCurrentEngine(ENGINE_NO_LOGO, false, false);
yield promiseSearchEvents(["CurrentEngine"]);
yield checkCurrentEngine(ENGINE_NO_LOGO);
// Add the engine with favicon and switch to it.
let faviconEngine = yield promiseNewSearchEngine(ENGINE_FAVICON);
Services.search.currentEngine = faviconEngine;
yield promiseSearchEvents(["CurrentEngine"]);
yield checkCurrentEngine(ENGINE_FAVICON);
// Add the engine with a 1x-DPI logo and switch to it.
let logo1xEngine = null;
yield promiseNewSearchEngine(ENGINE_1X_LOGO, 1).then(engine => {
logo1xEngine = engine;
TestRunner.next();
});
ok(!!logo1xEngine.getIconURLBySize(...LOGO_1X_DPI_SIZE),
"Sanity check: engine should have 1x logo");
ok(!logo1xEngine.getIconURLBySize(...LOGO_2X_DPI_SIZE),
"Sanity check: engine should not have 2x logo");
let logo1xEngine = yield promiseNewSearchEngine(ENGINE_1X_LOGO);
Services.search.currentEngine = logo1xEngine;
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
yield checkCurrentEngine(ENGINE_1X_LOGO, true, false);
yield promiseSearchEvents(["CurrentEngine"]);
yield checkCurrentEngine(ENGINE_1X_LOGO);
// Add the engine with a 2x-DPI logo and switch to it.
let logo2xEngine = null;
yield promiseNewSearchEngine(ENGINE_2X_LOGO, 1).then(engine => {
logo2xEngine = engine;
TestRunner.next();
});
ok(!logo2xEngine.getIconURLBySize(...LOGO_1X_DPI_SIZE),
"Sanity check: engine should not have 1x logo");
ok(!!logo2xEngine.getIconURLBySize(...LOGO_2X_DPI_SIZE),
"Sanity check: engine should have 2x logo");
let logo2xEngine = yield promiseNewSearchEngine(ENGINE_2X_LOGO);
Services.search.currentEngine = logo2xEngine;
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
yield checkCurrentEngine(ENGINE_2X_LOGO, false, true);
yield promiseSearchEvents(["CurrentEngine"]);
yield checkCurrentEngine(ENGINE_2X_LOGO);
// Add the engine with 1x- and 2x-DPI logos and switch to it.
let logo1x2xEngine = null;
yield promiseNewSearchEngine(ENGINE_1X_2X_LOGO, 2).then(engine => {
logo1x2xEngine = engine;
TestRunner.next();
});
ok(!!logo1x2xEngine.getIconURLBySize(...LOGO_1X_DPI_SIZE),
"Sanity check: engine should have 1x logo");
ok(!!logo1x2xEngine.getIconURLBySize(...LOGO_2X_DPI_SIZE),
"Sanity check: engine should have 2x logo");
let logo1x2xEngine = yield promiseNewSearchEngine(ENGINE_1X_2X_LOGO);
Services.search.currentEngine = logo1x2xEngine;
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
yield checkCurrentEngine(ENGINE_1X_2X_LOGO, true, true);
yield promiseSearchEvents(["CurrentEngine"]);
yield checkCurrentEngine(ENGINE_1X_2X_LOGO);
// Click the logo to open the search panel.
yield Promise.all([
promisePanelShown(panel),
promiseClick(logoImg()),
]).then(TestRunner.next);
]);
// In the search panel, click the no-logo engine. It should become the
// current engine.
@ -119,20 +132,20 @@ function runTests() {
yield Promise.all([
promiseSearchEvents(["CurrentEngine"]),
promiseClick(noLogoBox),
]).then(TestRunner.next);
]);
yield checkCurrentEngine(ENGINE_NO_LOGO, false, false);
yield checkCurrentEngine(ENGINE_NO_LOGO);
// Switch back to the 1x-and-2x logo engine.
Services.search.currentEngine = logo1x2xEngine;
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
yield checkCurrentEngine(ENGINE_1X_2X_LOGO, true, true);
yield promiseSearchEvents(["CurrentEngine"]);
yield checkCurrentEngine(ENGINE_1X_2X_LOGO);
// Open the panel again.
yield Promise.all([
promisePanelShown(panel),
promiseClick(logoImg()),
]).then(TestRunner.next);
]);
// In the search panel, click the Manage Engines box.
let manageBox = $("manage");
@ -140,17 +153,13 @@ function runTests() {
yield Promise.all([
promiseManagerOpen(),
promiseClick(manageBox),
]).then(TestRunner.next);
]);
// Add the engine that provides search suggestions and switch to it.
let suggestionEngine = null;
yield promiseNewSearchEngine(ENGINE_SUGGESTIONS, 0).then(engine => {
suggestionEngine = engine;
TestRunner.next();
});
let suggestionEngine = yield promiseNewSearchEngine(ENGINE_SUGGESTIONS);
Services.search.currentEngine = suggestionEngine;
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
yield checkCurrentEngine(ENGINE_SUGGESTIONS, false, false);
yield promiseSearchEvents(["CurrentEngine"]);
yield checkCurrentEngine(ENGINE_SUGGESTIONS);
// Avoid intermittent failures.
gSearch()._suggestionController.remoteTimeout = 5000;
@ -165,21 +174,22 @@ function runTests() {
// Wait for the search suggestions to become visible and for the Suggestions
// message.
let suggestionsUnhiddenDefer = Promise.defer();
let table = getContentDocument().getElementById("searchSuggestionTable");
info("Waiting for suggestions table to open");
let observer = new MutationObserver(() => {
if (input.getAttribute("aria-expanded") == "true") {
observer.disconnect();
ok(!table.hidden, "Search suggestion table unhidden");
TestRunner.next();
suggestionsUnhiddenDefer.resolve();
}
});
observer.observe(input, {
attributes: true,
attributeFilter: ["aria-expanded"],
});
yield undefined;
yield suggestionsPromise.then(TestRunner.next);
yield suggestionsUnhiddenDefer.promise;
yield suggestionsPromise;
// Empty the search input, causing the suggestions to be hidden.
EventUtils.synthesizeKey("a", { accelKey: true });
@ -190,12 +200,12 @@ function runTests() {
CustomizableUI.removeWidgetFromArea("search-container");
// Focus a different element than the search input from the page.
let btn = getContentDocument().getElementById("newtab-customize-button");
yield promiseClick(btn).then(TestRunner.next);
yield promiseClick(btn);
isnot(input, getContentDocument().activeElement, "Search input should not be focused");
// Test that Ctrl/Cmd + K will focus the input field from the page.
EventUtils.synthesizeKey("k", { accelKey: true });
yield promiseSearchEvents(["FocusInput"]).then(TestRunner.next);
yield promiseSearchEvents(["FocusInput"]);
is(input, getContentDocument().activeElement, "Search input should be focused");
// Reset changes made to toolbar
CustomizableUI.reset();
@ -207,13 +217,13 @@ function runTests() {
// Test that Ctrl/Cmd + K will focus the search bar from a new about:home page if
// the newtab is disabled from `NewTabUtils.allPages.enabled`.
yield addNewTabPageTab();
yield addNewTabPageTabPromise();
// Remove the search bar from toolbar
CustomizableUI.removeWidgetFromArea("search-container");
NewTabUtils.allPages.enabled = false;
EventUtils.synthesizeKey("k", { accelKey: true });
let waitEvent = "AboutHomeLoadSnippetsCompleted";
yield promiseTabLoadEvent(gWindow.gBrowser.selectedTab, "about:home", waitEvent).then(TestRunner.next);
yield promiseTabLoadEvent(gWindow.gBrowser.selectedTab, "about:home", waitEvent);
is(getContentDocument().documentURI.toLowerCase(), "about:home", "New tab's uri should be about:home");
let searchInput = getContentDocument().getElementById("searchText");
@ -225,38 +235,29 @@ function runTests() {
// Done. Revert the current engine and remove the new engines.
Services.search.currentEngine = oldCurrentEngine;
yield promiseSearchEvents(["CurrentEngine"]).then(TestRunner.next);
yield promiseSearchEvents(["CurrentEngine"]);
let events = [];
for (let engine of gNewEngines) {
Services.search.removeEngine(engine);
events.push("CurrentState");
}
yield promiseSearchEvents(events).then(TestRunner.next);
}
yield promiseSearchEvents(events);
});
function searchEventListener(event) {
info("Got search event " + event.detail.type);
let passed = false;
let nonempty = gExpectedSearchEventQueue.length > 0;
ok(nonempty, "Expected search event queue should be nonempty");
if (nonempty) {
let { type, deferred } = gExpectedSearchEventQueue.shift();
is(event.detail.type, type, "Got expected search event " + type);
if (event.detail.type == type) {
passed = true;
// Let gSearch respond to the event before continuing.
executeSoon(() => deferred.resolve());
deferred.resolve();
} else {
deferred.reject();
}
}
if (!passed) {
info("Didn't get expected event, stopping the test");
getContentWindow().removeEventListener(SERVICE_EVENT_NAME,
searchEventListener);
// Set next() to a no-op so the test really does stop.
TestRunner.next = function () {};
TestRunner.finish();
}
}
function $(idSuffix) {
@ -270,7 +271,7 @@ function promiseSearchEvents(events) {
return Promise.all(events.map(e => e.deferred.promise));
}
function promiseNewSearchEngine(basename, numLogos) {
function promiseNewSearchEngine({name: basename, numLogos}) {
info("Waiting for engine to be added: " + basename);
// Wait for the search events triggered by adding the new engine.
@ -297,19 +298,40 @@ function promiseNewSearchEngine(basename, numLogos) {
},
});
// Make a new promise that wraps the previous promises. The only point of
// this is to pass the new engine to the yielder via deferred.resolve(),
// which is a little nicer than passing an array whose first element is the
// new engine.
let deferred = Promise.defer();
Promise.all([addDeferred.promise, eventPromise]).then(values => {
let newEngine = values[0];
deferred.resolve(newEngine);
}, () => deferred.reject());
return deferred.promise;
return Promise.all([addDeferred.promise, eventPromise]).then(([newEngine, _]) => {
return newEngine;
});
}
function checkCurrentEngine(basename, has1xLogo, has2xLogo) {
function objectURLToBlob(url) {
return new Promise(function (resolve, reject) {
let xhr = new XMLHttpRequest();
xhr.open("get", url, true);
xhr.responseType = "blob";
xhr.overrideMimeType("image/png");
xhr.onload = function(e) {
if (this.status == 200) {
return resolve(this.response);
}
reject("Failed to get logo, xhr returned status: " + this.status);
};
xhr.onerror = reject;
xhr.send();
});
}
function blobToBase64(blob) {
return new Promise(function (resolve, reject) {
var reader = new FileReader();
reader.onload = function() {
resolve(reader.result);
}
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
let checkCurrentEngine = Task.async(function* ({name: basename, logoPrefix1x, logoPrefix2x}) {
let engine = Services.search.currentEngine;
ok(engine.name.contains(basename),
"Sanity check: current engine: engine.name=" + engine.name +
@ -319,41 +341,23 @@ function checkCurrentEngine(basename, has1xLogo, has2xLogo) {
is(gSearch().currentEngineName, engine.name,
"currentEngineName: " + engine.name);
// search bar logo
let logoURI = null;
if (window.devicePixelRatio == 2) {
if (has2xLogo) {
logoURI = engine.getIconURLBySize(...LOGO_2X_DPI_SIZE);
ok(!!logoURI, "Sanity check: engine should have 2x logo");
}
}
else {
if (has1xLogo) {
logoURI = engine.getIconURLBySize(...LOGO_1X_DPI_SIZE);
ok(!!logoURI, "Sanity check: engine should have 1x logo");
}
else if (has2xLogo) {
logoURI = engine.getIconURLBySize(...LOGO_2X_DPI_SIZE);
ok(!!logoURI, "Sanity check: engine should have 2x logo");
}
}
let expectedLogoPrefix = window.devicePixelRatio >= 2 ? logoPrefix2x : logoPrefix1x;
// Check that the right logo is set.
let logo = logoImg();
is(logo.hidden, !logoURI,
"Logo should be visible iff engine has a logo: " + engine.name);
if (logoURI) {
// The URLs of blobs created with the same ArrayBuffer are different, so
// just check that the URI is a blob URI.
ok(/^url\("blob:/.test(logo.style.backgroundImage), "Logo URI"); //"
}
if (expectedLogoPrefix) {
let objectURL = logo.style.backgroundImage.match(/^url\("([^"]*)"\)$/)[1];
ok(objectURL, "ObjectURL should be there.");
if (logo.hidden) {
executeSoon(TestRunner.next);
return;
}
let blob = yield objectURLToBlob(objectURL);
let base64 = yield blobToBase64(blob);
ok(base64.startsWith(expectedLogoPrefix), "Checking image prefix.");
// "selected" attributes of engines in the panel
let panel = searchPanel();
promisePanelShown(panel).then(() => {
panel.openPopup(logo);
yield promisePanelShown(panel);
panel.hidePopup();
for (let engineBox of panel.childNodes) {
let engineName = engineBox.getAttribute("engine");
@ -368,10 +372,11 @@ function checkCurrentEngine(basename, has1xLogo, has2xLogo) {
"non-selected engine: " + engineName);
}
}
TestRunner.next();
});
panel.openPopup(logo);
}
}
else {
is(logo.style.backgroundImage, "", "backgroundImage should be empty");
}
});
function promisePanelShown(panel) {
let deferred = Promise.defer();
@ -379,7 +384,7 @@ function promisePanelShown(panel) {
panel.addEventListener("popupshown", function onEvent() {
panel.removeEventListener("popupshown", onEvent);
is(panel.state, "open", "Panel state");
executeSoon(() => deferred.resolve());
deferred.resolve();
});
return deferred.promise;
}
@ -410,10 +415,8 @@ function promiseManagerOpen() {
is(subj.opener, gWindow,
"Search engine manager opener should be the chrome browser " +
"window containing the newtab page");
executeSoon(() => {
subj.close();
deferred.resolve();
});
}
});
}

View File

@ -327,6 +327,12 @@ function restore() {
* Creates a new tab containing 'about:newtab'.
*/
function addNewTabPageTab() {
addNewTabPageTabPromise().then(TestRunner.next);
}
function addNewTabPageTabPromise() {
let deferred = Promise.defer();
let tab = gWindow.gBrowser.selectedTab = gWindow.gBrowser.addTab("about:newtab");
let browser = tab.linkedBrowser;
@ -334,20 +340,17 @@ function addNewTabPageTab() {
if (NewTabUtils.allPages.enabled) {
// Continue when the link cache has been populated.
NewTabUtils.links.populateCache(function () {
whenSearchInitDone();
deferred.resolve(whenSearchInitDone());
});
} else {
// It's important that we call next() asynchronously.
// 'yield addNewTabPageTab()' would fail if next() is called
// synchronously because the iterator is already executing.
executeSoon(TestRunner.next);
deferred.resolve();
}
}
// The new tab page might have been preloaded in the background.
if (browser.contentDocument.readyState == "complete") {
whenNewTabLoaded();
return;
return deferred.promise;
}
// Wait for the new tab page to be loaded.
@ -355,6 +358,8 @@ function addNewTabPageTab() {
browser.removeEventListener("load", onLoad, true);
whenNewTabLoaded();
}, true);
return deferred.promise;
}
/**
@ -637,15 +642,16 @@ function whenPagesUpdated(aCallback, aOnlyIfHidden=false) {
* Waits for the response to the page's initial search state request.
*/
function whenSearchInitDone() {
let deferred = Promise.defer();
if (getContentWindow().gSearch._initialStateReceived) {
executeSoon(TestRunner.next);
return;
return Promise.resolve();
}
let eventName = "ContentSearchService";
getContentWindow().addEventListener(eventName, function onEvent(event) {
if (event.detail.type == "State") {
getContentWindow().removeEventListener(eventName, onEvent);
TestRunner.next();
deferred.resolve();
}
});
return deferred.promise;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -234,6 +234,12 @@ let SessionFileInternal = {
}
}
}
// All files are corrupted if files found but none could deliver a result.
let allCorrupt = !noFilesFound && !result;
Telemetry.getHistogramById("FX_SESSION_RESTORE_ALL_FILES_CORRUPT").
add(allCorrupt);
if (!result) {
// If everything fails, start with an empty session.
result = {

View File

@ -2202,12 +2202,9 @@ let SessionStoreInternal = {
if (aWindow && (!aWindow.__SSi || !this._windows[aWindow.__SSi]))
this.onLoad(aWindow);
let root;
try {
var root = typeof aState == "string" ? JSON.parse(aState) : aState;
if (!root.windows[0]) {
this._sendRestoreCompletedNotifications();
return; // nothing to restore
}
root = (typeof aState == "string") ? JSON.parse(aState) : aState;
}
catch (ex) { // invalid state object - don't restore anything
debug(ex);
@ -2215,15 +2212,23 @@ let SessionStoreInternal = {
return;
}
// Restore closed windows if any.
if (root._closedWindows) {
this._closedWindows = root._closedWindows;
}
// We're done here if there are no windows.
if (!root.windows || !root.windows.length) {
this._sendRestoreCompletedNotifications();
return;
}
TelemetryStopwatch.start("FX_SESSION_RESTORE_RESTORE_WINDOW_MS");
// We're not returning from this before we end up calling restoreTabs
// for this window, so make sure we send the SSWindowStateBusy event.
this._setWindowStateBusy(aWindow);
if (root._closedWindows)
this._closedWindows = root._closedWindows;
var winData;
if (!root.selectedWindow || root.selectedWindow > root.windows.length) {
root.selectedWindow = 0;

View File

@ -0,0 +1,114 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/*
* The primary purpose of this test is to ensure that
* the sessionstore component records information about
* corrupted backup files into a histogram.
*/
"use strict";
Cu.import("resource://gre/modules/osfile.jsm", this);
const Telemetry = Services.telemetry;
const Path = OS.Path;
const HistogramId = "FX_SESSION_RESTORE_ALL_FILES_CORRUPT";
// Prepare the session file.
let profd = do_get_profile();
Cu.import("resource:///modules/sessionstore/SessionFile.jsm", this);
/**
* A utility function for resetting the histogram and the contents
* of the backup directory.
*/
function reset_session(backups = {}) {
// Reset the histogram.
Telemetry.getHistogramById(HistogramId).clear();
// Reset the contents of the backups directory
OS.File.makeDir(SessionFile.Paths.backups);
for (let key of SessionFile.Paths.loadOrder) {
if (backups.hasOwnProperty(key)) {
OS.File.copy(backups[key], SessionFile.Paths[key]);
} else {
OS.File.remove(SessionFile.Paths[key]);
}
}
}
/**
* In order to use FX_SESSION_RESTORE_ALL_FILES_CORRUPT histogram
* it has to be registered in "toolkit/components/telemetry/Histograms.json".
* This test ensures that the histogram is registered and empty.
*/
add_task(function* test_ensure_histogram_exists_and_empty() {
let s = Telemetry.getHistogramById(HistogramId).snapshot();
Assert.equal(s.sum, 0, "Initially, the sum of probes is 0");
});
/**
* Makes sure that the histogram is negatively updated when no
* backup files are present.
*/
add_task(function* test_no_files_exist() {
// No session files are available to SessionFile.
reset_session();
yield SessionFile.read();
// Checking if the histogram is updated negatively
let h = Telemetry.getHistogramById(HistogramId);
let s = h.snapshot();
Assert.equal(s.counts[0], 1, "One probe for the 'false' bucket.");
Assert.equal(s.counts[1], 0, "No probes in the 'true' bucket.");
});
/**
* Makes sure that the histogram is negatively updated when at least one
* backup file is not corrupted.
*/
add_task(function* test_one_file_valid() {
// Corrupting some backup files.
let invalidSession = "data/sessionstore_invalid.js";
let validSession = "data/sessionstore_valid.js";
reset_session({
clean : invalidSession,
cleanBackup: validSession,
recovery: invalidSession,
recoveryBackup: invalidSession
});
yield SessionFile.read();
// Checking if the histogram is updated negatively.
let h = Telemetry.getHistogramById(HistogramId);
let s = h.snapshot();
Assert.equal(s.counts[0], 1, "One probe for the 'false' bucket.");
Assert.equal(s.counts[1], 0, "No probes in the 'true' bucket.");
});
/**
* Makes sure that the histogram is positively updated when all
* backup files are corrupted.
*/
add_task(function* test_all_files_corrupt() {
// Corrupting all backup files.
let invalidSession = "data/sessionstore_invalid.js";
reset_session({
clean : invalidSession,
cleanBackup: invalidSession,
recovery: invalidSession,
recoveryBackup: invalidSession
});
yield SessionFile.read();
// Checking if the histogram is positively updated.
let h = Telemetry.getHistogramById(HistogramId);
let s = h.snapshot();
Assert.equal(s.counts[1], 1, "One probe for the 'true' bucket.");
Assert.equal(s.counts[0], 0, "No probes in the 'false' bucket.");
});
function run_test() {
run_next_test();
}

View File

@ -11,3 +11,4 @@ support-files =
[test_startup_nosession_async.js]
[test_startup_session_async.js]
[test_startup_invalid_session.js]
[test_histogram_corrupt_files.js]

View File

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

View File

@ -206,6 +206,7 @@
@BINPATH@/components/dom_settings.xpt
@BINPATH@/components/dom_permissionsettings.xpt
@BINPATH@/components/dom_sidebar.xpt
@BINPATH@/components/dom_cellbroadcast.xpt
@BINPATH@/components/dom_mobilemessage.xpt
@BINPATH@/components/dom_storage.xpt
@BINPATH@/components/dom_stylesheets.xpt

View File

@ -386,10 +386,12 @@ this.ContentSearch = {
_currentEngineObj: Task.async(function* () {
let engine = Services.search.currentEngine;
let favicon = engine.getIconURLBySize(16, 16);
let uri1x = engine.getIconURLBySize(65, 26);
let uri2x = engine.getIconURLBySize(130, 52);
let obj = {
name: engine.name,
iconBuffer: yield this._arrayBufferFromDataURI(favicon),
logoBuffer: yield this._arrayBufferFromDataURI(uri1x),
logo2xBuffer: yield this._arrayBufferFromDataURI(uri2x),
};

View File

@ -258,9 +258,43 @@ add_task(function* GetSuggestions_AddFormHistoryEntry_RemoveFormHistoryEntry() {
yield waitForTestMsg("CurrentState");
});
function buffersEqual(actualArrayBuffer, expectedArrayBuffer) {
let expectedView = new Int8Array(expectedArrayBuffer);
let actualView = new Int8Array(actualArrayBuffer);
for (let i = 0; i < expectedView.length; i++) {
if (actualView[i] != expectedView[i]) {
return false;
}
}
return true;
}
function arrayBufferEqual(actualArrayBuffer, expectedArrayBuffer) {
ok(actualArrayBuffer instanceof ArrayBuffer, "Actual value is ArrayBuffer.");
ok(expectedArrayBuffer instanceof ArrayBuffer, "Expected value is ArrayBuffer.");
Assert.equal(actualArrayBuffer.byteLength, expectedArrayBuffer.byteLength,
"Array buffers have the same length.");
ok(buffersEqual(actualArrayBuffer, expectedArrayBuffer), "Buffers are equal.");
}
function checkArrayBuffers(actual, expected) {
if (actual instanceof ArrayBuffer) {
arrayBufferEqual(actual, expected);
}
if (typeof actual == "object") {
for (let i in actual) {
checkArrayBuffers(actual[i], expected[i]);
}
}
}
function checkMsg(actualMsg, expectedMsgData) {
let actualMsgData = actualMsg.data;
SimpleTest.isDeeply(actualMsg.data, expectedMsgData, "Checking message");
// Engines contain ArrayBuffers which we have to compare byte by byte and
// not as Objects (like SimpleTest.isDeeply does).
checkArrayBuffers(actualMsgData, expectedMsgData);
}
function waitForMsg(name, type) {
@ -330,8 +364,7 @@ function addTab() {
return deferred.promise;
}
function currentStateObj() {
return Task.spawn(function* () {
let currentStateObj = Task.async(function* () {
let state = {
engines: [],
currentEngine: yield currentEngineObj(),
@ -344,21 +377,20 @@ function currentStateObj() {
});
}
return state;
}.bind(this));
}
});
function currentEngineObj() {
return Task.spawn(function* () {
let currentEngineObj = Task.async(function* () {
let engine = Services.search.currentEngine;
let uri1x = engine.getIconURLBySize(65, 26);
let uri2x = engine.getIconURLBySize(130, 52);
let uriFavicon = engine.getIconURLBySize(16, 16);
return {
name: engine.name,
logoBuffer: yield arrayBufferFromDataURI(uri1x),
logo2xBuffer: yield arrayBufferFromDataURI(uri2x),
iconBuffer: yield arrayBufferFromDataURI(uriFavicon),
};
}.bind(this));
}
});
function arrayBufferFromDataURI(uri) {
if (!uri) {

View File

@ -33,6 +33,7 @@
#include "mozilla/dom/PowerManager.h"
#include "mozilla/dom/WakeLock.h"
#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/CellBroadcast.h"
#include "mozilla/dom/MobileMessageManager.h"
#include "mozilla/dom/ServiceWorkerContainer.h"
#include "mozilla/dom/Telephony.h"
@ -49,7 +50,6 @@
#endif
#ifdef MOZ_B2G_RIL
#include "mozilla/dom/IccManager.h"
#include "mozilla/dom/CellBroadcast.h"
#include "mozilla/dom/MobileConnectionArray.h"
#endif
#include "nsIIdleObserver.h"
@ -173,13 +173,13 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNotification)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mBatteryManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPowerManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileMessageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTelephony)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mVoicemail)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
#ifdef MOZ_B2G_RIL
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMobileConnections)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCellBroadcast)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIccManager)
#endif
#ifdef MOZ_B2G_BT
@ -242,6 +242,10 @@ Navigator::Invalidate()
mPowerManager = nullptr;
}
if (mCellBroadcast) {
mCellBroadcast = nullptr;
}
if (mMobileMessageManager) {
mMobileMessageManager->Shutdown();
mMobileMessageManager = nullptr;
@ -266,10 +270,6 @@ Navigator::Invalidate()
mMobileConnections = nullptr;
}
if (mCellBroadcast) {
mCellBroadcast = nullptr;
}
if (mIccManager) {
mIccManager->Shutdown();
mIccManager = nullptr;
@ -1638,6 +1638,8 @@ Navigator::GetMozMobileConnections(ErrorResult& aRv)
return mMobileConnections;
}
#endif // MOZ_B2G_RIL
CellBroadcast*
Navigator::GetMozCellBroadcast(ErrorResult& aRv)
{
@ -1652,8 +1654,6 @@ Navigator::GetMozCellBroadcast(ErrorResult& aRv)
return mCellBroadcast;
}
#endif // MOZ_B2G_RIL
Voicemail*
Navigator::GetMozVoicemail(ErrorResult& aRv)
{

View File

@ -85,12 +85,12 @@ class BluetoothManager;
#endif // MOZ_B2G_BT
#ifdef MOZ_B2G_RIL
class CellBroadcast;
class IccManager;
class MobileConnectionArray;
#endif
class PowerManager;
class CellBroadcast;
class Telephony;
class Voicemail;
@ -219,6 +219,7 @@ public:
nsTArray<nsRefPtr<nsDOMDeviceStorage> >& aStores,
ErrorResult& aRv);
DesktopNotificationCenter* GetMozNotification(ErrorResult& aRv);
CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
MobileMessageManager* GetMozMobileMessage();
Telephony* GetMozTelephony(ErrorResult& aRv);
Voicemail* GetMozVoicemail(ErrorResult& aRv);
@ -234,7 +235,6 @@ public:
#endif
#ifdef MOZ_B2G_RIL
MobileConnectionArray* GetMozMobileConnections(ErrorResult& aRv);
CellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
IccManager* GetMozIccManager(ErrorResult& aRv);
#endif // MOZ_B2G_RIL
#ifdef MOZ_GAMEPAD
@ -329,13 +329,13 @@ private:
nsRefPtr<FMRadio> mFMRadio;
#endif
nsRefPtr<PowerManager> mPowerManager;
nsRefPtr<CellBroadcast> mCellBroadcast;
nsRefPtr<MobileMessageManager> mMobileMessageManager;
nsRefPtr<Telephony> mTelephony;
nsRefPtr<Voicemail> mVoicemail;
nsRefPtr<network::Connection> mConnection;
#ifdef MOZ_B2G_RIL
nsRefPtr<MobileConnectionArray> mMobileConnections;
nsRefPtr<CellBroadcast> mCellBroadcast;
nsRefPtr<IccManager> mIccManager;
#endif
#ifdef MOZ_B2G_BT

View File

@ -702,6 +702,15 @@ DOMInterfaces = {
'nativeType': 'mozilla::dom::CellBroadcast',
},
'MozCellBroadcastEtwsInfo': {
'nativeType': 'mozilla::dom::CellBroadcastEtwsInfo',
'headerFile': 'CellBroadcastMessage.h'
},
'MozCellBroadcastMessage': {
'nativeType': 'mozilla::dom::CellBroadcastMessage',
},
'MozIcc': {
'nativeType': 'mozilla::dom::Icc',
},

View File

@ -3,15 +3,21 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CellBroadcast.h"
#include "mozilla/dom/CellBroadcast.h"
#include "mozilla/dom/CellBroadcastMessage.h"
#include "mozilla/dom/MozCellBroadcastBinding.h"
#include "mozilla/dom/MozCellBroadcastEvent.h"
#include "nsIDOMMozCellBroadcastMessage.h"
#include "nsServiceManagerUtils.h"
#define NS_RILCONTENTHELPER_CONTRACTID "@mozilla.org/ril/content-helper;1"
// Service instantiation
#include "ipc/CellBroadcastIPCService.h"
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
#include "nsIGonkCellBroadcastService.h"
#endif
#include "nsXULAppAPI.h" // For XRE_GetProcessType()
using namespace mozilla::dom;
using mozilla::ErrorResult;
/**
* CellBroadcast::Listener Implementation.
@ -58,34 +64,39 @@ CellBroadcast::Create(nsPIDOMWindow* aWindow, ErrorResult& aRv)
MOZ_ASSERT(aWindow);
MOZ_ASSERT(aWindow->IsInnerWindow());
nsCOMPtr<nsICellBroadcastProvider> provider =
do_GetService(NS_RILCONTENTHELPER_CONTRACTID);
if (!provider) {
nsCOMPtr<nsICellBroadcastService> service =
do_GetService(CELLBROADCAST_SERVICE_CONTRACTID);
if (!service) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
nsRefPtr<CellBroadcast> cb = new CellBroadcast(aWindow, provider);
nsRefPtr<CellBroadcast> cb = new CellBroadcast(aWindow, service);
return cb.forget();
}
CellBroadcast::CellBroadcast(nsPIDOMWindow *aWindow,
nsICellBroadcastProvider *aProvider)
nsICellBroadcastService *aService)
: DOMEventTargetHelper(aWindow)
, mProvider(aProvider)
{
mListener = new Listener(this);
DebugOnly<nsresult> rv = mProvider->RegisterCellBroadcastMsg(mListener);
DebugOnly<nsresult> rv = aService->RegisterListener(mListener);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv),
"Failed registering Cell Broadcast callback with provider");
"Failed registering Cell Broadcast callback");
}
CellBroadcast::~CellBroadcast()
{
MOZ_ASSERT(mProvider && mListener);
MOZ_ASSERT(mListener);
mListener->Disconnect();
mProvider->UnregisterCellBroadcastMsg(mListener);
nsCOMPtr<nsICellBroadcastService> service =
do_GetService(CELLBROADCAST_SERVICE_CONTRACTID);
if (service) {
service->UnregisterListener(mListener);
}
mListener = nullptr;
}
NS_IMPL_ISUPPORTS_INHERITED0(CellBroadcast, DOMEventTargetHelper)
@ -99,14 +110,54 @@ CellBroadcast::WrapObject(JSContext* aCx)
// Forwarded nsICellBroadcastListener methods
NS_IMETHODIMP
CellBroadcast::NotifyMessageReceived(nsIDOMMozCellBroadcastMessage* aMessage)
{
CellBroadcast::NotifyMessageReceived(uint32_t aServiceId,
uint32_t aGsmGeographicalScope,
uint16_t aMessageCode,
uint16_t aMessageId,
const nsAString& aLanguage,
const nsAString& aBody,
uint32_t aMessageClass,
DOMTimeStamp aTimestamp,
uint32_t aCdmaServiceCategory,
bool aHasEtwsInfo,
uint32_t aEtwsWarningType,
bool aEtwsEmergencyUserAlert,
bool aEtwsPopup) {
MozCellBroadcastEventInit init;
init.mBubbles = true;
init.mCancelable = false;
init.mMessage = aMessage;
init.mMessage = new CellBroadcastMessage(GetOwner(),
aServiceId,
aGsmGeographicalScope,
aMessageCode,
aMessageId,
aLanguage,
aBody,
aMessageClass,
aTimestamp,
aCdmaServiceCategory,
aHasEtwsInfo,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup);
nsRefPtr<MozCellBroadcastEvent> event =
MozCellBroadcastEvent::Constructor(this, NS_LITERAL_STRING("received"), init);
return DispatchTrustedEvent(event);
}
already_AddRefed<nsICellBroadcastService>
NS_CreateCellBroadcastService()
{
nsCOMPtr<nsICellBroadcastService> service;
if (XRE_GetProcessType() == GeckoProcessType_Content) {
service = new mozilla::dom::cellbroadcast::CellBroadcastIPCService();
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
} else {
service = do_GetService(GONK_CELLBROADCAST_SERVICE_CONTRACTID);
#endif
}
return service.forget();
}

View File

@ -9,7 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/ErrorResult.h"
#include "nsICellBroadcastProvider.h"
#include "nsICellBroadcastService.h"
#include "js/TypeDecls.h"
class nsPIDOMWindow;
@ -23,7 +23,7 @@ class CellBroadcast MOZ_FINAL : public DOMEventTargetHelper,
/**
* Class CellBroadcast doesn't actually expose nsICellBroadcastListener.
* Instead, it owns an nsICellBroadcastListener derived instance mListener
* and passes it to nsICellBroadcastProvider. The onreceived events are first
* and passes it to nsICellBroadcastService. The onreceived events are first
* delivered to mListener and then forwarded to its owner, CellBroadcast. See
* also bug 775997 comment #51.
*/
@ -43,7 +43,7 @@ public:
CellBroadcast() MOZ_DELETE;
CellBroadcast(nsPIDOMWindow *aWindow,
nsICellBroadcastProvider* aProvider);
nsICellBroadcastService* aService);
nsPIDOMWindow*
GetParentObject() const { return GetOwner(); }
@ -54,7 +54,6 @@ public:
IMPL_EVENT_HANDLER(received)
private:
nsCOMPtr<nsICellBroadcastProvider> mProvider;
nsRefPtr<Listener> mListener;
};

View File

@ -0,0 +1,154 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CellBroadcastMessage.h"
#include "mozilla/dom/MozCellBroadcastMessageBinding.h"
#include "nsPIDOMWindow.h"
#include "nsICellBroadcastService.h"
namespace mozilla {
namespace dom {
/**
* Converter for XPIDL Constants to WebIDL Enumerations
*/
template<class T> struct EnumConverter {};
template<class T>
struct StaticEnumConverter
{
typedef T WebidlEnumType;
typedef uint32_t XpidlEnumType;
static MOZ_CONSTEXPR WebidlEnumType
x2w(XpidlEnumType aXpidlEnum) { return static_cast<WebidlEnumType>(aXpidlEnum); }
};
template<class T>
MOZ_CONSTEXPR T
ToWebidlEnum(uint32_t aXpidlEnum) { return EnumConverter<T>::x2w(aXpidlEnum); }
// Declare converters here:
template <>
struct EnumConverter<CellBroadcastGsmGeographicalScope> :
public StaticEnumConverter<CellBroadcastGsmGeographicalScope> {};
template <>
struct EnumConverter<CellBroadcastMessageClass> :
public StaticEnumConverter<CellBroadcastMessageClass> {};
template <>
struct EnumConverter<CellBroadcastEtwsWarningType> :
public StaticEnumConverter<CellBroadcastEtwsWarningType> {};
/**
* CellBroadcastMessage Implementation.
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CellBroadcastMessage, mWindow, mEtwsInfo)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CellBroadcastMessage)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CellBroadcastMessage)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CellBroadcastMessage)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
CellBroadcastMessage::CellBroadcastMessage(nsPIDOMWindow* aWindow,
uint32_t aServiceId,
uint32_t aGsmGeographicalScope,
uint16_t aMessageCode,
uint16_t aMessageId,
const nsAString& aLanguage,
const nsAString& aBody,
uint32_t aMessageClass,
uint64_t aTimestamp,
uint32_t aCdmaServiceCategory,
bool aHasEtwsInfo,
uint32_t aEtwsWarningType,
bool aEtwsEmergencyUserAlert,
bool aEtwsPopup)
: mWindow(aWindow)
, mServiceId(aServiceId)
, mMessageCode(aMessageCode)
, mMessageId(aMessageId)
, mLanguage(aLanguage)
, mBody(aBody)
, mTimestamp(aTimestamp)
, mEtwsInfo(aHasEtwsInfo ? new CellBroadcastEtwsInfo(aWindow,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup)
: nullptr)
{
if (aGsmGeographicalScope < nsICellBroadcastService::GSM_GEOGRAPHICAL_SCOPE_INVALID) {
mGsmGeographicalScope.SetValue(
ToWebidlEnum<CellBroadcastGsmGeographicalScope>(aGsmGeographicalScope));
}
if (aMessageClass < nsICellBroadcastService::GSM_MESSAGE_CLASS_INVALID) {
mMessageClass.SetValue(
ToWebidlEnum<CellBroadcastMessageClass>(aMessageClass));
}
// CdmaServiceCategory represents a 16bit unsigned value.
if (aCdmaServiceCategory <= 0xFFFFU) {
mCdmaServiceCategory.SetValue(static_cast<uint16_t>(aCdmaServiceCategory));
}
SetIsDOMBinding();
}
JSObject*
CellBroadcastMessage::WrapObject(JSContext* aCx)
{
return MozCellBroadcastMessageBinding::Wrap(aCx, this);
}
already_AddRefed<CellBroadcastEtwsInfo>
CellBroadcastMessage::GetEtws() const
{
nsRefPtr<CellBroadcastEtwsInfo> etwsInfo = mEtwsInfo;
return etwsInfo.forget();
}
/**
* CellBroadcastEtwsInfo Implementation.
*/
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CellBroadcastEtwsInfo, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CellBroadcastEtwsInfo)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CellBroadcastEtwsInfo)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CellBroadcastEtwsInfo)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
CellBroadcastEtwsInfo::CellBroadcastEtwsInfo(nsPIDOMWindow* aWindow,
uint32_t aWarningType,
bool aEmergencyUserAlert,
bool aPopup)
: mWindow(aWindow)
, mEmergencyUserAlert(aEmergencyUserAlert)
, mPopup(aPopup)
{
if (aWarningType < nsICellBroadcastService::GSM_ETWS_WARNING_INVALID) {
mWarningType.SetValue(
ToWebidlEnum<CellBroadcastEtwsWarningType>(aWarningType));
}
SetIsDOMBinding();
}
JSObject*
CellBroadcastEtwsInfo::WrapObject(JSContext* aCx)
{
return MozCellBroadcastEtwsInfoBinding::Wrap(aCx, this);
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,136 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_cellbroadcast_CellBroadcastMessage_h
#define mozilla_dom_cellbroadcast_CellBroadcastMessage_h
#include "mozilla/dom/MozCellBroadcastMessageBinding.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsWrapperCache.h"
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class CellBroadcastEtwsInfo;
class CellBroadcastMessage MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CellBroadcastMessage)
CellBroadcastMessage(nsPIDOMWindow* aWindow,
uint32_t aServiceId,
uint32_t aGsmGeographicalScope,
uint16_t aMessageCode,
uint16_t aMessageId,
const nsAString& aLanguage,
const nsAString& aBody,
uint32_t aMessageClass,
uint64_t aTimestamp,
uint32_t aCdmaServiceCategory,
bool aHasEtwsInfo,
uint32_t aEtwsWarningType,
bool aEtwsEmergencyUserAlert,
bool aEtwsPopup);
nsPIDOMWindow*
GetParentObject() const { return mWindow; }
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
// WebIDL interface
uint32_t ServiceId() const { return mServiceId; }
const Nullable<CellBroadcastGsmGeographicalScope>&
GetGsmGeographicalScope() { return mGsmGeographicalScope; }
uint16_t MessageCode() const { return mMessageCode; }
uint16_t MessageId() const { return mMessageId; }
void GetLanguage(nsString& aLanguage) const { aLanguage = mLanguage; }
void GetBody(nsString& aBody) const { aBody = mBody; }
const Nullable<CellBroadcastMessageClass>&
GetMessageClass() { return mMessageClass; }
uint64_t Timestamp() const { return mTimestamp; }
// Mark this as resultNotAddRefed to return raw pointers
already_AddRefed<CellBroadcastEtwsInfo> GetEtws() const;
const Nullable<uint16_t>& GetCdmaServiceCategory() { return mCdmaServiceCategory; };
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~CellBroadcastMessage() {};
// Don't try to use the default constructor.
CellBroadcastMessage();
nsCOMPtr<nsPIDOMWindow> mWindow;
uint32_t mServiceId;
Nullable<CellBroadcastGsmGeographicalScope> mGsmGeographicalScope;
uint16_t mMessageCode;
uint16_t mMessageId;
nsString mLanguage;
nsString mBody;
Nullable<CellBroadcastMessageClass> mMessageClass;
uint64_t mTimestamp;
Nullable<uint16_t> mCdmaServiceCategory;
nsRefPtr<CellBroadcastEtwsInfo> mEtwsInfo;
};
class CellBroadcastEtwsInfo MOZ_FINAL : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CellBroadcastEtwsInfo)
CellBroadcastEtwsInfo(nsPIDOMWindow* aWindow,
uint32_t aWarningType,
bool aEmergencyUserAlert,
bool aPopup);
nsPIDOMWindow*
GetParentObject() const { return mWindow; }
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
// WebIDL interface
const Nullable<CellBroadcastEtwsWarningType>&
GetWarningType() { return mWarningType; }
bool EmergencyUserAlert() const { return mEmergencyUserAlert; }
bool Popup() const { return mPopup; }
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~CellBroadcastEtwsInfo() {};
// Don't try to use the default constructor.
CellBroadcastEtwsInfo();
nsCOMPtr<nsPIDOMWindow> mWindow;
Nullable<CellBroadcastEtwsWarningType> mWarningType;
bool mEmergencyUserAlert;
bool mPopup;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_cellbroadcast_CellBroadcastMessage_h

View File

@ -0,0 +1,196 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGetter(this, "RIL", function () {
let obj = {};
Cu.import("resource://gre/modules/ril_consts.js", obj);
return obj;
});
XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger",
"@mozilla.org/system-message-internal;1",
"nsISystemMessagesInternal");
const GONK_CELLBROADCAST_SERVICE_CONTRACTID =
"@mozilla.org/cellbroadcast/gonkservice;1";
const GONK_CELLBROADCAST_SERVICE_CID =
Components.ID("{7ba407ce-21fd-11e4-a836-1bfdee377e5c}");
const CELLBROADCASTMESSAGE_CID =
Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
const CELLBROADCASTETWSINFO_CID =
Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown";
let DEBUG;
function debug(s) {
dump("CellBroadcastService: " + s);
}
function CellBroadcastService() {
this._listeners = [];
this._updateDebugFlag();
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
}
CellBroadcastService.prototype = {
classID: GONK_CELLBROADCAST_SERVICE_CID,
classInfo: XPCOMUtils.generateCI({classID: GONK_CELLBROADCAST_SERVICE_CID,
contractID: GONK_CELLBROADCAST_SERVICE_CONTRACTID,
classDescription: "CellBroadcastService",
interfaces: [Ci.nsICellBroadcastService,
Ci.nsIGonkCellBroadcastService],
flags: Ci.nsIClassInfo.SINGLETON}),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastService,
Ci.nsIGonkCellBroadcastService,
Ci.nsIObserver]),
// An array of nsICellBroadcastListener instances.
_listeners: null,
_updateDebugFlag: function() {
try {
DEBUG = RIL.DEBUG_RIL ||
Services.prefs.getBoolPref(kPrefRilDebuggingEnabled);
} catch (e) {}
},
_convertCbGsmGeographicalScope: function(aGeographicalScope) {
return (aGeographicalScope >= Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_INVALID)
? null
: RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[aGeographicalScope];
},
_convertCbMessageClass: function(aMessageClass) {
return (aMessageClass >= Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS)
? null
: RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass];
},
_convertCbEtwsWarningType: function(aWarningType) {
return (aWarningType >= Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID)
? null
: RIL.CB_ETWS_WARNING_TYPE_NAMES[aWarningType];
},
/**
* nsICellBroadcastService interface
*/
registerListener: function(aListener) {
if (this._listeners.indexOf(aListener) >= 0) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._listeners.push(aListener);
},
unregisterListener: function(aListener) {
let index = this._listeners.indexOf(aListener);
if (index < 0) {
throw Cr.NS_ERROR_UNEXPECTED;
}
this._listeners.splice(index, 1);
},
/**
* nsIGonkCellBroadcastService interface
*/
notifyMessageReceived: function(aServiceId,
aGsmGeographicalScope,
aMessageCode,
aMessageId,
aLanguage,
aBody,
aMessageClass,
aTimestamp,
aCdmaServiceCategory,
aHasEtwsInfo,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup) {
// Broadcast CBS System message
// Align the same layout to MozCellBroadcastMessage
let systemMessage = {
serviceId: aServiceId,
gsmGeographicalScope: this._convertCbGsmGeographicalScope(aGsmGeographicalScope),
messageCode: aMessageCode,
messageId: aMessageId,
language: aLanguage,
body: aBody,
messageClass: this._convertCbMessageClass(aMessageClass),
timestamp: aTimestamp,
cdmaServiceCategory: null,
etws: null
};
if (aHasEtwsInfo) {
systemMessage.etws = {
warningType: this._convertCbEtwsWarningType(aEtwsWarningType),
emergencyUserAlert: aEtwsEmergencyUserAlert,
popup: aEtwsPopup
};
}
if (aCdmaServiceCategory !=
Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID) {
systemMessage.cdmaServiceCategory = aCdmaServiceCategory;
}
if (DEBUG) {
debug("CBS system message to be broadcasted: " + JSON.stringify(systemMessage));
}
gSystemMessenger.broadcastMessage("cellbroadcast-received", systemMessage);
// Notify received message to registered listener
for (let listener of this._listeners) {
try {
listener.notifyMessageReceived(aServiceId,
aGsmGeographicalScope,
aMessageCode,
aMessageId,
aLanguage,
aBody,
aMessageClass,
aTimestamp,
aCdmaServiceCategory,
aHasEtwsInfo,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup);
} catch (e) {
debug("listener threw an exception: " + e);
}
}
},
/**
* nsIObserver interface.
*/
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case NS_XPCOM_SHUTDOWN_OBSERVER_ID:
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
// Remove all listeners.
this._listeners = [];
break;
}
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([CellBroadcastService]);

View File

@ -0,0 +1,6 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
component {7ba407ce-21fd-11e4-a836-1bfdee377e5c} CellBroadcastService.js
contract @mozilla.org/cellbroadcast/gonkservice;1 {7ba407ce-21fd-11e4-a836-1bfdee377e5c}

View File

@ -5,9 +5,12 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPIDL_SOURCES += [
'nsICellBroadcastProvider.idl',
'nsIDOMMozCellBroadcastMessage.idl',
'nsICellBroadcastService.idl',
]
XPIDL_MODULE = 'dom_cellbroadcast'
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
XPIDL_SOURCES += [
'nsIGonkCellBroadcastService.idl',
]
XPIDL_MODULE = 'dom_cellbroadcast'

View File

@ -1,35 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
interface nsIDOMMozCellBroadcastMessage;
[scriptable, uuid(4c6fb794-31bd-4ed7-b21a-34b82aa3efbe)]
interface nsICellBroadcastListener : nsISupports
{
/**
* Called when a Cell Broadcast message has been received by the network.
*
* @param message
* The received Cell Broadcast Message.
*/
void notifyMessageReceived(in nsIDOMMozCellBroadcastMessage message);
};
/**
* XPCOM component (in the content process) that provides the cell broadcast
* information.
*/
[scriptable, uuid(e6c01d18-829e-4d5a-9611-60fca36e6b46)]
interface nsICellBroadcastProvider : nsISupports
{
/**
* Called when a content process registers receiving unsolicited messages from
* RadioInterfaceLayer in the chrome process. Only a content process that has
* the 'cellbroadcast' permission is allowed to register.
*/
void registerCellBroadcastMsg(in nsICellBroadcastListener listener);
void unregisterCellBroadcastMsg(in nsICellBroadcastListener listener);
};

View File

@ -0,0 +1,96 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
#include "nsISupports.idl"
[scriptable, uuid(56f66190-44a0-11e4-aa32-636783cc014a)]
interface nsICellBroadcastListener : nsISupports
{
/**
* Called when a Cell Broadcast message has been received by the network.
*/
void notifyMessageReceived(in unsigned long aServiceId,
in unsigned long aGsmGeographicalScope,
in unsigned short aMessageCode,
in unsigned short aMessageId,
in DOMString aLanguage,
in DOMString aBody,
in unsigned long aMessageClass,
in DOMTimeStamp aTimestamp,
in unsigned long aCdmaServiceCategory,
in boolean aHasEtwsInfo,
in unsigned long aEtwsWarningType,
in boolean aEtwsEmergencyUserAlert,
in boolean aEtwsPopup);
};
%{C++
#define CELLBROADCAST_SERVICE_CID \
{ 0xc870bdca, 0x277c, 0x11e4, { 0xac, 0xa3, 0x33, 0x73, 0xa1, 0xef, 0x48, 0xf8 } }
#define CELLBROADCAST_SERVICE_CONTRACTID \
"@mozilla.org/cellbroadcast/cellbroadcastservice;1"
%}
/**
* XPCOM component that provides the cell broadcast information.
*/
[scriptable, uuid(eed283f6-44a8-11e4-b364-afb894b7a283)]
interface nsICellBroadcastService : nsISupports
{
/**
* Constant definitions of predefined GSM Geographic Scope
* See 3GPP TS 23.041 clause 9.4.1.2.1 Serial Number
*/
const unsigned short GSM_GEOGRAPHICAL_SCOPE_CELL_IMMEDIATE = 0;
const unsigned short GSM_GEOGRAPHICAL_SCOPE_PLMN = 1;
const unsigned short GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA = 2;
const unsigned short GSM_GEOGRAPHICAL_SCOPE_CELL = 3;
const unsigned short GSM_GEOGRAPHICAL_SCOPE_INVALID = 4;
/**
* Constant definitions of predefined GSM Message Class
* See 3GPP TS 23.038 clause 5 CBS Data Coding Scheme
*/
const unsigned short GSM_MESSAGE_CLASS_0 = 0;
const unsigned short GSM_MESSAGE_CLASS_1 = 1;
const unsigned short GSM_MESSAGE_CLASS_2 = 2;
const unsigned short GSM_MESSAGE_CLASS_3 = 3;
const unsigned short GSM_MESSAGE_CLASS_USER_1 = 4;
const unsigned short GSM_MESSAGE_CLASS_USER_2 = 5;
const unsigned short GSM_MESSAGE_CLASS_NORMAL = 6;
const unsigned short GSM_MESSAGE_CLASS_INVALID = 7;
/**
* Constant definitions of predefined GSM ETWS Warning Types
* see 3GPP TS 23.041 clause 9.3.24 Warning-Type
*/
const unsigned short GSM_ETWS_WARNING_EARTHQUAKE = 0;
const unsigned short GSM_ETWS_WARNING_TSUNAMI = 1;
const unsigned short GSM_ETWS_WARNING_EARTHQUAKE_TSUNAMI = 2;
const unsigned short GSM_ETWS_WARNING_TEST = 3;
const unsigned short GSM_ETWS_WARNING_OTHER = 4;
const unsigned short GSM_ETWS_WARNING_INVALID = 5;
/**
* Attribute CdmaServiceCategory is only valid in CDMA network.
* Set to CDMA_SERVICE_CATEGORY_INVALID if received from GSM/UMTS network.
*/
const unsigned long CDMA_SERVICE_CATEGORY_INVALID = 0xFFFFFFFF;
/**
* Called to register receiving cellbroadcast messages.
*
* 'cellbroadcast' permission is required for registration/unregistration.
*/
void registerListener(in nsICellBroadcastListener listener);
void unregisterListener(in nsICellBroadcastListener listener);
};
%{C++
template<typename T> struct already_AddRefed;
already_AddRefed<nsICellBroadcastService>
NS_CreateCellBroadcastService();
%}

View File

@ -0,0 +1,31 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsICellBroadcastService.idl"
%{C++
#define GONK_CELLBROADCAST_SERVICE_CONTRACTID \
"@mozilla.org/cellbroadcast/gonkservice;1"
%}
[scriptable, uuid(7cac92aa-42f8-11e4-96f3-7f490e355277)]
interface nsIGonkCellBroadcastService : nsICellBroadcastService
{
/**
* Called when a cellbroadcast message has been received by the network.
*/
void notifyMessageReceived(in unsigned long aServiceId,
in unsigned long aGsmGeographicalScope,
in unsigned short aMessageCode,
in unsigned short aMessageId,
in DOMString aLanguage,
in DOMString aBody,
in unsigned long aMessageClass,
in DOMTimeStamp aTimestamp,
in unsigned long aCdmaServiceCategory,
in boolean aHasEtwsInfo,
in unsigned long aEtwsWarningType,
in boolean aEtwsEmergencyUserAlert,
in boolean aEtwsPopup);
};

View File

@ -0,0 +1,110 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CellBroadcastIPCService.h"
#include "mozilla/dom/ContentChild.h"
namespace mozilla {
namespace dom {
namespace cellbroadcast {
NS_IMPL_ISUPPORTS(CellBroadcastIPCService, nsICellBroadcastService)
CellBroadcastIPCService::CellBroadcastIPCService()
: mActorDestroyed(false)
{
ContentChild::GetSingleton()->SendPCellBroadcastConstructor(this);
}
CellBroadcastIPCService::~CellBroadcastIPCService()
{
if (!mActorDestroyed) {
Send__delete__(this);
}
mListeners.Clear();
}
/*
* Implementation of nsICellBroadcastService.
*/
NS_IMETHODIMP
CellBroadcastIPCService::RegisterListener(nsICellBroadcastListener* aListener)
{
MOZ_ASSERT(!mListeners.Contains(aListener));
NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_UNEXPECTED);
// nsTArray doesn't fail.
mListeners.AppendElement(aListener);
return NS_OK;
}
NS_IMETHODIMP
CellBroadcastIPCService::UnregisterListener(nsICellBroadcastListener* aListener)
{
MOZ_ASSERT(mListeners.Contains(aListener));
NS_ENSURE_TRUE(!mActorDestroyed, NS_ERROR_UNEXPECTED);
// We always have the element here, so it can't fail.
mListeners.RemoveElement(aListener);
return NS_OK;
}
/*
* Implementation of PCellBroadcastChild.
*/
bool
CellBroadcastIPCService::RecvNotifyReceivedMessage(const uint32_t& aServiceId,
const uint32_t& aGsmGeographicalScope,
const uint16_t& aMessageCode,
const uint16_t& aMessageId,
const nsString& aLanguage,
const nsString& aBody,
const uint32_t& aMessageClass,
const uint64_t& aTimestamp,
const uint32_t& aCdmaServiceCategory,
const bool& aHasEtwsInfo,
const uint32_t& aEtwsWarningType,
const bool& aEtwsEmergencyUserAlert,
const bool& aEtwsPopup)
{
// UnregisterListener() could be triggered in
// nsICellBroadcastListener::NotifyMessageReceived().
// Make a immutable copy for notifying the event.
nsTArray<nsCOMPtr<nsICellBroadcastListener>> immutableListeners(mListeners);
for (uint32_t i = 0; i < immutableListeners.Length(); i++) {
immutableListeners[i]->NotifyMessageReceived(aServiceId,
aGsmGeographicalScope,
aMessageCode,
aMessageId,
aLanguage,
aBody,
aMessageClass,
aTimestamp,
aCdmaServiceCategory,
aHasEtwsInfo,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup);
}
return true;
}
void
CellBroadcastIPCService::ActorDestroy(ActorDestroyReason aWhy)
{
mActorDestroyed = true;
}
} // namespace cellbroadcast
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,58 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_cellbroadcast_CellBroadcastIPCService_h
#define mozilla_dom_cellbroadcast_CellBroadcastIPCService_h
#include "mozilla/dom/cellbroadcast/PCellBroadcastChild.h"
#include "nsICellBroadcastService.h"
#include "nsCOMPtr.h"
#include "nsTArray.h"
namespace mozilla {
namespace dom {
namespace cellbroadcast {
class CellBroadcastIPCService MOZ_FINAL : public PCellBroadcastChild
, public nsICellBroadcastService
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICELLBROADCASTSERVICE
CellBroadcastIPCService();
// PCellBroadcastChild interface
virtual bool
RecvNotifyReceivedMessage(const uint32_t& aServiceId,
const uint32_t& aGsmGeographicalScope,
const uint16_t& aMessageCode,
const uint16_t& aMessageId,
const nsString& aLanguage,
const nsString& aBody,
const uint32_t& aMessageClass,
const uint64_t& aTimestamp,
const uint32_t& aCdmaServiceCategory,
const bool& aHasEtwsInfo,
const uint32_t& aEtwsWarningType,
const bool& aEtwsEmergencyUserAlert,
const bool& aEtwsPopup) MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~CellBroadcastIPCService();
bool mActorDestroyed;
nsTArray<nsCOMPtr<nsICellBroadcastListener>> mListeners;
};
} // namespace cellbroadcast
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_cellbroadcast_CellBroadcastIPCService_h

View File

@ -0,0 +1,74 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/cellbroadcast/CellBroadcastParent.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
namespace dom {
namespace cellbroadcast {
NS_IMPL_ISUPPORTS(CellBroadcastParent, nsICellBroadcastListener)
bool
CellBroadcastParent::Init()
{
nsCOMPtr<nsICellBroadcastService> service =
do_GetService(CELLBROADCAST_SERVICE_CONTRACTID);
if (service) {
return NS_SUCCEEDED(service->RegisterListener(this));
}
return false;
}
void
CellBroadcastParent::ActorDestroy(ActorDestroyReason aWhy)
{
nsCOMPtr<nsICellBroadcastService> service =
do_GetService(CELLBROADCAST_SERVICE_CONTRACTID);
if (service) {
service->UnregisterListener(this);
}
}
/*
* nsICellBroadcastListener
*/
NS_IMETHODIMP
CellBroadcastParent::NotifyMessageReceived(uint32_t aServiceId,
uint32_t aGsmGeographicalScope,
uint16_t aMessageCode,
uint16_t aMessageId,
const nsAString& aLanguage,
const nsAString& aBody,
uint32_t aMessageClass,
DOMTimeStamp aTimestamp,
uint32_t aCdmaServiceCategory,
bool aHasEtwsInfo,
uint32_t aEtwsWarningType,
bool aEtwsEmergencyUserAlert,
bool aEtwsPopup)
{
return SendNotifyReceivedMessage(aServiceId,
aGsmGeographicalScope,
aMessageCode,
aMessageId,
nsString(aLanguage),
nsString(aBody),
aMessageClass,
aTimestamp,
aCdmaServiceCategory,
aHasEtwsInfo,
aEtwsWarningType,
aEtwsEmergencyUserAlert,
aEtwsPopup) ? NS_OK : NS_ERROR_FAILURE;
}
} // namespace cellbroadcast
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_cellbroadcast_CellBroadcastParent_h
#define mozilla_dom_cellbroadcast_CellBroadcastParent_h
#include "mozilla/dom/cellbroadcast/PCellBroadcastParent.h"
#include "nsICellBroadcastService.h"
namespace mozilla {
namespace dom {
namespace cellbroadcast {
class CellBroadcastParent MOZ_FINAL : public PCellBroadcastParent
, public nsICellBroadcastListener
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICELLBROADCASTLISTENER
bool Init();
private:
// MOZ_FINAL suppresses -Werror,-Wdelete-non-virtual-dtor
~CellBroadcastParent() {};
virtual void ActorDestroy(ActorDestroyReason aWhy);
};
} // namespace cellbroadcast
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_cellbroadcast_CellBroadcastParent_h

View File

@ -0,0 +1,41 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set sw=2 ts=8 et ft=cpp : */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PContent;
namespace mozilla {
namespace dom {
namespace cellbroadcast {
sync protocol PCellBroadcast {
manager PContent;
child:
NotifyReceivedMessage(uint32_t aServiceId,
uint32_t aGsmGeographicalScope,
uint16_t aMessageCode,
uint16_t aMessageId,
nsString aLanguage,
nsString aBody,
uint32_t aMessageClass,
uint64_t aTimestamp,
uint32_t aCdmaServiceCategory,
bool aHasEtwsInfo,
uint32_t aEtwsWarningType,
bool aEtwsEmergencyUserAlert,
bool aEtwsPopup);
parent:
/**
* Sent when the child no longer needs to use cellbroadcast.
*/
__delete__();
};
} // namespace mobilemessage
} // namespace dom
} // namespace cellbroadcast

View File

@ -8,12 +8,33 @@ DIRS += ['interfaces']
EXPORTS.mozilla.dom += [
'CellBroadcast.h',
'CellBroadcastMessage.h',
]
SOURCES += [
'CellBroadcast.cpp',
'CellBroadcastMessage.cpp',
'ipc/CellBroadcastIPCService.cpp',
'ipc/CellBroadcastParent.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_B2G_RIL']:
EXTRA_COMPONENTS += [
'gonk/CellBroadcastService.js',
'gonk/CellBroadcastService.manifest',
]
EXPORTS.mozilla.dom.cellbroadcast += [
'ipc/CellBroadcastIPCService.h',
'ipc/CellBroadcastParent.h',
]
IPDL_SOURCES += [
'ipc/PCellBroadcast.ipdl',
]
include('/ipc/chromium/chromium-config.mozbuild')
FAIL_ON_WARNINGS = True
FINAL_LIBRARY = 'xul'

View File

@ -23,7 +23,9 @@ function testReceiving_ETWS_MessageAttributes() {
ok(aMessage.etws.emergencyUserAlert != null,
"aMessage.etws.emergencyUserAlert");
ok(aMessage.etws.popup != null, "aMessage.etws.popup");
ok(aMessage.cdmaServiceCategory != null, "aMessage.cdmaServiceCategory");
// cdmaServiceCategory shall always be unavailable in GMS/UMTS CB message.
ok(aMessage.cdmaServiceCategory == null, "aMessage.cdmaServiceCategory");
};
// Here we use a simple ETWS message for test.

View File

@ -22,7 +22,9 @@ function testReceiving_GSM_MessageAttributes() {
ok(aMessage.etws.emergencyUserAlert != null, "aMessage.etws.emergencyUserAlert");
ok(aMessage.etws.popup != null, "aMessage.etws.popup");
}
ok(aMessage.cdmaServiceCategory != null, "aMessage.cdmaServiceCategory");
// cdmaServiceCategory shall always be unavailable in GMS/UMTS CB message.
ok(aMessage.cdmaServiceCategory == null, "aMessage.cdmaServiceCategory");
};
// Here we use a simple GSM message for test.
@ -296,20 +298,6 @@ function testReceiving_GSM_Multipart() {
return promise;
}
function testReceiving_GSM_ServiceCategory() {
log("Test receiving GSM Cell Broadcast - Service Category");
let verifyCBMessage = (aMessage) => {
// Bug 910091
// "Service Category" is not defined in GSM. We should always get '0' here.
is(aMessage.cdmaServiceCategory, 0, "aMessage.cdmaServiceCategory");
};
let pdu = buildHexStr(0, CB_MESSAGE_SIZE_GSM * 2);
return sendMultipleRawCbsToEmulatorAndWait([pdu])
.then((aMessage) => verifyCBMessage(aMessage));
}
function testReceiving_GSM_PaddingCharacters() {
log("Test receiving GSM Cell Broadcast - Padding Characters <CR>");
@ -369,6 +357,5 @@ startTestCommon(function testCaseMain() {
.then(() => testReceiving_GSM_EmergencyUserAlert())
.then(() => testReceiving_GSM_Popup())
.then(() => testReceiving_GSM_Multipart())
.then(() => testReceiving_GSM_ServiceCategory())
.then(() => testReceiving_GSM_PaddingCharacters());
});

View File

@ -20,7 +20,9 @@ function testReceiving_UMTS_MessageAttributes() {
ok(aMessage.etws.emergencyUserAlert != null, "aMessage.etws.emergencyUserAlert");
ok(aMessage.etws.popup != null, "aMessage.etws.popup");
}
ok(aMessage.cdmaServiceCategory != null, "aMessage.cdmaServiceCategory");
// cdmaServiceCategory shall always be unavailable in GMS/UMTS CB message.
ok(aMessage.cdmaServiceCategory == null, "aMessage.cdmaServiceCategory");
};
// Here we use a single UMTS message for test.

View File

@ -129,6 +129,7 @@
#include "ipc/Nuwa.h"
#endif
#include "mozilla/dom/cellbroadcast/CellBroadcastIPCService.h"
#include "mozilla/dom/mobileconnection/MobileConnectionChild.h"
#include "mozilla/dom/mobilemessage/SmsChild.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
@ -162,6 +163,7 @@ using namespace base;
using namespace mozilla;
using namespace mozilla::docshell;
using namespace mozilla::dom::bluetooth;
using namespace mozilla::dom::cellbroadcast;
using namespace mozilla::dom::devicestorage;
using namespace mozilla::dom::ipc;
using namespace mozilla::dom::mobileconnection;
@ -1394,6 +1396,30 @@ ContentChild::DeallocPExternalHelperAppChild(PExternalHelperAppChild* aService)
return true;
}
PCellBroadcastChild*
ContentChild::AllocPCellBroadcastChild()
{
MOZ_CRASH("No one should be allocating PCellBroadcastChild actors");
}
PCellBroadcastChild*
ContentChild::SendPCellBroadcastConstructor(PCellBroadcastChild* aActor)
{
aActor = PContentChild::SendPCellBroadcastConstructor(aActor);
if (aActor) {
static_cast<CellBroadcastIPCService*>(aActor)->AddRef();
}
return aActor;
}
bool
ContentChild::DeallocPCellBroadcastChild(PCellBroadcastChild* aActor)
{
static_cast<CellBroadcastIPCService*>(aActor)->Release();
return true;
}
PSmsChild*
ContentChild::AllocPSmsChild()
{

View File

@ -225,6 +225,10 @@ public:
PBrowserChild* aBrowser) MOZ_OVERRIDE;
virtual bool DeallocPExternalHelperAppChild(PExternalHelperAppChild *aService) MOZ_OVERRIDE;
virtual PCellBroadcastChild* AllocPCellBroadcastChild() MOZ_OVERRIDE;
PCellBroadcastChild* SendPCellBroadcastConstructor(PCellBroadcastChild* aActor);
virtual bool DeallocPCellBroadcastChild(PCellBroadcastChild* aActor) MOZ_OVERRIDE;
virtual PSmsChild* AllocPSmsChild() MOZ_OVERRIDE;
virtual bool DeallocPSmsChild(PSmsChild*) MOZ_OVERRIDE;

View File

@ -33,22 +33,23 @@
#include "mozilla/a11y/DocAccessibleParent.h"
#include "nsAccessibilityService.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/asmjscache/AsmJSCache.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/DataStoreService.h"
#include "mozilla/dom/ExternalHelperAppParent.h"
#include "mozilla/dom/PContentBridgeParent.h"
#include "mozilla/dom/PCycleCollectWithLogsParent.h"
#include "mozilla/dom/PMemoryReportRequestParent.h"
#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/DOMStorageIPC.h"
#include "mozilla/dom/bluetooth/PBluetoothParent.h"
#include "mozilla/dom/PFMRadioParent.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/ExternalHelperAppParent.h"
#include "mozilla/dom/FileSystemRequestParent.h"
#include "mozilla/dom/GeolocationBinding.h"
#include "mozilla/dom/PContentBridgeParent.h"
#include "mozilla/dom/PCycleCollectWithLogsParent.h"
#include "mozilla/dom/PFMRadioParent.h"
#include "mozilla/dom/PMemoryReportRequestParent.h"
#include "mozilla/dom/asmjscache/AsmJSCache.h"
#include "mozilla/dom/bluetooth/PBluetoothParent.h"
#include "mozilla/dom/cellbroadcast/CellBroadcastParent.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
#include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
#include "mozilla/dom/mobilemessage/SmsParent.h"
#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/quota/QuotaManager.h"
#include "mozilla/dom/telephony/TelephonyParent.h"
#include "mozilla/dom/time/DateCacheCleaner.h"
@ -192,6 +193,7 @@ static const char* sClipboardTextFlavors[] = { kUnicodeMime };
using base::ChildPrivileges;
using base::KillProcess;
using namespace mozilla::dom::bluetooth;
using namespace mozilla::dom::cellbroadcast;
using namespace mozilla::dom::devicestorage;
using namespace mozilla::dom::indexedDB;
using namespace mozilla::dom::power;
@ -3118,6 +3120,31 @@ ContentParent::DeallocPExternalHelperAppParent(PExternalHelperAppParent* aServic
return true;
}
PCellBroadcastParent*
ContentParent::AllocPCellBroadcastParent()
{
if (!AssertAppProcessPermission(this, "cellbroadcast")) {
return nullptr;
}
CellBroadcastParent* actor = new CellBroadcastParent();
actor->AddRef();
return actor;
}
bool
ContentParent::DeallocPCellBroadcastParent(PCellBroadcastParent* aActor)
{
static_cast<CellBroadcastParent*>(aActor)->Release();
return true;
}
bool
ContentParent::RecvPCellBroadcastConstructor(PCellBroadcastParent* aActor)
{
return static_cast<CellBroadcastParent*>(aActor)->Init();
}
PSmsParent*
ContentParent::AllocPSmsParent()
{

View File

@ -476,6 +476,10 @@ private:
PBrowserParent* aBrowser) MOZ_OVERRIDE;
virtual bool DeallocPExternalHelperAppParent(PExternalHelperAppParent* aService) MOZ_OVERRIDE;
virtual PCellBroadcastParent* AllocPCellBroadcastParent() MOZ_OVERRIDE;
virtual bool DeallocPCellBroadcastParent(PCellBroadcastParent*) MOZ_OVERRIDE;
virtual bool RecvPCellBroadcastConstructor(PCellBroadcastParent* aActor) MOZ_OVERRIDE;
virtual PSmsParent* AllocPSmsParent() MOZ_OVERRIDE;
virtual bool DeallocPSmsParent(PSmsParent*) MOZ_OVERRIDE;

View File

@ -9,6 +9,7 @@ include protocol PBackground;
include protocol PBlob;
include protocol PBluetooth;
include protocol PBrowser;
include protocol PCellBroadcast;
include protocol PCompositor;
include protocol PContentBridge;
include protocol PCycleCollectWithLogs;
@ -41,6 +42,11 @@ include PTabContext;
include URIParams;
include ProtocolTypes;
// Workaround to prevent error if PContentChild.cpp & PContentBridgeParent.cpp
// are put into different UnifiedProtocolsXX.cpp files.
// XXX Remove this once bug 1069073 is fixed
include "mozilla/dom/PContentBridgeParent.h";
include "mozilla/dom/indexedDB/SerializationHelpers.h";
using GeoPosition from "nsGeoPositionIPCSerialiser.h";
@ -324,6 +330,7 @@ intr protocol PContent
manages PBlob;
manages PBluetooth;
manages PBrowser;
manages PCellBroadcast;
manages PCrashReporter;
manages PCycleCollectWithLogs;
manages PDocAccessible;
@ -542,6 +549,8 @@ parent:
float systemDefaultScale,
bool success);
PCellBroadcast();
PSms();
PSpeechSynthesis();

View File

@ -46,6 +46,7 @@ DIRS += [
'battery',
'browser-element',
'canvas',
'cellbroadcast',
'contacts',
'crypto',
'phonenumberutils',
@ -112,7 +113,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
if CONFIG['MOZ_B2G_RIL']:
DIRS += [
'icc',
'cellbroadcast',
'wappush',
]

View File

@ -55,7 +55,7 @@ const NFC_IPC_MSG_NAMES = [
"NFC:ConnectResponse",
"NFC:CloseResponse",
"NFC:CheckP2PRegistrationResponse",
"NFC:PeerEvent",
"NFC:DOMEvent",
"NFC:NotifySendFileStatusResponse",
"NFC:ConfigResponse"
];
@ -96,7 +96,7 @@ NfcContentHelper.prototype = {
}),
_requestMap: null,
peerEventListener: null,
eventTarget: null,
encodeNDEFRecords: function encodeNDEFRecords(records) {
let encodedRecords = [];
@ -257,8 +257,9 @@ NfcContentHelper.prototype = {
});
},
registerPeerEventListener: function registerPeerEventListener(listener) {
this.peerEventListener = listener;
registerEventTarget: function registerEventTarget(target) {
this.eventTarget = target;
cpmm.sendAsyncMessage("NFC:AddEventTarget");
},
registerTargetForPeerReady: function registerTargetForPeerReady(window, appId) {
@ -412,13 +413,13 @@ NfcContentHelper.prototype = {
this.fireRequestSuccess(atob(result.requestId), result);
}
break;
case "NFC:PeerEvent":
case "NFC:DOMEvent":
switch (result.event) {
case NFC.NFC_PEER_EVENT_READY:
this.peerEventListener.notifyPeerReady(result.sessionToken);
this.eventTarget.notifyPeerReady(result.sessionToken);
break;
case NFC.NFC_PEER_EVENT_LOST:
this.peerEventListener.notifyPeerLost(result.sessionToken);
this.eventTarget.notifyPeerLost(result.sessionToken);
break;
}
break;

View File

@ -47,6 +47,10 @@ const NFC_CONTRACTID = "@mozilla.org/nfc;1";
const NFC_CID =
Components.ID("{2ff24790-5e74-11e1-b86c-0800200c9a66}");
const NFC_IPC_ADD_EVENT_TARGET_MSG_NAMES = [
"NFC:AddEventTarget"
];
const NFC_IPC_MSG_NAMES = [
"NFC:CheckSessionToken"
];
@ -95,6 +99,8 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
peerTargets: {},
currentPeer: null,
eventTargets: [],
init: function init(nfc) {
this.nfc = nfc;
@ -113,6 +119,10 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
_registerMessageListeners: function _registerMessageListeners() {
ppmm.addMessageListener("child-process-shutdown", this);
for (let message of NFC_IPC_ADD_EVENT_TARGET_MSG_NAMES) {
ppmm.addMessageListener(message, this);
}
for (let message of NFC_IPC_MSG_NAMES) {
ppmm.addMessageListener(message, this);
}
@ -133,6 +143,10 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
_unregisterMessageListeners: function _unregisterMessageListeners() {
ppmm.removeMessageListener("child-process-shutdown", this);
for (let message of NFC_IPC_ADD_EVENT_TARGET_MSG_NAMES) {
ppmm.removeMessageListener(message, this);
}
for (let message of NFC_IPC_MSG_NAMES) {
ppmm.removeMessageListener(message, this);
}
@ -175,16 +189,28 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
});
},
notifyPeerEvent: function notifyPeerEvent(target, event, sessionToken) {
notifyDOMEvent: function notifyDOMEvent(target, options) {
if (!target) {
dump("invalid target");
return;
}
target.sendAsyncMessage("NFC:PeerEvent", {
event: event,
sessionToken: sessionToken
});
target.sendAsyncMessage("NFC:DOMEvent", options);
},
addEventTarget: function addEventTarget(target) {
if (this.eventTargets.indexOf(target) != -1) {
return;
}
this.eventTargets.push(target);
},
removeEventTarget: function removeEventTarget(target) {
let index = this.eventTargets.indexOf(target);
if (index != -1) {
delete this.eventTargets[index];
}
},
checkP2PRegistration: function checkP2PRegistration(message) {
@ -210,7 +236,8 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
// Remember the target that receives onpeerready.
this.currentPeer = target;
this.notifyPeerEvent(target, NFC.NFC_PEER_EVENT_READY, sessionToken);
this.notifyDOMEvent(target, {event: NFC.NFC_PEER_EVENT_READY,
sessionToken: sessionToken});
},
onPeerLost: function onPeerLost(sessionToken) {
@ -221,7 +248,8 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
// For peerlost, the message is delievered to the target which
// onpeerready has been called before.
this.notifyPeerEvent(this.currentPeer, NFC.NFC_PEER_EVENT_LOST, sessionToken);
this.notifyDOMEvent(this.currentPeer, {event: NFC.NFC_PEER_EVENT_LOST,
sessionToken: sessionToken});
this.currentPeer = null;
},
@ -235,10 +263,12 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
if (message.name == "child-process-shutdown") {
this.removePeerTarget(message.target);
this.nfc.removeTarget(message.target);
this.removeEventTarget(msg.target);
return null;
}
if (NFC_IPC_MSG_NAMES.indexOf(message.name) != -1) {
if (NFC_IPC_MSG_NAMES.indexOf(message.name) != -1 ||
NFC_IPC_ADD_EVENT_TARGET_MSG_NAMES.indexOf(message.name) != -1 ) {
// Do nothing.
} else if (NFC_IPC_READ_PERM_MSG_NAMES.indexOf(message.name) != -1) {
if (!message.target.assertPermission("nfc-read")) {
@ -264,6 +294,9 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
}
switch (message.name) {
case "NFC:AddEventTarget":
this.addEventTarget(message.target);
return null;
case "NFC:CheckSessionToken":
if (!SessionHelper.isValidToken(message.data.sessionToken)) {
debug("Received invalid Session Token: " + message.data.sessionToken);
@ -472,6 +505,7 @@ Nfc.prototype = {
// Update the upper layers with a session token (alias)
message.sessionToken =
SessionHelper.registerSession(message.sessionId, message.techList);
// Do not expose the actual session to the content
delete message.sessionId;

View File

@ -7,8 +7,8 @@
interface nsIVariant;
[scriptable, uuid(57fc2998-1058-4fd5-8dd9-0e303218d5fd)]
interface nsINfcPeerEventListener : nsISupports
[scriptable, uuid(e81cc1ac-6f0b-4581-a9fb-7ee47ed0158e)]
interface nsINfcDOMEventTarget : nsISupports
{
/**
* Callback function used to notify peerready.
@ -27,7 +27,7 @@ interface nsINfcPeerEventListener : nsISupports
void notifyPeerLost(in DOMString sessionToken);
};
[scriptable, uuid(9a41d969-3375-4933-814e-2da781c8f691)]
[scriptable, uuid(7eaf4c31-e1d1-422e-aa55-181f4eb156b0)]
interface nsINfcContentHelper : nsISupports
{
const long NFC_EVENT_PEER_READY = 0x01;
@ -65,11 +65,11 @@ interface nsINfcContentHelper : nsISupports
in DOMString sessionToken);
/**
* Register the peer event listener.
* Register the event target.
*
* @param listener An instance of the nsINfcPeerEventListener.
* @param target An instance of the nsINfcDOMEventTarget.
*/
void registerPeerEventListener(in nsINfcPeerEventListener listener);
void registerEventTarget(in nsINfcDOMEventTarget target);
/**
* Register the given application id with Chrome process

View File

@ -138,7 +138,7 @@ function mozNfc() {
debug("No NFC support.")
}
this._nfcContentHelper.registerPeerEventListener(this);
this._nfcContentHelper.registerEventTarget(this);
}
mozNfc.prototype = {
_nfcContentHelper: null,
@ -289,7 +289,7 @@ mozNfc.prototype = {
contractID: "@mozilla.org/navigatorNfc;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsINfcPeerEventListener]),
Ci.nsINfcDOMEventTarget]),
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([MozNFCTag, MozNFCPeer, mozNfc]);

View File

@ -47,10 +47,6 @@ const GSMICCINFO_CID =
Components.ID("{e0fa785b-ad3f-46ed-bc56-fcb0d6fe4fa8}");
const CDMAICCINFO_CID =
Components.ID("{3d1f844f-9ec5-48fb-8907-aed2e5421709}");
const CELLBROADCASTMESSAGE_CID =
Components.ID("{29474c96-3099-486f-bb4a-3c9a1da834e4}");
const CELLBROADCASTETWSINFO_CID =
Components.ID("{59f176ee-9dcd-4005-9d47-f6be0cd08e17}");
const ICCCARDLOCKERROR_CID =
Components.ID("{08a71987-408c-44ff-93fd-177c0a85c3dd}");
@ -61,7 +57,6 @@ const RIL_IPC_MSG_NAMES = [
"RIL:CardLockRetryCount",
"RIL:StkCommand",
"RIL:StkSessionEnd",
"RIL:CellBroadcastReceived",
"RIL:IccOpenChannel",
"RIL:IccCloseChannel",
"RIL:IccExchangeAPDU",
@ -168,71 +163,6 @@ CdmaIccInfo.prototype = {
prlVersion: 0
};
function CellBroadcastMessage(clientId, pdu) {
this.serviceId = clientId;
this.gsmGeographicalScope = RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[pdu.geographicalScope];
this.messageCode = pdu.messageCode;
this.messageId = pdu.messageId;
this.language = pdu.language;
this.body = pdu.fullBody;
this.messageClass = pdu.messageClass;
this.timestamp = pdu.timestamp;
if (pdu.etws != null) {
this.etws = new CellBroadcastEtwsInfo(pdu.etws);
}
this.cdmaServiceCategory = pdu.serviceCategory;
}
CellBroadcastMessage.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastMessage]),
classID: CELLBROADCASTMESSAGE_CID,
classInfo: XPCOMUtils.generateCI({
classID: CELLBROADCASTMESSAGE_CID,
classDescription: "CellBroadcastMessage",
flags: Ci.nsIClassInfo.DOM_OBJECT,
interfaces: [Ci.nsIDOMMozCellBroadcastMessage]
}),
// nsIDOMMozCellBroadcastMessage
serviceId: -1,
gsmGeographicalScope: null,
messageCode: null,
messageId: null,
language: null,
body: null,
messageClass: null,
timestamp: null,
etws: null,
cdmaServiceCategory: null
};
function CellBroadcastEtwsInfo(etwsInfo) {
if (etwsInfo.warningType != null) {
this.warningType = RIL.CB_ETWS_WARNING_TYPE_NAMES[etwsInfo.warningType];
}
this.emergencyUserAlert = etwsInfo.emergencyUserAlert;
this.popup = etwsInfo.popup;
}
CellBroadcastEtwsInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMMozCellBroadcastEtwsInfo]),
classID: CELLBROADCASTETWSINFO_CID,
classInfo: XPCOMUtils.generateCI({
classID: CELLBROADCASTETWSINFO_CID,
classDescription: "CellBroadcastEtwsInfo",
flags: Ci.nsIClassInfo.DOM_OBJECT,
interfaces: [Ci.nsIDOMMozCellBroadcastEtwsInfo]
}),
// nsIDOMMozCellBroadcastEtwsInfo
warningType: null,
emergencyUserAlert: null,
popup: null
};
function IccCardLockError() {
}
IccCardLockError.prototype = {
@ -263,7 +193,6 @@ function RILContentHelper() {
this.initDOMRequestHelper(/* aWindow */ null, RIL_IPC_MSG_NAMES);
this._windowsMap = [];
this._cellBroadcastListeners = [];
this._iccListeners = [];
Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
@ -274,15 +203,13 @@ function RILContentHelper() {
RILContentHelper.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
QueryInterface: XPCOMUtils.generateQI([Ci.nsICellBroadcastProvider,
Ci.nsIIccProvider,
QueryInterface: XPCOMUtils.generateQI([Ci.nsIIccProvider,
Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
classID: RILCONTENTHELPER_CID,
classInfo: XPCOMUtils.generateCI({classID: RILCONTENTHELPER_CID,
classDescription: "RILContentHelper",
interfaces: [Ci.nsICellBroadcastProvider,
Ci.nsIIccProvider]}),
interfaces: [Ci.nsIIccProvider]}),
updateDebugFlag: function() {
try {
@ -638,7 +565,6 @@ RILContentHelper.prototype = {
return request;
},
_cellBroadcastListeners: null,
_iccListeners: null,
registerListener: function(listenerType, clientId, listener) {
@ -674,22 +600,6 @@ RILContentHelper.prototype = {
}
},
registerCellBroadcastMsg: function(listener) {
if (DEBUG) debug("Registering for Cell Broadcast related messages");
// Instead of registering multiple listeners for Multi-SIM, we reuse
// clientId 0 to route all CBS messages to single listener and provide the
// |clientId| info by |CellBroadcastMessage.serviceId|.
this.registerListener("_cellBroadcastListeners", 0, listener);
cpmm.sendAsyncMessage("RIL:RegisterCellBroadcastMsg");
},
unregisterCellBroadcastMsg: function(listener) {
// Instead of unregistering multiple listeners for Multi-SIM, we reuse
// clientId 0 to route all CBS messages to single listener and provide the
// |clientId| info by |CellBroadcastMessage.serviceId|.
this.unregisterListener("_cellBroadcastListeners", 0, listener);
},
registerIccMsg: function(clientId, listener) {
if (DEBUG) debug("Registering for ICC related messages");
this.registerListener("_iccListeners", clientId, listener);
@ -860,16 +770,6 @@ RILContentHelper.prototype = {
case "RIL:MatchMvno":
this.handleSimpleRequest(data.requestId, data.errorMsg, data.result);
break;
case "RIL:CellBroadcastReceived": {
// All CBS messages are to routed the listener for clientId 0 and
// provide the |clientId| info by |CellBroadcastMessage.serviceId|.
let message = new CellBroadcastMessage(clientId, data);
this._deliverEvent(0, // route to clientId 0.
"_cellBroadcastListeners",
"notifyMessageReceived",
[message]);
break;
}
}
},

View File

@ -127,10 +127,6 @@ const RIL_IPC_ICCMANAGER_MSG_NAMES = [
"RIL:MatchMvno"
];
const RIL_IPC_CELLBROADCAST_MSG_NAMES = [
"RIL:RegisterCellBroadcastMsg"
];
// set to true in ril_consts.js to see debug messages
var DEBUG = RIL.DEBUG_RIL;
@ -198,6 +194,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService",
"@mozilla.org/mobileconnection/mobileconnectionservice;1",
"nsIGonkMobileConnectionService");
XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService",
"@mozilla.org/cellbroadcast/gonkservice;1",
"nsIGonkCellBroadcastService");
XPCOMUtils.defineLazyGetter(this, "WAP", function() {
let wap = {};
Cu.import("resource://gre/modules/WapPushManager.js", wap);
@ -245,9 +245,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
ppmm.addMessageListener(msgName, this);
}
for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
ppmm.addMessageListener(msgname, this);
}
},
_unregisterMessageListeners: function() {
@ -255,9 +252,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
for (let msgName of RIL_IPC_ICCMANAGER_MSG_NAMES) {
ppmm.removeMessageListener(msgName, this);
}
for (let msgname of RIL_IPC_CELLBROADCAST_MSG_NAMES) {
ppmm.removeMessageListener(msgname, this);
}
ppmm = null;
},
@ -373,14 +367,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
}
return null;
}
} else if (RIL_IPC_CELLBROADCAST_MSG_NAMES.indexOf(msg.name) != -1) {
if (!msg.target.assertPermission("cellbroadcast")) {
if (DEBUG) {
debug("Cell Broadcast message " + msg.name +
" from a content process with no 'cellbroadcast' privileges.");
}
return null;
}
} else {
if (DEBUG) debug("Ignoring unknown message type: " + msg.name);
return null;
@ -390,9 +376,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
case "RIL:RegisterIccMsg":
this._registerMessageTarget("icc", msg.target);
return null;
case "RIL:RegisterCellBroadcastMsg":
this._registerMessageTarget("cellbroadcast", msg.target);
return null;
}
let clientId = msg.json.clientId || 0;
@ -428,13 +411,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
});
},
sendCellBroadcastMessage: function(message, clientId, data) {
this._sendTargetMessage("cellbroadcast", message, {
clientId: clientId,
data: data
});
},
sendIccMessage: function(message, clientId, data) {
this._sendTargetMessage("icc", message, {
clientId: clientId,
@ -2128,10 +2104,7 @@ RadioInterface.prototype = {
this.handleSmsMultipart(message);
break;
case "cellbroadcast-received":
message.timestamp = Date.now();
this.broadcastCbsSystemMessage(message);
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
this.clientId, message);
this.handleCellbroadcastMessageReceived(message);
break;
case "nitzTime":
this.handleNitzTime(message);
@ -2661,8 +2634,7 @@ RadioInterface.prototype = {
if (DEBUG) this.debug("handleSmsReceived: " + JSON.stringify(message));
if (message.messageType == RIL.PDU_CDMA_MSG_TYPE_BROADCAST) {
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
this.clientId, message);
this.handleCellbroadcastMessageReceived(message);
return true;
}
@ -2804,48 +2776,6 @@ RadioInterface.prototype = {
},
/**
* A helper to broadcast the system message to launch registered apps
* like CMAS app and etc.
*
* @param aName
* The system message name.
* @param aMessage
* The Cellbroadcast message received from ril_worker.
*/
broadcastCbsSystemMessage: function(aMessage) {
// Create system message with the same structure of nsIDOMMozCellBroadcastMessage
// and nsIDOMMozCellBroadcastEtwsInfo.
let etws = (aMessage.etws != null)
? {
warningType: (aMessage.etws.warningType != null)
? RIL.CB_ETWS_WARNING_TYPE_NAMES[aMessage.etws.warningType]
: null,
emergencyUserAlert: aMessage.etws.emergencyUserAlert,
popup: aMessage.etws.popup
}
: null;
let systemMessage = {
serviceId: this.clientId,
gsmGeographicalScope: RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[aMessage.geographicalScope],
messageCode: aMessage.messageCode,
messageId: aMessage.messageId,
language: aMessage.language,
body: aMessage.fullBody,
messageClass: aMessage.messageClass,
timestamp: aMessage.timestamp,
etws: etws,
cdmaServiceCategory: aMessage.serviceCategory
};
if (DEBUG) {
this.debug("CBS system message to be broadcasted: " + JSON.stringify(systemMessage));
}
gSystemMessenger.broadcastMessage("cellbroadcast-received", systemMessage);
},
/**
* Set the setting value of "time.clock.automatic-update.available".
*/
@ -3013,6 +2943,50 @@ RadioInterface.prototype = {
gMessageManager.sendIccMessage("RIL:StkCommand", this.clientId, message);
},
_convertCbGsmGeographicalScope: function(aGeographicalScope) {
return (aGeographicalScope != null)
? aGeographicalScope
: Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_INVALID;
},
_convertCbMessageClass: function(aMessageClass) {
let index = RIL.GECKO_SMS_MESSAGE_CLASSES.indexOf(aMessageClass);
return (index != -1)
? index
: Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_INVALID;
},
_convertCbEtwsWarningType: function(aWarningType) {
return (aWarningType != null)
? aWarningType
: Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID;
},
handleCellbroadcastMessageReceived: function(aMessage) {
let etwsInfo = aMessage.etws;
let hasEtwsInfo = etwsInfo != null;
let serviceCategory = (aMessage.serviceCategory)
? aMessage.serviceCategory
: Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID;
gCellBroadcastService
.notifyMessageReceived(this.clientId,
this._convertCbGsmGeographicalScope(aMessage.geographicalScope),
aMessage.messageCode,
aMessage.messageId,
aMessage.language,
aMessage.fullBody,
this._convertCbMessageClass(aMessage.messageClass),
Date.now(),
serviceCategory,
hasEtwsInfo,
(hasEtwsInfo)
? this._convertCbEtwsWarningType(etwsInfo.warningType)
: Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID,
hasEtwsInfo ? etwsInfo.emergencyUserAlert : false,
hasEtwsInfo ? etwsInfo.popup : false);
},
// nsIObserver
observe: function(subject, topic, data) {

View File

@ -1571,13 +1571,13 @@ this.PDU_PID_USIM_DATA_DOWNLOAD = 0x7F;
this.PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0x00;
this.PDU_DCS_MSG_CODING_8BITS_ALPHABET = 0x04;
this.PDU_DCS_MSG_CODING_16BITS_ALPHABET = 0x08;
this.PDU_DCS_MSG_CLASS_NORMAL = 0xFF;
this.PDU_DCS_MSG_CLASS_0 = 0x00;
this.PDU_DCS_MSG_CLASS_1 = 0x01;
this.PDU_DCS_MSG_CLASS_2 = 0x02;
this.PDU_DCS_MSG_CLASS_3 = 0x03;
this.PDU_DCS_MSG_CLASS_USER_1 = 0x04;
this.PDU_DCS_MSG_CLASS_USER_2 = 0x05;
this.PDU_DCS_MSG_CLASS_NORMAL = 0x06;
this.PDU_DCS_CODING_GROUP_BITS = 0xF0;
this.PDU_DCS_MSG_CLASS_BITS = 0x03;
this.PDU_DCS_MWI_ACTIVE_BITS = 0x08;
@ -1588,14 +1588,15 @@ this.PDU_DCS_MWI_TYPE_FAX = 0x01;
this.PDU_DCS_MWI_TYPE_EMAIL = 0x02;
this.PDU_DCS_MWI_TYPE_OTHER = 0x03;
this.GECKO_SMS_MESSAGE_CLASSES = {};
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL] = "normal";
// Set as Array instead of Object for reversed-mapping with Array.indexOf().
this.GECKO_SMS_MESSAGE_CLASSES = [];
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0] = "class-0";
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1] = "class-1";
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2] = "class-2";
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3] = "class-3";
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_1] = "user-1";
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_2] = "user-2";
GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL] = "normal";
// Because service center timestamp omit the century. Yay.
this.PDU_TIMESTAMP_YEAR_OFFSET = 2000;

View File

@ -674,6 +674,10 @@ var interfaceNamesInGlobalScope =
{name: "MozCellBroadcast", b2g: true, pref: "dom.cellbroadcast.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "MozCellBroadcastEvent", b2g: true, pref: "dom.cellbroadcast.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "MozCellBroadcastEtwsInfo", b2g: true, pref: "dom.cellbroadcast.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "MozCellBroadcastMessage", b2g: true, pref: "dom.cellbroadcast.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "MozClirModeEvent", b2g: true, pref: "dom.mobileconnection.enabled"},
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -3,7 +3,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
interface MozCellBroadcastMessage;
[Constructor(DOMString type, optional MozCellBroadcastEventInit eventInitDict), Pref="dom.cellbroadcast.enabled"]
interface MozCellBroadcastEvent : Event

View File

@ -1,18 +1,18 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=40: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "domstubs.idl"
#include "nsISupports.idl"
enum CellBroadcastGsmGeographicalScope {"cell-immediate", "plmn",
"location-area", "cell"};
enum CellBroadcastMessageClass {"class-0", "class-1", "class-2",
"class-3", "user-1", "user-2", "normal"};
enum CellBroadcastEtwsWarningType {"earthquake", "tsunami",
"earthquake-tsunami", "test", "other"};
interface nsIDOMMozCellBroadcastEtwsInfo;
/**
* MozCellBroadcastMessage encapsulates Cell Broadcast short message service
* (CBS) messages.
*/
[scriptable, uuid(dc729df4-f1d8-11e3-b00d-d3332542c557)]
interface nsIDOMMozCellBroadcastMessage : nsISupports
[Pref="dom.cellbroadcast.enabled"]
interface MozCellBroadcastMessage
{
/**
* The Service Id in the device where the message is received from.
@ -25,7 +25,7 @@ interface nsIDOMMozCellBroadcastMessage : nsISupports
*
* Possible values are: "cell-immediate", "plmn", "location-area" and "cell".
*/
readonly attribute DOMString gsmGeographicalScope;
readonly attribute CellBroadcastGsmGeographicalScope? gsmGeographicalScope;
/**
* The Message Code differentiates between messages from the same source and
@ -43,18 +43,18 @@ interface nsIDOMMozCellBroadcastMessage : nsISupports
/**
* ISO-639-1 language code for this message. Null if unspecified.
*/
readonly attribute DOMString language;
readonly attribute DOMString? language;
/**
* Text message carried by the message.
*/
readonly attribute DOMString body;
readonly attribute DOMString? body;
/**
* Possible values are "normal", "class-0", "class-1", "class-2", "class-3",
* "user-1", and "user-2".
*/
readonly attribute DOMString messageClass;
readonly attribute CellBroadcastMessageClass? messageClass;
/**
* System time stamp at receival.
@ -64,26 +64,22 @@ interface nsIDOMMozCellBroadcastMessage : nsISupports
/**
* Additional ETWS-specific info.
*/
readonly attribute nsIDOMMozCellBroadcastEtwsInfo etws;
readonly attribute MozCellBroadcastEtwsInfo? etws;
/**
* Service Category.
*/
readonly attribute long cdmaServiceCategory;
readonly attribute unsigned short? cdmaServiceCategory;
};
/**
* ETWS (Earthquake and Tsunami Warning service) Primary Notification message
* specific information.
*/
[scriptable, uuid(af009d9a-f5e8-4573-a6ee-a85118465bed)]
interface nsIDOMMozCellBroadcastEtwsInfo : nsISupports
[Pref="dom.cellbroadcast.enabled"]
interface MozCellBroadcastEtwsInfo
{
/**
* Warning type. Possible values are "earthquake", "tsunami",
* "earthquake-tsunami", "test" and "other".
*/
readonly attribute ACString warningType;
readonly attribute CellBroadcastEtwsWarningType? warningType;
/**
* Emergency user alert indication. It is used to command mobile terminals to
@ -98,4 +94,3 @@ interface nsIDOMMozCellBroadcastEtwsInfo : nsISupports
*/
readonly attribute boolean popup;
};

View File

@ -265,6 +265,8 @@ WEBIDL_FILES = [
'MouseEvent.webidl',
'MouseScrollEvent.webidl',
'MozActivity.webidl',
'MozCellBroadcast.webidl',
'MozCellBroadcastMessage.webidl',
'MozMmsMessage.webidl',
'MozMobileCellInfo.webidl',
'MozMobileConnection.webidl',
@ -605,7 +607,6 @@ if CONFIG['MOZ_B2G_BT']:
if CONFIG['MOZ_B2G_RIL']:
WEBIDL_FILES += [
'IccCardLockError.webidl',
'MozCellBroadcast.webidl',
'MozIcc.webidl',
'MozIccManager.webidl',
]
@ -662,6 +663,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
'MediaStreamEvent.webidl',
'MediaStreamTrackEvent.webidl',
'MozApplicationEvent.webidl',
'MozCellBroadcastEvent.webidl',
'MozClirModeEvent.webidl',
'MozContactChangeEvent.webidl',
'MozEmergencyCbModeEvent.webidl',
@ -724,11 +726,6 @@ if CONFIG['MOZ_B2G_BT']:
'BluetoothStatusChangedEvent.webidl',
]
if CONFIG['MOZ_B2G_RIL']:
GENERATED_EVENTS_WEBIDL_FILES += [
'MozCellBroadcastEvent.webidl',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
GENERATED_EVENTS_WEBIDL_FILES += [
'MozWifiConnectionInfoEvent.webidl',

View File

@ -214,6 +214,7 @@ static void Shutdown();
#endif
#include "nsCSPService.h"
#include "nsCSPContext.h"
#include "nsICellBroadcastService.h"
#include "nsISmsService.h"
#include "nsIMmsService.h"
#include "nsIMobileConnectionService.h"
@ -318,6 +319,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsHapticFeedback)
#endif
#endif
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(ThirdPartyUtil, Init)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsICellBroadcastService,
NS_CreateCellBroadcastService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsISmsService, NS_CreateSmsService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMmsService, NS_CreateMmsService)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIMobileMessageService,
@ -764,6 +767,7 @@ NS_DEFINE_NAMED_CID(NS_DEVICE_SENSORS_CID);
NS_DEFINE_NAMED_CID(NS_HAPTICFEEDBACK_CID);
#endif
#endif
NS_DEFINE_NAMED_CID(CELLBROADCAST_SERVICE_CID);
NS_DEFINE_NAMED_CID(SMS_SERVICE_CID);
NS_DEFINE_NAMED_CID(MMS_SERVICE_CID);
NS_DEFINE_NAMED_CID(MOBILE_MESSAGE_SERVICE_CID);
@ -1057,6 +1061,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
#endif
{ &kTHIRDPARTYUTIL_CID, false, nullptr, ThirdPartyUtilConstructor },
{ &kNS_STRUCTUREDCLONECONTAINER_CID, false, nullptr, nsStructuredCloneContainerConstructor },
{ &kCELLBROADCAST_SERVICE_CID, false, nullptr, nsICellBroadcastServiceConstructor },
{ &kSMS_SERVICE_CID, false, nullptr, nsISmsServiceConstructor },
{ &kMMS_SERVICE_CID, false, nullptr, nsIMmsServiceConstructor },
{ &kMOBILE_MESSAGE_SERVICE_CID, false, nullptr, nsIMobileMessageServiceConstructor },
@ -1215,6 +1220,7 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
#endif
{ THIRDPARTYUTIL_CONTRACTID, &kTHIRDPARTYUTIL_CID },
{ NS_STRUCTUREDCLONECONTAINER_CONTRACTID, &kNS_STRUCTUREDCLONECONTAINER_CID },
{ CELLBROADCAST_SERVICE_CONTRACTID, &kCELLBROADCAST_SERVICE_CID },
{ SMS_SERVICE_CONTRACTID, &kSMS_SERVICE_CID },
{ MMS_SERVICE_CONTRACTID, &kMMS_SERVICE_CID },
{ MOBILE_MESSAGE_SERVICE_CONTRACTID, &kMOBILE_MESSAGE_SERVICE_CID },

View File

@ -12,17 +12,17 @@ b2g = true
skip = false
; webapi tests
[include:../../../../../dom/battery/test/marionette/manifest.ini]
[include:../../../../../dom/bluetooth/tests/marionette/manifest.ini]
[include:../../../../../dom/cellbroadcast/tests/marionette/manifest.ini]
[include:../../../../../dom/events/test/marionette/manifest.ini]
[include:../../../../../dom/icc/tests/marionette/manifest.ini]
[include:../../../../../dom/mobileconnection/tests/marionette/manifest.ini]
[include:../../../../../dom/mobilemessage/tests/marionette/manifest.ini]
[include:../../../../../dom/nfc/tests/marionette/manifest.ini]
[include:../../../../../dom/system/gonk/tests/marionette/manifest.ini]
[include:../../../../../dom/system/tests/marionette/manifest.ini]
[include:../../../../../dom/telephony/test/marionette/manifest.ini]
[include:../../../../../dom/tethering/tests/marionette/manifest.ini]
[include:../../../../../dom/voicemail/test/marionette/manifest.ini]
[include:../../../../../dom/battery/test/marionette/manifest.ini]
[include:../../../../../dom/mobilemessage/tests/marionette/manifest.ini]
[include:../../../../../dom/mobileconnection/tests/marionette/manifest.ini]
[include:../../../../../dom/system/gonk/tests/marionette/manifest.ini]
[include:../../../../../dom/icc/tests/marionette/manifest.ini]
[include:../../../../../dom/system/tests/marionette/manifest.ini]
[include:../../../../../dom/nfc/tests/marionette/manifest.ini]
[include:../../../../../dom/events/test/marionette/manifest.ini]
[include:../../../../../dom/wifi/test/marionette/manifest.ini]
[include:../../../../../dom/cellbroadcast/tests/marionette/manifest.ini]
[include:../../../../../dom/tethering/tests/marionette/manifest.ini]

View File

@ -3823,6 +3823,11 @@
"kind": "boolean",
"description": "Session restore: Whether the file read on startup contained parse-able JSON"
},
"FX_SESSION_RESTORE_ALL_FILES_CORRUPT": {
"expires_in_version": "default",
"kind": "boolean",
"description": "Session restore: Whether none of the backup files contained parse-able JSON"
},
"FX_SESSION_RESTORE_RESTORE_WINDOW_MS": {
"expires_in_version": "default",
"kind": "exponential",

View File

@ -1567,6 +1567,7 @@ extends="chrome://global/content/bindings/popup.xml#popup">
this._titleOverflowEllipsis.hidden = false;
let types = new Set(type.split(/\s+/));
let initialTypes = new Set(types);
// If the type includes an action, set up the item appropriately.
if (types.has("action")) {
@ -1655,7 +1656,8 @@ extends="chrome://global/content/bindings/popup.xml#popup">
type = "bookmark";
// keyword and favicon type results for search engines
// have an extra magnifying glass icon after them
} else if (type == "keyword" || type == "search favicon") {
} else if (type == "keyword" || (initialTypes.has("search") &&
initialTypes.has("favicon"))) {
// Configure the extra box for keyword display
this._extraBox.hidden = false;
this._extraBox.childNodes[0].hidden = true;
@ -1680,6 +1682,9 @@ extends="chrome://global/content/bindings/popup.xml#popup">
// Don't emphasize keyword searches in the title or url
this.setAttribute("text", "");
} else {
// Don't show any description for non keyword types.
this._setUpDescription(this._extra, "", true);
}
// If the result has the type favicon and a known search provider,
// customize it the same way as a keyword result.

View File

@ -1061,6 +1061,14 @@ let Front = Class({
this.actorID = null;
},
manage: function(front) {
if (!front.actorID) {
throw new Error("Can't manage front without an actor ID.\n" +
"Ensure server supports " + front.typeName + ".");
}
return Pool.prototype.manage.call(this, front);
},
/**
* @returns a promise that will resolve to the actorID this front
* represents.

View File

@ -488,9 +488,15 @@ PopupNotifications.prototype = {
* Hides the notification popup.
*/
_hidePanel: function PopupNotifications_hide() {
// We need to disable the closing animation when setting _ignoreDismissal
// to true, otherwise the popuphidden event will fire after we have set
// _ignoreDismissal back to false.
let transitionsEnabled = this.transitionsEnabled;
this.transitionsEnabled = false;
this._ignoreDismissal = true;
this.panel.hidePopup();
this._ignoreDismissal = false;
this.transitionsEnabled = transitionsEnabled;
},
/**

View File

@ -437,16 +437,19 @@ var gEventManager = {
contextMenu.setAttribute("addontype", addon.type);
var menuSep = document.getElementById("addonitem-menuseparator");
var countEnabledMenuCmds = 0;
var countMenuItemsBeforeSep = 0;
for (let child of contextMenu.children) {
if (child == menuSep) {
break;
}
if (child.nodeName == "menuitem" &&
gViewController.isCommandEnabled(child.command)) {
countEnabledMenuCmds++;
countMenuItemsBeforeSep++;
}
}
// with only one menu item, we hide the menu separator
menuSep.hidden = (countEnabledMenuCmds <= 1);
// Hide the separator if there are no visible menu items before it
menuSep.hidden = (countMenuItemsBeforeSep == 0);
}, false);
},

View File

@ -197,6 +197,21 @@ add_task(function* testInstalledDetails() {
el = doc.getElementById("detail-warning");
is_element_hidden(el, "Warning notification is hidden.");
el = doc.getElementsByTagName("setting")[0];
let contextMenu = doc.getElementById("addonitem-popup");
let deferred = Promise.defer();
let listener = () => {
contextMenu.removeEventListener("popupshown", listener, false);
deferred.resolve();
};
contextMenu.addEventListener("popupshown", listener, false);
el = doc.getElementsByClassName("detail-view-container")[0];
EventUtils.synthesizeMouse(el, 4, 4, { }, gManagerWindow);
EventUtils.synthesizeMouse(el, 4, 4, { type: "contextmenu", button: 2 }, gManagerWindow);
yield deferred.promise;
let menuSep = doc.getElementById("addonitem-menuseparator");
is_element_hidden(menuSep, "Menu separator is hidden.");
contextMenu.hidePopup();
});
add_task(function* testPreferencesButton() {