Merge m-c to inbound a=merge
@ -12,10 +12,10 @@
|
||||
<!--original fetch url was https://git.mozilla.org/releases-->
|
||||
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
|
||||
<!-- B2G specific things. -->
|
||||
<project name="platform_build" path="build" remote="b2g" revision="1865c6639c51f0290d5778adef146147d5d6a5f0">
|
||||
<project name="platform_build" path="build" remote="b2g" revision="53a59364ce4f14068034c8d6fe01f4f6b9f78f23">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
@ -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="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<!-- 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"/>
|
||||
@ -127,9 +127,9 @@
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/external/icu4c" path="external/icu4c" revision="2bb01561780583cc37bc667f0ea79f48a122d8a2"/>
|
||||
<!-- dolphin specific things -->
|
||||
<project name="device/sprd" path="device/sprd" revision="66f858de575b95e334f32f6c7ac9d1cd85e9f0d8"/>
|
||||
<project name="device/sprd" path="device/sprd" revision="9a1f8e59b0cbf91d99b02f836b5197a822eadf1a"/>
|
||||
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="4e58336019b5cbcfd134caf55b142236cf986618"/>
|
||||
<project name="platform/frameworks/av" path="frameworks/av" revision="cbd80d8c03fc639dd810b17c4b682c67abc06ee8"/>
|
||||
<project name="platform/frameworks/av" path="frameworks/av" revision="facca8d3e35431b66f85a4eb42bc6c5b24bd04da"/>
|
||||
<project name="platform/hardware/akm" path="hardware/akm" revision="6d3be412647b0eab0adff8a2768736cf4eb68039"/>
|
||||
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
|
||||
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
|
||||
|
@ -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="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a567a787b5ac3e0cb663aa6464b18a24ec764409"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -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="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -12,10 +12,10 @@
|
||||
<!--original fetch url was https://git.mozilla.org/releases-->
|
||||
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
|
||||
<!-- B2G specific things. -->
|
||||
<project name="platform_build" path="build" remote="b2g" revision="1865c6639c51f0290d5778adef146147d5d6a5f0">
|
||||
<project name="platform_build" path="build" remote="b2g" revision="53a59364ce4f14068034c8d6fe01f4f6b9f78f23">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
@ -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="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<!-- 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"/>
|
||||
|
@ -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="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
|
||||
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="a567a787b5ac3e0cb663aa6464b18a24ec764409"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
|
||||
<project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
|
||||
|
@ -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="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -4,6 +4,6 @@
|
||||
"remote": "",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "670b42b547f817727fc98f2983c606e8cc8766af",
|
||||
"revision": "2b76279a1d0770938d1ed660f40faba07b2a5e19",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -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="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
|
||||
|
@ -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="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
|
@ -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="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
|
||||
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
|
||||
<!-- Stock Android things -->
|
||||
|
@ -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="afcdd36f13e75adcdebe57d842a277fd587faf28"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="e424c85eda87a40c0fa64d6a779c3fa368bf770b"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="76a2d31804463dcb49e2fd852c8c2e27a89e9e46"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="d59843c1d66bd8d93c6012efda47fa447b99813c"/>
|
||||
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
|
||||
<!-- Stock Android things -->
|
||||
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
|
||||
|
@ -248,6 +248,8 @@ pref("xpinstall.whitelist.add", "addons.mozilla.org");
|
||||
pref("xpinstall.whitelist.add.180", "marketplace.firefox.com");
|
||||
|
||||
pref("lightweightThemes.update.enabled", true);
|
||||
pref("lightweightThemes.getMoreURL", "https://addons.mozilla.org/%LOCALE%/firefox/themes");
|
||||
pref("lightweightThemes.recommendedThemes", "[{\"id\":\"recommended-1\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/a-web-browser-renaissance/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.footer.jpg\",\"textcolor\":\"#000000\",\"accentcolor\":\"#f2d9b1\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/1.preview.jpg\",\"author\":\"Sean.Martell\",\"version\":\"0\"},{\"id\":\"recommended-2\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/space-fantasy/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.header.jpg\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.footer.jpg\",\"textcolor\":\"#ffffff\",\"accentcolor\":\"#d9d9d9\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/2.preview.jpg\",\"author\":\"fx5800p\",\"version\":\"1.0\"},{\"id\":\"recommended-3\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/linen-light/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.footer.png\",\"textcolor\":\"#None\",\"accentcolor\":\"#ada8a8\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/3.preview.png\",\"author\":\"DVemer\",\"version\":\"1.0\"},{\"id\":\"recommended-4\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/pastel-gradient/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.footer.png\",\"textcolor\":\"#000000\",\"accentcolor\":\"#000000\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.icon.png\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/4.preview.png\",\"author\":\"darrinhenein\",\"version\":\"1.0\"},{\"id\":\"recommended-5\",\"homepageURL\":\"https://addons.mozilla.org/firefox/addon/carbon-light/\",\"headerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.header.png\",\"footerURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.footer.png\",\"textcolor\":\"#3b3b3b\",\"accentcolor\":\"#2e2e2e\",\"iconURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.icon.jpg\",\"previewURL\":\"resource:///chrome/browser/content/browser/defaultthemes/5.preview.jpg\",\"author\":\"Jaxivo\",\"version\":\"1.0\"}]");
|
||||
|
||||
// UI tour experience.
|
||||
pref("browser.uitour.enabled", true);
|
||||
|
BIN
browser/base/content/defaultthemes/1.footer.jpg
Normal file
After Width: | Height: | Size: 148 KiB |
BIN
browser/base/content/defaultthemes/1.header.jpg
Normal file
After Width: | Height: | Size: 260 KiB |
BIN
browser/base/content/defaultthemes/1.icon.jpg
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
browser/base/content/defaultthemes/1.preview.jpg
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
browser/base/content/defaultthemes/2.footer.jpg
Normal file
After Width: | Height: | Size: 79 KiB |
BIN
browser/base/content/defaultthemes/2.header.jpg
Normal file
After Width: | Height: | Size: 170 KiB |
BIN
browser/base/content/defaultthemes/2.icon.jpg
Normal file
After Width: | Height: | Size: 509 B |
BIN
browser/base/content/defaultthemes/2.preview.jpg
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
browser/base/content/defaultthemes/3.footer.png
Normal file
After Width: | Height: | Size: 176 KiB |
BIN
browser/base/content/defaultthemes/3.header.png
Normal file
After Width: | Height: | Size: 287 KiB |
BIN
browser/base/content/defaultthemes/3.icon.png
Normal file
After Width: | Height: | Size: 896 B |
BIN
browser/base/content/defaultthemes/3.preview.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
browser/base/content/defaultthemes/4.footer.png
Normal file
After Width: | Height: | Size: 375 KiB |
BIN
browser/base/content/defaultthemes/4.header.png
Normal file
After Width: | Height: | Size: 751 KiB |
BIN
browser/base/content/defaultthemes/4.icon.png
Normal file
After Width: | Height: | Size: 731 B |
BIN
browser/base/content/defaultthemes/4.preview.png
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
browser/base/content/defaultthemes/5.footer.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
browser/base/content/defaultthemes/5.header.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
browser/base/content/defaultthemes/5.icon.jpg
Normal file
After Width: | Height: | Size: 267 B |
BIN
browser/base/content/defaultthemes/5.preview.jpg
Normal file
After Width: | Height: | Size: 2.8 KiB |
@ -168,8 +168,7 @@ let gGrid = {
|
||||
' class="newtab-control newtab-control-pin"/>' +
|
||||
'<input type="button" title="' + newTabString("block") + '"' +
|
||||
' class="newtab-control newtab-control-block"/>' +
|
||||
'<input type="button" title="' + newTabString("sponsored") + '"' +
|
||||
' class="newtab-control newtab-control-sponsored"/>';
|
||||
'<span class="newtab-sponsored">' + newTabString("sponsored.button") + '</span>';
|
||||
|
||||
this._siteFragment = document.createDocumentFragment();
|
||||
this._siteFragment.appendChild(site);
|
||||
|
@ -149,19 +149,77 @@ input[type=button] {
|
||||
}
|
||||
|
||||
/* TITLES */
|
||||
.newtab-sponsored,
|
||||
.newtab-title {
|
||||
bottom: -26px;
|
||||
font-size: 13px;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
padding-top: 14px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.newtab-title {
|
||||
font-size: 13px;
|
||||
left: 0;
|
||||
padding-top: 14px;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.newtab-sponsored {
|
||||
background-color: #f9f9f9;
|
||||
border: 1px solid #dcdcdc;
|
||||
border-radius: 2px;
|
||||
color: #9b9b9b;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
font-family: Arial;
|
||||
font-size: 10px;
|
||||
height: 17px;
|
||||
line-height: 17px;
|
||||
margin-bottom: -1px;
|
||||
padding: 0 4px;
|
||||
}
|
||||
|
||||
.newtab-sponsored:-moz-any(:hover, [active]) {
|
||||
background-color: #dcdcdc;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.newtab-sponsored:-moz-locale-dir(rtl) {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
.newtab-site:-moz-any([type=enhanced], [type=sponsored]) .newtab-sponsored {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sponsored-explain,
|
||||
.sponsored-explain a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.sponsored-explain {
|
||||
background-color: rgba(51, 51, 51, 0.95);
|
||||
border-bottom-left-radius: 6px;
|
||||
border-bottom-right-radius: 6px;
|
||||
bottom: 0px;
|
||||
line-height: 20px;
|
||||
padding: 15px 10px;
|
||||
position: absolute;
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
.sponsored-explain input {
|
||||
background-size: 20px;
|
||||
height: 20px;
|
||||
opacity: 1;
|
||||
pointer-events: none;
|
||||
position: static;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
/* CONTROLS */
|
||||
.newtab-control {
|
||||
position: absolute;
|
||||
@ -185,31 +243,16 @@ input[type=button] {
|
||||
}
|
||||
}
|
||||
|
||||
.newtab-control-sponsored:-moz-locale-dir(rtl),
|
||||
.newtab-control-pin:-moz-locale-dir(ltr),
|
||||
.newtab-control-block:-moz-locale-dir(rtl) {
|
||||
left: 4px;
|
||||
}
|
||||
|
||||
.newtab-control-sponsored:-moz-locale-dir(ltr),
|
||||
.newtab-control-block:-moz-locale-dir(ltr),
|
||||
.newtab-control-pin:-moz-locale-dir(rtl) {
|
||||
right: 4px;
|
||||
}
|
||||
|
||||
.newtab-control.newtab-control-sponsored {
|
||||
bottom: -20px;
|
||||
height: 14px;
|
||||
-moz-margin-end: -5px;
|
||||
opacity: 1;
|
||||
top: auto;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
.newtab-site:not([type=sponsored]) .newtab-control-sponsored {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* DRAG & DROP */
|
||||
|
||||
/*
|
||||
@ -224,19 +267,6 @@ input[type=button] {
|
||||
opacity: 0.01;
|
||||
}
|
||||
|
||||
/* SPONSORED PANEL */
|
||||
#sponsored-panel {
|
||||
width: 330px;
|
||||
}
|
||||
|
||||
#sponsored-panel description {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#sponsored-panel .text-link {
|
||||
margin: 12px 0 0;
|
||||
}
|
||||
|
||||
/* SEARCH */
|
||||
#newtab-search-container {
|
||||
display: -moz-box;
|
||||
|
@ -35,7 +35,13 @@ XPCOMUtils.defineLazyGetter(this, "gStringBundle", function() {
|
||||
createBundle("chrome://browser/locale/newTab.properties");
|
||||
});
|
||||
|
||||
function newTabString(name) gStringBundle.GetStringFromName('newtab.' + name);
|
||||
function newTabString(name, args) {
|
||||
let stringName = "newtab." + name;
|
||||
if (!args) {
|
||||
return gStringBundle.GetStringFromName(stringName);
|
||||
}
|
||||
return gStringBundle.formatStringFromName(stringName, args, args.length);
|
||||
}
|
||||
|
||||
function inPrivateBrowsingMode() {
|
||||
return PrivateBrowsingUtils.isWindowPrivate(window);
|
||||
@ -44,6 +50,8 @@ function inPrivateBrowsingMode() {
|
||||
const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NAMESPACE = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
|
||||
const TILES_EXPLAIN_LINK = "https://support.mozilla.org/kb/how-do-sponsored-tiles-work";
|
||||
|
||||
#include transformations.js
|
||||
#include page.js
|
||||
#include grid.js
|
||||
|
@ -20,14 +20,6 @@
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="&newtab.pageTitle;">
|
||||
|
||||
<xul:panel id="sponsored-panel" orient="vertical" type="arrow">
|
||||
<xul:description id="sponsored-panel-release-descr">&newtab.sponsored.release.message;</xul:description>
|
||||
<xul:description id="sponsored-panel-trial-descr">&newtab.sponsored.trial.message2;</xul:description>
|
||||
<xul:label class="text-link"
|
||||
href="https://support.mozilla.org/kb/how-do-sponsored-tiles-work"
|
||||
value="&newtab.panel.link.text;" />
|
||||
</xul:panel>
|
||||
|
||||
<xul:panel id="newtab-search-panel" orient="vertical" type="arrow"
|
||||
noautohide="true">
|
||||
<xul:hbox id="newtab-search-manage" class="newtab-search-panel-engine">
|
||||
|
@ -24,17 +24,6 @@ let gPage = {
|
||||
// listen from the xul window and filter then delegate
|
||||
addEventListener("click", this, false);
|
||||
|
||||
// Initialize sponsored panel
|
||||
this._sponsoredPanel = document.getElementById("sponsored-panel");
|
||||
let link = this._sponsoredPanel.querySelector(".text-link");
|
||||
link.addEventListener("click", () => this._sponsoredPanel.hidePopup());
|
||||
if (UpdateChannel.get().startsWith("release")) {
|
||||
document.getElementById("sponsored-panel-trial-descr").style.display = "none";
|
||||
}
|
||||
else {
|
||||
document.getElementById("sponsored-panel-release-descr").style.display = "none";
|
||||
}
|
||||
|
||||
// Check if the new tab feature is enabled.
|
||||
let enabled = gAllPages.enabled;
|
||||
if (enabled)
|
||||
@ -89,21 +78,6 @@ let gPage = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows sponsored panel
|
||||
*/
|
||||
showSponsoredPanel: function Page_showSponsoredPanel(aTarget) {
|
||||
if (this._sponsoredPanel.state == "closed") {
|
||||
let self = this;
|
||||
this._sponsoredPanel.addEventListener("popuphidden", function onPopupHidden(aEvent) {
|
||||
self._sponsoredPanel.removeEventListener("popuphidden", onPopupHidden, false);
|
||||
aTarget.removeAttribute("panelShown");
|
||||
});
|
||||
}
|
||||
aTarget.setAttribute("panelShown", "true");
|
||||
this._sponsoredPanel.openPopup(aTarget);
|
||||
},
|
||||
|
||||
/**
|
||||
* Internally initializes the page. This runs only when/if the feature
|
||||
* is/gets enabled.
|
||||
|
@ -120,8 +120,9 @@ Site.prototype = {
|
||||
* Renders the site's data (fills the HTML fragment).
|
||||
*/
|
||||
_render: function Site_render() {
|
||||
let enhanced = gAllPages.enhanced && DirectoryLinksProvider.getEnhancedLink(this.link);
|
||||
let url = this.url;
|
||||
let title = this.title || url;
|
||||
let title = enhanced && enhanced.title || this.title || url;
|
||||
let tooltip = (title == url ? title : title + "\n" + url);
|
||||
|
||||
let link = this._querySelector(".newtab-link");
|
||||
@ -185,7 +186,7 @@ Site.prototype = {
|
||||
this._node.addEventListener("mouseover", this, false);
|
||||
|
||||
// Specially treat the sponsored icon to prevent regular hover effects
|
||||
let sponsored = this._querySelector(".newtab-control-sponsored");
|
||||
let sponsored = this._querySelector(".newtab-sponsored");
|
||||
sponsored.addEventListener("mouseover", () => {
|
||||
this.cell.node.setAttribute("ignorehover", "true");
|
||||
});
|
||||
@ -218,6 +219,30 @@ Site.prototype = {
|
||||
.add(aIndex);
|
||||
},
|
||||
|
||||
_toggleSponsored: function() {
|
||||
let button = this._querySelector(".newtab-sponsored");
|
||||
if (button.hasAttribute("active")) {
|
||||
let explain = this._querySelector(".sponsored-explain");
|
||||
explain.parentNode.removeChild(explain);
|
||||
|
||||
button.removeAttribute("active");
|
||||
}
|
||||
else {
|
||||
let explain = document.createElementNS(HTML_NAMESPACE, "div");
|
||||
explain.className = "sponsored-explain";
|
||||
this.node.appendChild(explain);
|
||||
|
||||
let link = '<a href="' + TILES_EXPLAIN_LINK + '">' +
|
||||
newTabString("learn.link") + "</a>";
|
||||
let type = this.node.getAttribute("type");
|
||||
let icon = '<input type="button" class="newtab-control newtab-' +
|
||||
(type == "sponsored" ? "control-block" : "customize") + '"/>';
|
||||
explain.innerHTML = newTabString(type + ".explain", [icon, link]);
|
||||
|
||||
button.setAttribute("active", "true");
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles site click events.
|
||||
*/
|
||||
@ -226,6 +251,8 @@ Site.prototype = {
|
||||
let pinned = this.isPinned();
|
||||
let tileIndex = this.cell.index;
|
||||
let {button, target} = aEvent;
|
||||
|
||||
// Handle tile/thumbnail link click
|
||||
if (target.classList.contains("newtab-link") ||
|
||||
target.parentElement.classList.contains("newtab-link")) {
|
||||
// Record for primary and middle clicks
|
||||
@ -234,6 +261,10 @@ Site.prototype = {
|
||||
action = "click";
|
||||
}
|
||||
}
|
||||
// Handle sponsored explanation link click
|
||||
else if (target.parentElement.classList.contains("sponsored-explain")) {
|
||||
action = "sponsored_link";
|
||||
}
|
||||
// Only handle primary clicks for the remaining targets
|
||||
else if (button == 0) {
|
||||
aEvent.preventDefault();
|
||||
@ -241,8 +272,9 @@ Site.prototype = {
|
||||
this.block();
|
||||
action = "block";
|
||||
}
|
||||
else if (target.classList.contains("newtab-control-sponsored")) {
|
||||
gPage.showSponsoredPanel(target);
|
||||
else if (target.classList.contains("sponsored-explain") ||
|
||||
target.classList.contains("newtab-sponsored")) {
|
||||
this._toggleSponsored();
|
||||
action = "sponsored";
|
||||
}
|
||||
else if (pinned) {
|
||||
|
@ -46,29 +46,21 @@
|
||||
<getter><![CDATA[
|
||||
if (this._frame)
|
||||
return this._frame;
|
||||
let notificationFrameId = "social-mark-frame-" + this.getAttribute("origin");
|
||||
let provider = Social._getProviderFromOrigin(this.getAttribute("origin"));
|
||||
let size = provider.getPageSize("marks");
|
||||
let {width, height} = size ? size : {width: 330, height: 100};
|
||||
|
||||
this._frame = SharedFrame.createFrame(
|
||||
notificationFrameId, /* frame name */
|
||||
this.panel, /* parent */
|
||||
{
|
||||
"type": "content",
|
||||
"mozbrowser": "true",
|
||||
"class": "social-panel-frame",
|
||||
"id": notificationFrameId,
|
||||
"tooltip": "aHTMLTooltip",
|
||||
"flex": "1",
|
||||
"context": "contentAreaContextMenu",
|
||||
"origin": this.getAttribute("origin"),
|
||||
"src": "about:blank",
|
||||
"style": "width: " + width + "px; height: " + height + "px;",
|
||||
}
|
||||
);
|
||||
let iframe = this._frame = document.createElement("iframe");
|
||||
iframe.setAttribute("type", "content");
|
||||
iframe.setAttribute("class", "social-panel-frame");
|
||||
iframe.setAttribute("flex", "1");
|
||||
iframe.setAttribute("tooltip", "aHTMLTooltip");
|
||||
iframe.setAttribute("context", "contentAreaContextMenu");
|
||||
iframe.setAttribute("origin", provider.origin);
|
||||
iframe.setAttribute("style", "width: " + width + "px; height: " + height + "px;");
|
||||
this.panel.appendChild(iframe);
|
||||
|
||||
this._frame.addEventListener("DOMLinkAdded", this);
|
||||
this.setAttribute("notificationFrameId", notificationFrameId);
|
||||
return this._frame;
|
||||
]]></getter>
|
||||
</property>
|
||||
@ -117,6 +109,9 @@
|
||||
this._dynamicResizer = null;
|
||||
}
|
||||
this.content.setAttribute("src", "about:blank");
|
||||
// called during onhidden, make sure the docshell is updated
|
||||
if (this._frame.docShell)
|
||||
this._frame.docShell.createAboutBlankContentViewer(null);
|
||||
|
||||
// do we have a savable page loaded?
|
||||
let aURI = gBrowser.currentURI;
|
||||
@ -216,18 +211,6 @@
|
||||
<parameter name="aResetOnClose"/>
|
||||
<body><![CDATA[
|
||||
let panel = this.panel;
|
||||
let frameId = this.getAttribute("notificationFrameId");
|
||||
|
||||
SharedFrame.setOwner(frameId, this.content);
|
||||
|
||||
// Clear dimensions on all browsers so the panel size will
|
||||
// only use the selected browser.
|
||||
let frameIter = panel.firstElementChild;
|
||||
while (frameIter) {
|
||||
frameIter.collapsed = (frameIter != this.content);
|
||||
frameIter = frameIter.nextElementSibling;
|
||||
}
|
||||
|
||||
let anchor = document.getAnonymousElementByAttribute(this._anchor, "class", "toolbarbutton-icon");
|
||||
// Bug 849216 - open the popup in a setTimeout so we avoid the auto-rollup
|
||||
// handling from preventing it being opened in some cases.
|
||||
|
@ -64,6 +64,7 @@ support-files =
|
||||
offlineQuotaNotification.cacheManifest
|
||||
offlineQuotaNotification.html
|
||||
page_style_sample.html
|
||||
parsingTestHelpers.jsm
|
||||
print_postdata.sjs
|
||||
redirect_bug623155.sjs
|
||||
searchSuggestionEngine.sjs
|
||||
@ -342,6 +343,8 @@ skip-if = buildapp == 'mulet' || e10s # Bug 866413 - PageInfo doesn't work in e1
|
||||
skip-if = e10s # Bug ?????? - test directly manipulates content
|
||||
|
||||
[browser_parsable_css.js]
|
||||
[browser_parsable_script.js]
|
||||
skip-if = debug || asan # Times out on debug/asan, and we are less picky about our JS there
|
||||
|
||||
[browser_pinnedTabs.js]
|
||||
skip-if = e10s # Bug 921905 - pinTab/unpinTab fail in e10s
|
||||
|
@ -17,6 +17,9 @@ const kWhitelist = [
|
||||
{sourceName: /loop\/.*sdk-content\/.*\.css$/i /* TokBox SDK assets, see bug 1032469 */}
|
||||
];
|
||||
|
||||
let moduleLocation = gTestPath.replace(/\/[^\/]*$/i, "/parsingTestHelpers.jsm");
|
||||
let {generateURIsFromDirTree} = Cu.import(moduleLocation, {});
|
||||
|
||||
/**
|
||||
* Check if an error should be ignored due to matching one of the whitelist
|
||||
* objects defined in kWhitelist
|
||||
@ -40,113 +43,12 @@ function ignoredError(aErrorObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a promise that is resolved with a list of CSS files to check,
|
||||
* represented by their nsIURI objects.
|
||||
*
|
||||
* @param appDir the application directory to scan for CSS files (nsIFile)
|
||||
*/
|
||||
function generateURIsFromDirTree(appDir) {
|
||||
let rv = [];
|
||||
let dirQueue = [appDir.path];
|
||||
return Task.spawn(function*() {
|
||||
while (dirQueue.length) {
|
||||
let nextDir = dirQueue.shift();
|
||||
let {subdirs, cssfiles} = yield iterateOverPath(nextDir);
|
||||
dirQueue = dirQueue.concat(subdirs);
|
||||
rv = rv.concat(cssfiles);
|
||||
}
|
||||
return rv;
|
||||
});
|
||||
}
|
||||
|
||||
/* Shorthand constructor to construct an nsI(Local)File */
|
||||
let LocalFile = Components.Constructor("@mozilla.org/file/local;1", Ci.nsIFile, "initWithPath");
|
||||
|
||||
/**
|
||||
* Uses OS.File.DirectoryIterator to asynchronously iterate over a directory.
|
||||
* It returns a promise that is resolved with an object with two properties:
|
||||
* - cssfiles: an array of nsIURIs corresponding to CSS that needs checking
|
||||
* - subdirs: an array of paths for subdirectories we need to recurse into
|
||||
* (handled by generateURIsFromDirTree above)
|
||||
*
|
||||
* @param path the path to check (string)
|
||||
*/
|
||||
function iterateOverPath(path) {
|
||||
let iterator = new OS.File.DirectoryIterator(path);
|
||||
let parentDir = new LocalFile(path);
|
||||
let subdirs = [];
|
||||
let cssfiles = [];
|
||||
// Iterate through the directory
|
||||
let promise = iterator.forEach(
|
||||
function onEntry(entry) {
|
||||
if (entry.isDir) {
|
||||
let subdir = parentDir.clone();
|
||||
subdir.append(entry.name);
|
||||
subdirs.push(subdir.path);
|
||||
} else if (entry.name.endsWith(".css")) {
|
||||
let file = parentDir.clone();
|
||||
file.append(entry.name);
|
||||
let uriSpec = getURLForFile(file);
|
||||
cssfiles.push(Services.io.newURI(uriSpec, null, null));
|
||||
} else if (entry.name.endsWith(".ja")) {
|
||||
let file = parentDir.clone();
|
||||
file.append(entry.name);
|
||||
let subentries = [uri for (uri of generateEntriesFromJarFile(file))];
|
||||
cssfiles = cssfiles.concat(subentries);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
let outerPromise = Promise.defer();
|
||||
promise.then(function() {
|
||||
outerPromise.resolve({cssfiles: cssfiles, subdirs: subdirs});
|
||||
iterator.close();
|
||||
}, function(e) {
|
||||
outerPromise.reject(e);
|
||||
iterator.close();
|
||||
});
|
||||
return outerPromise.promise;
|
||||
}
|
||||
|
||||
/* Helper function to generate a URI spec (NB: not an nsIURI yet!)
|
||||
* given an nsIFile object */
|
||||
function getURLForFile(file) {
|
||||
let fileHandler = Services.io.getProtocolHandler("file");
|
||||
fileHandler = fileHandler.QueryInterface(Ci.nsIFileProtocolHandler);
|
||||
return fileHandler.getURLSpecFromFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* A generator that generates nsIURIs for CSS files found in jar files
|
||||
* like omni.ja.
|
||||
*
|
||||
* @param jarFile an nsIFile object for the jar file that needs checking.
|
||||
*/
|
||||
function* generateEntriesFromJarFile(jarFile) {
|
||||
const ZipReader = new Components.Constructor("@mozilla.org/libjar/zip-reader;1", "nsIZipReader", "open");
|
||||
let zr = new ZipReader(jarFile);
|
||||
let entryEnumerator = zr.findEntries("*.css$");
|
||||
|
||||
const kURIStart = getURLForFile(jarFile);
|
||||
while (entryEnumerator.hasMore()) {
|
||||
let entry = entryEnumerator.getNext();
|
||||
let entryURISpec = "jar:" + kURIStart + "!/" + entry;
|
||||
yield Services.io.newURI(entryURISpec, null, null);
|
||||
}
|
||||
zr.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* The actual test.
|
||||
*/
|
||||
add_task(function checkAllTheCSS() {
|
||||
let appDir = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
|
||||
// This asynchronously produces a list of URLs (sadly, mostly sync on our
|
||||
// test infrastructure because it runs against jarfiles there, and
|
||||
// our zipreader APIs are all sync)
|
||||
let uris = yield generateURIsFromDirTree(appDir);
|
||||
let uris = yield generateURIsFromDirTree(appDir, ".css");
|
||||
|
||||
// Create a clean iframe to load all the files into:
|
||||
let hiddenWin = Services.appShell.hiddenDOMWindow;
|
||||
|
83
browser/base/content/test/general/browser_parsable_script.js
Normal file
@ -0,0 +1,83 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* This list allows pre-existing or 'unfixable' JS issues to remain, while we
|
||||
* detect newly occurring issues in shipping JS. It is a list of regexes
|
||||
* matching files which have errors:
|
||||
*/
|
||||
const kWhitelist = new Set([
|
||||
/defaults\/profile\/prefs.js$/,
|
||||
]);
|
||||
|
||||
|
||||
let moduleLocation = gTestPath.replace(/\/[^\/]*$/i, "/parsingTestHelpers.jsm");
|
||||
let {generateURIsFromDirTree} = Cu.import(moduleLocation, {});
|
||||
let {Reflect} = Cu.import("resource://gre/modules/reflect.jsm", {});
|
||||
|
||||
/**
|
||||
* Check if an error should be ignored due to matching one of the whitelist
|
||||
* objects defined in kWhitelist
|
||||
*
|
||||
* @param uri the uri to check against the whitelist
|
||||
* @return true if the uri should be skipped, false otherwise.
|
||||
*/
|
||||
function uriIsWhiteListed(uri) {
|
||||
for (let whitelistItem of kWhitelist) {
|
||||
if (whitelistItem.test(uri.spec)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function parsePromise(uri) {
|
||||
let promise = new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", uri, true);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (this.readyState == this.DONE) {
|
||||
let scriptText = this.responseText;
|
||||
let ast;
|
||||
try {
|
||||
info("Checking " + uri);
|
||||
ast = Reflect.parse(scriptText);
|
||||
resolve(true);
|
||||
} catch (ex) {
|
||||
let errorMsg = "Script error reading " + uri + ": " + ex;
|
||||
ok(false, errorMsg);
|
||||
resolve(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.onerror = (error) => {
|
||||
ok(false, "XHR error reading " + uri + ": " + error);
|
||||
resolve(false);
|
||||
};
|
||||
xhr.overrideMimeType("application/javascript");
|
||||
xhr.send(null);
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
add_task(function* checkAllTheJS() {
|
||||
let appDir = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
|
||||
// This asynchronously produces a list of URLs (sadly, mostly sync on our
|
||||
// test infrastructure because it runs against jarfiles there, and
|
||||
// our zipreader APIs are all sync)
|
||||
let uris = yield generateURIsFromDirTree(appDir, [".js", ".jsm"]);
|
||||
|
||||
// We create an array of promises so we can parallelize all our parsing
|
||||
// and file loading activity:
|
||||
let allPromises = [];
|
||||
for (let uri of uris) {
|
||||
if (uriIsWhiteListed(uri)) {
|
||||
info("Not checking " + uri.spec);
|
||||
continue;
|
||||
}
|
||||
allPromises.push(parsePromise(uri.spec));
|
||||
}
|
||||
|
||||
let promiseResults = yield Promise.all(allPromises);
|
||||
is(promiseResults.filter((x) => !x).length, 0, "There should be 0 parsing errors");
|
||||
});
|
||||
|
126
browser/base/content/test/general/parsingTestHelpers.jsm
Normal file
@ -0,0 +1,126 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["generateURIsFromDirTree"];
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
/* Shorthand constructors to construct an nsI(Local)File and zip reader: */
|
||||
const LocalFile = new Components.Constructor("@mozilla.org/file/local;1", Ci.nsIFile, "initWithPath");
|
||||
const ZipReader = new Components.Constructor("@mozilla.org/libjar/zip-reader;1", "nsIZipReader", "open");
|
||||
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/osfile.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
|
||||
/**
|
||||
* Returns a promise that is resolved with a list of files that have one of the
|
||||
* extensions passed, represented by their nsIURI objects, which exist inside
|
||||
* the directory passed.
|
||||
*
|
||||
* @param dir the directory which to scan for files (nsIFile)
|
||||
* @param extensions the extensions of files we're interested in (Array).
|
||||
*/
|
||||
function generateURIsFromDirTree(dir, extensions) {
|
||||
if (!Array.isArray(extensions)) {
|
||||
extensions = [extensions];
|
||||
}
|
||||
let dirQueue = [dir.path];
|
||||
return Task.spawn(function*() {
|
||||
let rv = [];
|
||||
while (dirQueue.length) {
|
||||
let nextDir = dirQueue.shift();
|
||||
let {subdirs, files} = yield iterateOverPath(nextDir, extensions);
|
||||
dirQueue.push(...subdirs);
|
||||
rv.push(...files);
|
||||
}
|
||||
return rv;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses OS.File.DirectoryIterator to asynchronously iterate over a directory.
|
||||
* It returns a promise that is resolved with an object with two properties:
|
||||
* - files: an array of nsIURIs corresponding to files that match the extensions passed
|
||||
* - subdirs: an array of paths for subdirectories we need to recurse into
|
||||
* (handled by generateURIsFromDirTree above)
|
||||
*
|
||||
* @param path the path to check (string)
|
||||
* @param extensions the file extensions we're interested in.
|
||||
*/
|
||||
function iterateOverPath(path, extensions) {
|
||||
let iterator = new OS.File.DirectoryIterator(path);
|
||||
let parentDir = new LocalFile(path);
|
||||
let subdirs = [];
|
||||
let files = [];
|
||||
|
||||
let pathEntryIterator = (entry) => {
|
||||
if (entry.isDir) {
|
||||
subdirs.push(entry.path);
|
||||
} else if (extensions.some((extension) => entry.name.endsWith(extension))) {
|
||||
let file = parentDir.clone();
|
||||
file.append(entry.name);
|
||||
let uriSpec = getURLForFile(file);
|
||||
files.push(Services.io.newURI(uriSpec, null, null));
|
||||
} else if (entry.name.endsWith(".ja") || entry.name.endsWith(".jar")) {
|
||||
let file = parentDir.clone();
|
||||
file.append(entry.name);
|
||||
for (let extension of extensions) {
|
||||
let jarEntryIterator = generateEntriesFromJarFile(file, extension);
|
||||
files.push(...jarEntryIterator);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
Task.spawn(function* () {
|
||||
try {
|
||||
// Iterate through the directory
|
||||
yield iterator.forEach(pathEntryIterator);
|
||||
resolve({files: files, subdirs: subdirs});
|
||||
} catch (ex) {
|
||||
reject(ex);
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* Helper function to generate a URI spec (NB: not an nsIURI yet!)
|
||||
* given an nsIFile object */
|
||||
function getURLForFile(file) {
|
||||
let fileHandler = Services.io.getProtocolHandler("file");
|
||||
fileHandler = fileHandler.QueryInterface(Ci.nsIFileProtocolHandler);
|
||||
return fileHandler.getURLSpecFromActualFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* A generator that generates nsIURIs for particular files found in jar files
|
||||
* like omni.ja.
|
||||
*
|
||||
* @param jarFile an nsIFile object for the jar file that needs checking.
|
||||
* @param extension the extension we're interested in.
|
||||
*/
|
||||
function* generateEntriesFromJarFile(jarFile, extension) {
|
||||
let zr = new ZipReader(jarFile);
|
||||
let entryEnumerator = zr.findEntries("*" + extension + "$");
|
||||
|
||||
const kURIStart = getURLForFile(jarFile);
|
||||
while (entryEnumerator.hasMore()) {
|
||||
let entry = entryEnumerator.getNext();
|
||||
// Ignore the JS cache which is stored in omni.ja
|
||||
if (entry.startsWith("jsloader") || entry.startsWith("jssubloader")) {
|
||||
continue;
|
||||
}
|
||||
let entryURISpec = "jar:" + kURIStart + "!/" + entry;
|
||||
yield Services.io.newURI(entryURISpec, null, null);
|
||||
}
|
||||
zr.close();
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ gDirectorySource = "data:application/json," + JSON.stringify({
|
||||
"en-US": [{
|
||||
url: "http://example.com/",
|
||||
enhancedImageURI: "data:image/png;base64,helloWORLD",
|
||||
title: "title",
|
||||
type: "organic"
|
||||
}]
|
||||
});
|
||||
@ -28,6 +29,7 @@ function runTests() {
|
||||
return {
|
||||
type: siteNode.getAttribute("type"),
|
||||
enhanced: siteNode.querySelector(".enhanced-content").style.backgroundImage,
|
||||
title: siteNode.querySelector(".newtab-title").textContent,
|
||||
};
|
||||
}
|
||||
|
||||
@ -37,27 +39,40 @@ function runTests() {
|
||||
// Test with enhanced = false
|
||||
NewTabUtils.allPages.enhanced = false;
|
||||
yield addNewTabPageTab();
|
||||
let {type, enhanced} = getData(0);
|
||||
let {type, enhanced, title} = getData(0);
|
||||
is(type, "organic", "directory link is organic");
|
||||
isnot(enhanced, "", "directory link has enhanced image");
|
||||
is(title, "title");
|
||||
|
||||
is(getData(1), null, "history link pushed out by directory link");
|
||||
|
||||
// Test with enhanced = true
|
||||
NewTabUtils.allPages.enhanced = true;
|
||||
yield addNewTabPageTab();
|
||||
let {type, enhanced} = getData(0);
|
||||
let {type, enhanced, title} = getData(0);
|
||||
is(type, "organic", "directory link is still organic");
|
||||
isnot(enhanced, "", "directory link still has enhanced image");
|
||||
is(title, "title");
|
||||
|
||||
is(getData(1), null, "history link still pushed out by directory link");
|
||||
|
||||
// Test with a pinned link
|
||||
setPinnedLinks("-1");
|
||||
yield addNewTabPageTab();
|
||||
let {type, enhanced} = getData(0);
|
||||
let {type, enhanced, title} = getData(0);
|
||||
is(type, "enhanced", "pinned history link is enhanced");
|
||||
isnot(enhanced, "", "pinned history link has enhanced image");
|
||||
is(title, "title");
|
||||
|
||||
is(getData(1), null, "directory link pushed out by pinned history link");
|
||||
|
||||
// Test pinned link with enhanced = false
|
||||
NewTabUtils.allPages.enhanced = false;
|
||||
yield addNewTabPageTab();
|
||||
let {type, enhanced, title} = getData(0);
|
||||
isnot(type, "enhanced", "history link is not enhanced");
|
||||
is(enhanced, "", "history link has no enhanced image");
|
||||
is(title, "site#-1");
|
||||
|
||||
is(getData(1), null, "directory link still pushed out by pinned history link");
|
||||
}
|
||||
|
@ -8,26 +8,29 @@ function runTests() {
|
||||
let site = getCell(0).node.querySelector(".newtab-site");
|
||||
site.setAttribute("type", "sponsored");
|
||||
|
||||
let sponsoredPanel = getContentDocument().getElementById("sponsored-panel");
|
||||
is(sponsoredPanel.state, "closed", "Sponsored panel must be closed");
|
||||
// test explain text appearing upon a click
|
||||
let sponsoredButton = site.querySelector(".newtab-sponsored");
|
||||
EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, getContentWindow());
|
||||
let explain = site.querySelector(".sponsored-explain");
|
||||
isnot(explain, null, "Sponsored explanation shown");
|
||||
ok(explain.querySelector("input").classList.contains("newtab-control-block"), "sponsored tiles show blocked image");
|
||||
ok(sponsoredButton.hasAttribute("active"), "Sponsored button has active attribute");
|
||||
|
||||
function continueOnceOn(event) {
|
||||
sponsoredPanel.addEventListener(event, function listener() {
|
||||
sponsoredPanel.removeEventListener(event, listener);
|
||||
executeSoon(TestRunner.next);
|
||||
});
|
||||
}
|
||||
// test dismissing sponsored explain
|
||||
EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, getContentWindow());
|
||||
is(site.querySelector(".sponsored-explain"), null, "Sponsored explanation no longer shown");
|
||||
ok(!sponsoredButton.hasAttribute("active"), "Sponsored button does not have active attribute");
|
||||
|
||||
// test sponsoredPanel appearing upon a click
|
||||
continueOnceOn("popupshown");
|
||||
let sponsoredButton = site.querySelector(".newtab-control-sponsored");
|
||||
yield EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, getContentWindow());
|
||||
is(sponsoredPanel.state, "open", "Sponsored panel opens on click");
|
||||
ok(sponsoredButton.hasAttribute("panelShown"), "Sponsored button has panelShown attribute");
|
||||
// test with enhanced tile
|
||||
site.setAttribute("type", "enhanced");
|
||||
EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, getContentWindow());
|
||||
explain = site.querySelector(".sponsored-explain");
|
||||
isnot(explain, null, "Sponsored explanation shown");
|
||||
ok(explain.querySelector("input").classList.contains("newtab-customize"), "enhanced tiles show customize image");
|
||||
ok(sponsoredButton.hasAttribute("active"), "Sponsored button has active attribute");
|
||||
|
||||
// test sponsoredPanel hiding
|
||||
continueOnceOn("popuphidden");
|
||||
yield sponsoredPanel.hidePopup();
|
||||
is(sponsoredPanel.state, "closed", "Sponsored panel correctly closed/hidden");
|
||||
ok(!sponsoredButton.hasAttribute("panelShown"), "Sponsored button does not have panelShown attribute");
|
||||
// test dismissing enhanced explain
|
||||
EventUtils.synthesizeMouseAtCenter(sponsoredButton, {}, getContentWindow());
|
||||
is(site.querySelector(".sponsored-explain"), null, "Sponsored explanation no longer shown");
|
||||
ok(!sponsoredButton.hasAttribute("active"), "Sponsored button does not have active attribute");
|
||||
}
|
||||
|
@ -78,6 +78,26 @@ browser.jar:
|
||||
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
|
||||
* content/browser/chatWindow.xul (content/chatWindow.xul)
|
||||
content/browser/content.js (content/content.js)
|
||||
content/browser/defaultthemes/1.footer.jpg (content/defaultthemes/1.footer.jpg)
|
||||
content/browser/defaultthemes/1.header.jpg (content/defaultthemes/1.header.jpg)
|
||||
content/browser/defaultthemes/1.icon.jpg (content/defaultthemes/1.icon.jpg)
|
||||
content/browser/defaultthemes/1.preview.jpg (content/defaultthemes/1.preview.jpg)
|
||||
content/browser/defaultthemes/2.footer.jpg (content/defaultthemes/2.footer.jpg)
|
||||
content/browser/defaultthemes/2.header.jpg (content/defaultthemes/2.header.jpg)
|
||||
content/browser/defaultthemes/2.icon.jpg (content/defaultthemes/2.icon.jpg)
|
||||
content/browser/defaultthemes/2.preview.jpg (content/defaultthemes/2.preview.jpg)
|
||||
content/browser/defaultthemes/3.footer.png (content/defaultthemes/3.footer.png)
|
||||
content/browser/defaultthemes/3.header.png (content/defaultthemes/3.header.png)
|
||||
content/browser/defaultthemes/3.icon.png (content/defaultthemes/3.icon.png)
|
||||
content/browser/defaultthemes/3.preview.png (content/defaultthemes/3.preview.png)
|
||||
content/browser/defaultthemes/4.footer.png (content/defaultthemes/4.footer.png)
|
||||
content/browser/defaultthemes/4.header.png (content/defaultthemes/4.header.png)
|
||||
content/browser/defaultthemes/4.icon.png (content/defaultthemes/4.icon.png)
|
||||
content/browser/defaultthemes/4.preview.png (content/defaultthemes/4.preview.png)
|
||||
content/browser/defaultthemes/5.footer.png (content/defaultthemes/5.footer.png)
|
||||
content/browser/defaultthemes/5.header.png (content/defaultthemes/5.header.png)
|
||||
content/browser/defaultthemes/5.icon.jpg (content/defaultthemes/5.icon.jpg)
|
||||
content/browser/defaultthemes/5.preview.jpg (content/defaultthemes/5.preview.jpg)
|
||||
content/browser/newtab/newTab.xul (content/newtab/newTab.xul)
|
||||
* content/browser/newtab/newTab.js (content/newtab/newTab.js)
|
||||
content/browser/newtab/newTab.css (content/newtab/newTab.css)
|
||||
|
@ -27,11 +27,15 @@ Cu.import("resource:///modules/CustomizableUI.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/AddonManager.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "DragPositionManager",
|
||||
"resource:///modules/DragPositionManager.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
|
||||
"resource:///modules/BrowserUITelemetry.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
|
||||
"resource://gre/modules/LightweightThemeManager.jsm");
|
||||
|
||||
|
||||
let gModuleName = "[CustomizeMode]";
|
||||
#include logging.js
|
||||
@ -1218,6 +1222,119 @@ CustomizeMode.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
openAddonsManagerThemes: function(aEvent) {
|
||||
aEvent.target.parentNode.parentNode.hidePopup();
|
||||
this.window.BrowserOpenAddonsMgr('addons://list/theme');
|
||||
},
|
||||
|
||||
getMoreThemes: function(aEvent) {
|
||||
aEvent.target.parentNode.parentNode.hidePopup();
|
||||
let getMoreURL = Services.urlFormatter.formatURLPref("lightweightThemes.getMoreURL");
|
||||
this.window.openUILinkIn(getMoreURL, "tab");
|
||||
},
|
||||
|
||||
onLWThemesMenuShowing: function(aEvent) {
|
||||
AddonManager.getAddonsByTypes(["theme"], function(aThemes) {
|
||||
function buildToolbarButton(doc, aTheme) {
|
||||
function previewTheme(aEvent) {
|
||||
LightweightThemeManager.previewTheme(aEvent.target.theme);
|
||||
}
|
||||
function resetPreview() {
|
||||
LightweightThemeManager.resetPreview();
|
||||
}
|
||||
let tbb = doc.createElement("toolbarbutton");
|
||||
tbb.theme = aTheme;
|
||||
tbb.setAttribute("label", aTheme.name);
|
||||
tbb.setAttribute("image", aTheme.iconURL);
|
||||
tbb.setAttribute("tooltiptext", aTheme.description);
|
||||
tbb.setAttribute("tabindex", "0");
|
||||
tbb.classList.add("customization-lwtheme-menu-theme");
|
||||
tbb.setAttribute("aria-checked", aTheme.isActive);
|
||||
tbb.setAttribute("role", "menuitemradio");
|
||||
if (aTheme.isActive) {
|
||||
tbb.setAttribute("active", "true");
|
||||
}
|
||||
tbb.addEventListener("focus", previewTheme);
|
||||
tbb.addEventListener("mouseover", previewTheme);
|
||||
tbb.addEventListener("blur", resetPreview);
|
||||
tbb.addEventListener("mouseout", resetPreview);
|
||||
|
||||
return tbb;
|
||||
}
|
||||
|
||||
const DEFAULT_THEME_ID = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
|
||||
// Order the themes so the Default theme is always at the beginning.
|
||||
aThemes.sort((a,b) => {a.id != DEFAULT_THEME_ID});
|
||||
let doc = this.window.document;
|
||||
let footer = doc.getElementById("customization-lwtheme-menu-footer");
|
||||
let panel = footer.parentNode;
|
||||
let themesInMyThemesSection = 0;
|
||||
let recommendedLabel = doc.getElementById("customization-lwtheme-menu-recommended");
|
||||
for (let theme of aThemes) {
|
||||
// Only allow the Default full theme to be shown in this list.
|
||||
if ("skinnable" in theme &&
|
||||
theme.id != DEFAULT_THEME_ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let tbb = buildToolbarButton(doc, theme);
|
||||
tbb.addEventListener("command", function() {
|
||||
this.theme.userDisabled = false;
|
||||
this.parentNode.hidePopup();
|
||||
});
|
||||
panel.insertBefore(tbb, recommendedLabel);
|
||||
themesInMyThemesSection++;
|
||||
}
|
||||
|
||||
let lwthemePrefs = Services.prefs.getBranch("lightweightThemes.");
|
||||
let recommendedThemes = lwthemePrefs.getComplexValue("recommendedThemes",
|
||||
Ci.nsISupportsString).data;
|
||||
recommendedThemes = JSON.parse(recommendedThemes);
|
||||
let sb = Services.strings.createBundle("chrome://browser/locale/lightweightThemes.properties");
|
||||
for (let theme of recommendedThemes) {
|
||||
theme.name = sb.GetStringFromName("lightweightThemes." + theme.id + ".name");
|
||||
theme.description = sb.GetStringFromName("lightweightThemes." + theme.id + ".description");
|
||||
let tbb = buildToolbarButton(doc, theme);
|
||||
tbb.addEventListener("command", function() {
|
||||
LightweightThemeManager.setLocalTheme(this.theme);
|
||||
recommendedThemes = recommendedThemes.filter((aTheme) => { return aTheme.id != this.theme.id; });
|
||||
let string = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
string.data = JSON.stringify(recommendedThemes);
|
||||
lwthemePrefs.setComplexValue("recommendedThemes",
|
||||
Ci.nsISupportsString, string);
|
||||
this.parentNode.hidePopup();
|
||||
});
|
||||
panel.insertBefore(tbb, footer);
|
||||
}
|
||||
let hideRecommendedLabel = (footer.previousSibling == recommendedLabel);
|
||||
recommendedLabel.hidden = hideRecommendedLabel;
|
||||
|
||||
let hideMyThemesSection = themesInMyThemesSection < 2 && hideRecommendedLabel;
|
||||
let headerLabel = doc.getElementById("customization-lwtheme-menu-header");
|
||||
if (hideMyThemesSection) {
|
||||
let element = recommendedLabel.previousSibling;
|
||||
while (element && element != headerLabel) {
|
||||
element.hidden = true;
|
||||
element = element.previousSibling;
|
||||
}
|
||||
}
|
||||
headerLabel.hidden = hideMyThemesSection;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
onLWThemesMenuHidden: function(aEvent) {
|
||||
let doc = aEvent.target.ownerDocument;
|
||||
let footer = doc.getElementById("customization-lwtheme-menu-footer");
|
||||
let recommendedLabel = doc.getElementById("customization-lwtheme-menu-recommended");
|
||||
for (let element of [footer, recommendedLabel]) {
|
||||
while (element.previousSibling &&
|
||||
element.previousSibling.localName == "toolbarbutton") {
|
||||
element.previousSibling.remove();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onUIChange: function() {
|
||||
this._changed = true;
|
||||
if (!this.resetting) {
|
||||
|
@ -29,6 +29,27 @@
|
||||
<button id="customization-toolbar-visibility-button" label="&customizeMode.toolbars;" class="customizationmode-button" type="menu">
|
||||
<menupopup id="customization-toolbar-menu" onpopupshowing="onViewToolbarsPopupShowing(event)"/>
|
||||
</button>
|
||||
<button id="customization-lwtheme-button" label="&customizeMode.lwthemes;" class="customizationmode-button" type="menu">
|
||||
<panel type="arrow" id="customization-lwtheme-menu"
|
||||
onpopupshowing="gCustomizeMode.onLWThemesMenuShowing(event);"
|
||||
onpopuphidden="gCustomizeMode.onLWThemesMenuHidden(event);"
|
||||
role="menu">
|
||||
<label id="customization-lwtheme-menu-header" value="&customizeMode.lwthemes.myThemes;"/>
|
||||
<label id="customization-lwtheme-menu-recommended" value="&customizeMode.lwthemes.recommended;"/>
|
||||
<hbox id="customization-lwtheme-menu-footer">
|
||||
<toolbarbutton class="customization-lwtheme-menu-footeritem"
|
||||
label="&customizeMode.lwthemes.menuManage;"
|
||||
accesskey="&customizeMode.lwthemes.menuManage.accessKey;"
|
||||
tabindex="0"
|
||||
oncommand="gCustomizeMode.openAddonsManagerThemes(event);"/>
|
||||
<toolbarbutton class="customization-lwtheme-menu-footeritem"
|
||||
label="&customizeMode.lwthemes.menuGetMore;"
|
||||
accesskey="&customizeMode.lwthemes.menuGetMore.accessKey;"
|
||||
tabindex="0"
|
||||
oncommand="gCustomizeMode.getMoreThemes(event);"/>
|
||||
</hbox>
|
||||
</panel>
|
||||
</button>
|
||||
<spacer id="customization-footer-spacer"/>
|
||||
<button id="customization-undo-reset-button"
|
||||
class="customizationmode-button"
|
||||
|
@ -115,6 +115,7 @@ skip-if = os == "linux"
|
||||
[browser_996364_registerArea_different_properties.js]
|
||||
[browser_996635_remove_non_widgets.js]
|
||||
[browser_1003588_no_specials_in_panel.js]
|
||||
[browser_1007336_lwthemes_in_customize_mode.js]
|
||||
[browser_1008559_anchor_undo_restore.js]
|
||||
[browser_1042100_default_placements_update.js]
|
||||
[browser_bootstrapped_custom_toolbar.js]
|
||||
|
@ -0,0 +1,60 @@
|
||||
/* 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 DEFAULT_THEME_ID = "{972ce4c6-7e08-4474-a285-3208198ce6fd}";
|
||||
|
||||
add_task(function () {
|
||||
Services.prefs.clearUserPref("lightweightThemes.usedThemes");
|
||||
Services.prefs.clearUserPref("lightweightThemes.recommendedThemes");
|
||||
|
||||
yield startCustomizing();
|
||||
|
||||
let themesButton = document.getElementById("customization-lwtheme-button");
|
||||
let popup = document.getElementById("customization-lwtheme-menu");
|
||||
|
||||
let popupShownPromise = popupShown(popup);
|
||||
EventUtils.synthesizeMouseAtCenter(themesButton, {});
|
||||
info("Clicked on themes button");
|
||||
yield popupShownPromise;
|
||||
|
||||
let header = document.getElementById("customization-lwtheme-menu-header");
|
||||
let recommendedHeader = document.getElementById("customization-lwtheme-menu-recommended");
|
||||
|
||||
is(header.nextSibling.nextSibling, recommendedHeader,
|
||||
"There should only be one theme (default) in the 'My Themes' section by default");
|
||||
is(header.nextSibling.theme.id, DEFAULT_THEME_ID, "That theme should be the default theme");
|
||||
|
||||
let firstLWTheme = recommendedHeader.nextSibling;
|
||||
let firstLWThemeId = firstLWTheme.theme.id;
|
||||
let themeChangedPromise = promiseObserverNotified("lightweight-theme-changed");
|
||||
firstLWTheme.doCommand();
|
||||
info("Clicked on first theme");
|
||||
yield themeChangedPromise;
|
||||
|
||||
popupShownPromise = popupShown(popup);
|
||||
EventUtils.synthesizeMouseAtCenter(themesButton, {});
|
||||
info("Clicked on themes button");
|
||||
yield popupShownPromise;
|
||||
|
||||
is(header.nextSibling.theme.id, DEFAULT_THEME_ID, "The first theme should be the Default theme");
|
||||
let installedThemeId = header.nextSibling.nextSibling.theme.id;
|
||||
ok(installedThemeId.startsWith(firstLWThemeId),
|
||||
"The second theme in the 'My Themes' section should be the newly installed theme: " +
|
||||
"Installed theme id: " + installedThemeId + "; First theme ID: " + firstLWThemeId);
|
||||
is(header.nextSibling.nextSibling.nextSibling, recommendedHeader,
|
||||
"There should be two themes in the 'My Themes' section");
|
||||
|
||||
let defaultTheme = header.nextSibling;
|
||||
defaultTheme.doCommand();
|
||||
is(Services.prefs.getBoolPref("lightweightThemes.isThemeSelected"), false, "No lwtheme should be selected");
|
||||
});
|
||||
|
||||
add_task(function asyncCleanup() {
|
||||
yield endCustomizing();
|
||||
|
||||
Services.prefs.clearUserPref("lightweightThemes.usedThemes");
|
||||
Services.prefs.clearUserPref("lightweightThemes.recommendedThemes");
|
||||
})
|
@ -227,6 +227,15 @@ function startCustomizing(aWindow=window) {
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseObserverNotified(aTopic) {
|
||||
let deferred = Promise.defer();
|
||||
Services.obs.addObserver(function onNotification(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(onNotification, aTopic);
|
||||
deferred.resolve({subject: aSubject, data: aData});
|
||||
}, aTopic, false);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function openAndLoadWindow(aOptions, aWaitForDelayedStartup=false) {
|
||||
let deferred = Promise.defer();
|
||||
let win = OpenBrowserWindow(aOptions);
|
||||
|
@ -26,7 +26,7 @@ box,
|
||||
min-height: 3em;
|
||||
max-height: 14em;
|
||||
max-width: 400px;
|
||||
min-width: 180px;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.splitview-nav {
|
||||
|
@ -697,6 +697,13 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
||||
<!ENTITY customizeMode.restoreDefaults "Restore Defaults">
|
||||
<!ENTITY customizeMode.toolbars "Show / Hide Toolbars">
|
||||
<!ENTITY customizeMode.titlebar "Title Bar">
|
||||
<!ENTITY customizeMode.lwthemes "Themes">
|
||||
<!ENTITY customizeMode.lwthemes.myThemes "My Themes">
|
||||
<!ENTITY customizeMode.lwthemes.recommended "Recommended">
|
||||
<!ENTITY customizeMode.lwthemes.menuManage "Manage">
|
||||
<!ENTITY customizeMode.lwthemes.menuManage.accessKey "M">
|
||||
<!ENTITY customizeMode.lwthemes.menuGetMore "Get More Themes">
|
||||
<!ENTITY customizeMode.lwthemes.menuGetMore.accessKey "G">
|
||||
|
||||
<!ENTITY social.chatBar.commandkey "c">
|
||||
<!ENTITY social.chatBar.label "Focus chats">
|
||||
|
@ -0,0 +1,18 @@
|
||||
# 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/.
|
||||
|
||||
lightweightThemes.recommended-1.name=A Web Browser Renaissance
|
||||
lightweightThemes.recommended-1.description=A Web Browser Renaissance is (C) Sean.Martell. Available under CC-BY-SA. No warranty.
|
||||
|
||||
lightweightThemes.recommended-2.name=Space Fantasy
|
||||
lightweightThemes.recommended-2.description=Space Fantasy is (C) fx5800p. Available under CC-BY-SA. No warranty.
|
||||
|
||||
lightweightThemes.recommended-3.name=Linen Light
|
||||
lightweightThemes.recommended-3.description=Linen Light is (C) DVemer. Available under CC-BY-SA. No warranty.
|
||||
|
||||
lightweightThemes.recommended-4.name=Pastel Gradient
|
||||
lightweightThemes.recommended-4.description=Pastel Gradient is (C) darrinhenein. Available under CC-BY. No warranty.
|
||||
|
||||
lightweightThemes.recommended-5.name=Carbon Light
|
||||
lightweightThemes.recommended-5.description=Carbon Light is (C) Jaxivo. Available under CC-BY-SA. No warranty.
|
@ -12,6 +12,3 @@
|
||||
<!ENTITY newtab.undo.undoButton "Undo.">
|
||||
<!ENTITY newtab.undo.restoreButton "Restore All.">
|
||||
<!ENTITY newtab.undo.closeTooltip "Hide">
|
||||
<!ENTITY newtab.sponsored.release.message "This Sponsor site was suggested because we hoped you’d find it interesting and because it supports Mozilla’s mission.">
|
||||
<!ENTITY newtab.sponsored.trial.message2 "This site was suggested because we hoped you’d find it interesting and because it supports Mozilla’s mission.">
|
||||
<!ENTITY newtab.panel.link.text "Learn more…">
|
||||
|
@ -5,4 +5,16 @@
|
||||
newtab.pin=Pin this site at its current position
|
||||
newtab.unpin=Unpin this site
|
||||
newtab.block=Remove this site
|
||||
newtab.sponsored=Show information on sponsored tiles
|
||||
# LOCALIZATION NOTE(newtab.sponsored.button): This text appears for sponsored
|
||||
# and enhanced tiles on the same line as the tile's title, so prefer short
|
||||
# strings to avoid overlap. This string should be uppercase.
|
||||
newtab.sponsored.button=SPONSORED
|
||||
# LOCALIZATION NOTE(newtab.sponsored.explain): %1$S will be replaced inline by
|
||||
# the (X) block icon. %2$S will be replaced by an active link using string
|
||||
# newtab.learn.link as text.
|
||||
newtab.sponsored.explain=This tile is being shown to you on behalf of a Mozilla partner. You can remove it at any time by clicking the %1$S button. %2$S
|
||||
# LOCALIZATION NOTE(newtab.enhanced.explain): %1$S will be replaced inline by
|
||||
# the gear icon used to customize the new tab window. %2$S will be replaced by
|
||||
# an active link using string newtab.learn.link as text.
|
||||
newtab.enhanced.explain=A Mozilla partner has visually enhanced this tile, replacing the screenshot. You can turn off enhanced tiles by clicking the %1$S button for your preferences. %2$S
|
||||
newtab.learn.link=Learn more…
|
||||
|
@ -66,6 +66,7 @@
|
||||
locale/browser/devtools/app-manager.properties (%chrome/browser/devtools/app-manager.properties)
|
||||
locale/browser/devtools/webide.dtd (%chrome/browser/devtools/webide.dtd)
|
||||
locale/browser/devtools/webide.properties (%chrome/browser/devtools/webide.properties)
|
||||
locale/browser/lightweightThemes.properties (%chrome/browser/lightweightThemes.properties)
|
||||
locale/browser/loop/loop.properties (%chrome/browser/loop/loop.properties)
|
||||
locale/browser/newTab.dtd (%chrome/browser/newTab.dtd)
|
||||
locale/browser/newTab.properties (%chrome/browser/newTab.properties)
|
||||
|
@ -81,7 +81,7 @@ this.ContentSearch = {
|
||||
// them immediately, which would result in non-FIFO responses due to the
|
||||
// asynchrononicity added by converting image data URIs to ArrayBuffers.
|
||||
_eventQueue: [],
|
||||
_currentEvent: null,
|
||||
_currentEventPromise: null,
|
||||
|
||||
// This is used to handle search suggestions. It maps xul:browsers to objects
|
||||
// { controller, previousFormHistoryResult }. See _onMessageGetSuggestions.
|
||||
@ -94,6 +94,16 @@ this.ContentSearch = {
|
||||
Services.obs.addObserver(this, "browser-search-engine-modified", false);
|
||||
},
|
||||
|
||||
destroy: function () {
|
||||
Cc["@mozilla.org/globalmessagemanager;1"].
|
||||
getService(Ci.nsIMessageListenerManager).
|
||||
removeMessageListener(INBOUND_MESSAGE, this);
|
||||
Services.obs.removeObserver(this, "browser-search-engine-modified");
|
||||
|
||||
this._eventQueue.length = 0;
|
||||
return Promise.resolve(this._currentEventPromise);
|
||||
},
|
||||
|
||||
/**
|
||||
* Focuses the search input in the page with the given message manager.
|
||||
* @param messageManager
|
||||
@ -141,22 +151,24 @@ this.ContentSearch = {
|
||||
}
|
||||
},
|
||||
|
||||
_processEventQueue: Task.async(function* () {
|
||||
if (this._currentEvent || !this._eventQueue.length) {
|
||||
_processEventQueue: function () {
|
||||
if (this._currentEventPromise || !this._eventQueue.length) {
|
||||
return;
|
||||
}
|
||||
this._currentEvent = this._eventQueue.shift();
|
||||
try {
|
||||
yield this["_on" + this._currentEvent.type](this._currentEvent.data);
|
||||
}
|
||||
catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
finally {
|
||||
this._currentEvent = null;
|
||||
this._processEventQueue();
|
||||
}
|
||||
}),
|
||||
|
||||
let event = this._eventQueue.shift();
|
||||
|
||||
return this._currentEventPromise = Task.spawn(function* () {
|
||||
try {
|
||||
yield this["_on" + event.type](event.data);
|
||||
} catch (err) {
|
||||
Cu.reportError(err);
|
||||
} finally {
|
||||
this._currentEventPromise = null;
|
||||
this._processEventQueue();
|
||||
}
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_onMessage: Task.async(function* (msg) {
|
||||
let methodName = "_onMessage" + msg.data.type;
|
||||
|
@ -45,10 +45,6 @@
|
||||
-moz-padding-start: 0;
|
||||
}
|
||||
|
||||
.subviewbutton.bookmark-item > .toolbarbutton-icon {
|
||||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
/* subviewbutton entries for social sidebars have images that come from external
|
||||
/* sources, and are not guaranteed to be the size we want, so force the size on
|
||||
/* those icons. */
|
||||
|
@ -118,8 +118,6 @@ browser.jar:
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
* skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
|
||||
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
|
||||
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
|
||||
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
||||
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
||||
|
@ -192,8 +192,6 @@ browser.jar:
|
||||
skin/classic/browser/feeds/audioFeedIcon.png (feeds/feedIcon.png)
|
||||
skin/classic/browser/feeds/audioFeedIcon16.png (feeds/feedIcon16.png)
|
||||
* skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
|
||||
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
|
||||
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
|
||||
skin/classic/browser/setDesktopBackground.css
|
||||
skin/classic/browser/monitor.png
|
||||
|
@ -276,4 +276,97 @@ toolbarpaletteitem[place="toolbar"] {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
#customization-lwtheme-menu > .panel-arrowcontainer > .panel-arrowcontent {
|
||||
-moz-box-orient: vertical;
|
||||
/* Make the panel padding uniform across all platforms due to the
|
||||
styling of the section headers and footer. */
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.customization-lwtheme-menu-theme > .toolbarbutton-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.customization-lwtheme-menu-theme {
|
||||
-moz-appearance: none;
|
||||
border: 1px solid transparent;
|
||||
margin: 0 -5px 5px;
|
||||
padding-top: 0;
|
||||
-moz-padding-end: 5px;
|
||||
padding-bottom: 0;
|
||||
-moz-padding-start: 0;
|
||||
}
|
||||
|
||||
.customization-lwtheme-menu-theme[active="true"],
|
||||
.customization-lwtheme-menu-theme:hover {
|
||||
background-color: hsla(210,4%,10%,.08);
|
||||
border-color: hsla(210,4%,10%,.11);
|
||||
}
|
||||
|
||||
.customization-lwtheme-menu-theme[active="true"],
|
||||
.customization-lwtheme-menu-theme:hover:active {
|
||||
background-color: hsla(210,4%,10%,.15);
|
||||
}
|
||||
|
||||
.customization-lwtheme-menu-theme > .toolbarbutton-icon {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.customization-lwtheme-menu-theme > .toolbarbutton-text {
|
||||
text-align: start;
|
||||
}
|
||||
|
||||
#customization-lwtheme-menu-header,
|
||||
#customization-lwtheme-menu-recommended {
|
||||
padding: 10px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#customization-lwtheme-menu-header,
|
||||
#customization-lwtheme-menu-recommended,
|
||||
#customization-lwtheme-menu-footer {
|
||||
background-color: hsla(210,4%,10%,.05);
|
||||
color: hsl(0,0%,50%);
|
||||
margin-right: -10px;
|
||||
margin-left: -10px;
|
||||
}
|
||||
|
||||
#customization-lwtheme-menu-header {
|
||||
margin-top: -10px;
|
||||
border-bottom: 1px solid hsla(210,4%,10%,.05);
|
||||
}
|
||||
|
||||
#customization-lwtheme-menu-recommended {
|
||||
border-top: 1px solid hsla(210,4%,10%,.05);
|
||||
border-bottom: 1px solid hsla(210,4%,10%,.05);
|
||||
}
|
||||
|
||||
#customization-lwtheme-menu-footer {
|
||||
border-top: 1px solid hsla(210,4%,10%,.05);
|
||||
margin-bottom: -10px;
|
||||
}
|
||||
|
||||
.customization-lwtheme-menu-footeritem {
|
||||
-moz-appearance: none;
|
||||
-moz-box-flex: 1;
|
||||
color: hsl(0,0%,50%);
|
||||
border: 1px solid transparent;
|
||||
padding: 10px;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.customization-lwtheme-menu-footeritem:hover {
|
||||
background-color: hsla(210,4%,10%,.15);
|
||||
}
|
||||
|
||||
#customization-lwtheme-menu-footer:not(:hover) > .customization-lwtheme-menu-footeritem:first-child {
|
||||
-moz-border-end: 1px solid hsla(210,4%,10%,.15);
|
||||
}
|
||||
|
||||
#customization-lwtheme-menu-footer:hover > .customization-lwtheme-menu-footeritem:first-child {
|
||||
-moz-border-end-color: transparent;
|
||||
}
|
||||
|
||||
%include customizeTip.inc.css
|
||||
|
Before Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 22 KiB |
@ -62,7 +62,8 @@
|
||||
}
|
||||
|
||||
/* CUSTOMIZE */
|
||||
#newtab-customize-button {
|
||||
#newtab-customize-button,
|
||||
.newtab-customize {
|
||||
background-color: transparent;
|
||||
background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 32, 32, 0);
|
||||
background-size: 28px;
|
||||
@ -160,10 +161,6 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.newtab-site[type=sponsored] .newtab-title {
|
||||
-moz-padding-end: 24px;
|
||||
}
|
||||
|
||||
/* CONTROLS */
|
||||
.newtab-control {
|
||||
background-color: transparent;
|
||||
@ -199,24 +196,3 @@
|
||||
.newtab-control-block:hover:active {
|
||||
background-image: -moz-image-rect(url(chrome://browser/skin/newtab/controls.svg), 0, 256, 32, 224);
|
||||
}
|
||||
|
||||
.newtab-control-sponsored {
|
||||
background-image: url(chrome://browser/skin/newtab/controls.png);
|
||||
background-position: -249px -1px;
|
||||
background-size: auto;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.newtab-control-sponsored {
|
||||
background-image: url(chrome://browser/skin/newtab/controls@2x.png);
|
||||
background-size: 296px;
|
||||
}
|
||||
}
|
||||
|
||||
.newtab-control-sponsored:hover {
|
||||
background-position: -265px -1px;
|
||||
}
|
||||
|
||||
.newtab-control-sponsored[panelShown] {
|
||||
background-position: -281px -1px;
|
||||
}
|
||||
|
@ -100,10 +100,6 @@ menuitem[type="checkbox"].subviewbutton {
|
||||
-moz-padding-start: 0;
|
||||
}
|
||||
|
||||
.subviewbutton.bookmark-item > .toolbarbutton-icon {
|
||||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
/* subviewbutton entries for social sidebars have images that come from external
|
||||
/* sources, and are not guaranteed to be the size we want, so force the size on
|
||||
/* those icons. */
|
||||
|
@ -141,8 +141,6 @@ browser.jar:
|
||||
skin/classic/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
* skin/classic/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/browser/newtab/controls.png (../shared/newtab/controls.png)
|
||||
skin/classic/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
|
||||
skin/classic/browser/newtab/controls.svg (../shared/newtab/controls.svg)
|
||||
skin/classic/browser/places/places.css (places/places.css)
|
||||
* skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||
@ -556,8 +554,6 @@ browser.jar:
|
||||
skin/classic/aero/browser/feeds/subscribe.css (feeds/subscribe.css)
|
||||
skin/classic/aero/browser/feeds/subscribe-ui.css (feeds/subscribe-ui.css)
|
||||
* skin/classic/aero/browser/newtab/newTab.css (newtab/newTab.css)
|
||||
skin/classic/aero/browser/newtab/controls.png (../shared/newtab/controls.png)
|
||||
skin/classic/aero/browser/newtab/controls@2x.png (../shared/newtab/controls@2x.png)
|
||||
skin/classic/aero/browser/newtab/controls.svg (../shared/newtab/controls.svg)
|
||||
* skin/classic/aero/browser/places/places.css (places/places-aero.css)
|
||||
* skin/classic/aero/browser/places/organizer.css (places/organizer-aero.css)
|
||||
|
@ -26,8 +26,10 @@ class MOZ_STACK_CLASS nsViewportInfo
|
||||
{
|
||||
public:
|
||||
nsViewportInfo(const mozilla::ScreenIntSize& aDisplaySize,
|
||||
bool aAllowZoom = true, bool aAllowDoubleTapZoom = true) :
|
||||
mDefaultZoom(1.0),
|
||||
const mozilla::CSSToScreenScale& aDefaultZoom,
|
||||
bool aAllowZoom,
|
||||
bool aAllowDoubleTapZoom) :
|
||||
mDefaultZoom(aDefaultZoom),
|
||||
mAutoSize(true),
|
||||
mAllowZoom(aAllowZoom),
|
||||
mAllowDoubleTapZoom(aAllowDoubleTapZoom)
|
||||
|
@ -7501,15 +7501,27 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
|
||||
nsViewportInfo
|
||||
nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
{
|
||||
nsPresContext* context = mPresShell->GetPresContext();
|
||||
float fullZoom = context ? context->GetFullZoom() : 1.0;
|
||||
fullZoom = (fullZoom == 0.0) ? 1.0 : fullZoom;
|
||||
CSSToScreenScale defaultScale = CSSToLayoutDeviceScale(fullZoom) *
|
||||
LayoutDeviceToScreenScale(1.0);
|
||||
|
||||
// In cases where the width of the CSS viewport is less than or equal to the width
|
||||
// of the display (i.e. width <= device-width) then we disable double-tap-to-zoom
|
||||
// behaviour. See bug 941995 for details.
|
||||
|
||||
switch (mViewportType) {
|
||||
case DisplayWidthHeight:
|
||||
return nsViewportInfo(aDisplaySize);
|
||||
return nsViewportInfo(aDisplaySize,
|
||||
defaultScale,
|
||||
/*allowZoom*/ true,
|
||||
/*allowDoubleTapZoom*/ true);
|
||||
case DisplayWidthHeightNoZoom:
|
||||
return nsViewportInfo(aDisplaySize, /*allowZoom*/ false, /*allowDoubleTapZoom*/ false);
|
||||
return nsViewportInfo(aDisplaySize,
|
||||
defaultScale,
|
||||
/*allowZoom*/ false,
|
||||
/*allowDoubleTapZoom*/ false);
|
||||
case Unknown:
|
||||
{
|
||||
nsAutoString viewport;
|
||||
@ -7529,7 +7541,10 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
{
|
||||
// We're making an assumption that the docType can't change here
|
||||
mViewportType = DisplayWidthHeight;
|
||||
return nsViewportInfo(aDisplaySize, /*allowZoom*/true, /*allowDoubleTapZoom*/false);
|
||||
return nsViewportInfo(aDisplaySize,
|
||||
defaultScale,
|
||||
/*allowZoom*/true,
|
||||
/*allowDoubleTapZoom*/false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7538,7 +7553,10 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
|
||||
if (handheldFriendly.EqualsLiteral("true")) {
|
||||
mViewportType = DisplayWidthHeight;
|
||||
return nsViewportInfo(aDisplaySize, /*allowZoom*/true, /*allowDoubleTapZoom*/false);
|
||||
return nsViewportInfo(aDisplaySize,
|
||||
defaultScale,
|
||||
/*allowZoom*/true,
|
||||
/*allowDoubleTapZoom*/false);
|
||||
}
|
||||
|
||||
// Bug 940036. This is bad. When FirefoxOS was built, apps installed
|
||||
@ -7561,7 +7579,10 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
"ImplicitMetaViewportTagFallback");
|
||||
}
|
||||
mViewportType = DisplayWidthHeightNoZoom;
|
||||
return nsViewportInfo(aDisplaySize, /*allowZoom*/false, /*allowDoubleTapZoom*/false);
|
||||
return nsViewportInfo(aDisplaySize,
|
||||
defaultScale,
|
||||
/*allowZoom*/false,
|
||||
/*allowDoubleTapZoom*/false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7652,8 +7673,11 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
if (mValidHeight && !aDisplaySize.IsEmpty()) {
|
||||
size.width = size.height * aDisplaySize.width / aDisplaySize.height;
|
||||
} else {
|
||||
// Stretch CSS pixel size of viewport to keep device pixel size
|
||||
// unchanged after full zoom applied.
|
||||
// See bug 974242.
|
||||
size.width = Preferences::GetInt("browser.viewport.desktopWidth",
|
||||
kViewportDefaultScreenWidth);
|
||||
kViewportDefaultScreenWidth) / fullZoom;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7664,10 +7688,13 @@ nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
size.height = size.width;
|
||||
}
|
||||
}
|
||||
// Now convert the scale into device pixels per CSS pixel.
|
||||
|
||||
// Now convert the scale into device pixels per CSS pixel base on this formula
|
||||
// CSSPixel x widget scale x full zoom = LayoutDevicePixel
|
||||
nsIWidget *widget = nsContentUtils::WidgetForDocument(this);
|
||||
CSSToLayoutDeviceScale pixelRatio = widget ? widget->GetDefaultScale()
|
||||
: CSSToLayoutDeviceScale(1.0f);
|
||||
CSSToLayoutDeviceScale pixelRatio = CSSToLayoutDeviceScale(
|
||||
(widget ? widget->GetDefaultScale().scale : 1.0f) * fullZoom);
|
||||
|
||||
CSSToScreenScale scaleFloat = mScaleFloat * pixelRatio;
|
||||
CSSToScreenScale scaleMinFloat = mScaleMinFloat * pixelRatio;
|
||||
CSSToScreenScale scaleMaxFloat = mScaleMaxFloat * pixelRatio;
|
||||
|
@ -329,6 +329,13 @@ TabChildBase::HandlePossibleViewportChange(const ScreenIntSize& aOldScreenSize)
|
||||
metrics.SetScrollId(viewId);
|
||||
}
|
||||
|
||||
if (nsIPresShell* shell = document->GetShell()) {
|
||||
if (nsPresContext* context = shell->GetPresContext()) {
|
||||
metrics.mDevPixelsPerCSSPixel = CSSToLayoutDeviceScale(
|
||||
(float)nsPresContext::AppUnitsPerCSSPixel() / context->AppUnitsPerDevPixel());
|
||||
}
|
||||
}
|
||||
|
||||
metrics.mCumulativeResolution = metrics.GetZoom() / metrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
|
||||
// This is the root layer, so the cumulative resolution is the same
|
||||
// as the resolution.
|
||||
@ -758,6 +765,8 @@ TabChild::HandleEvent(nsIDOMEvent* aEvent)
|
||||
// This meta data may or may not have been a meta viewport tag. If it was,
|
||||
// we should handle it immediately.
|
||||
HandlePossibleViewportChange(mInnerSize);
|
||||
} else if (eventType.EqualsLiteral("FullZoomChange")) {
|
||||
HandlePossibleViewportChange(mInnerSize);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -1463,6 +1472,7 @@ TabChild::ActorDestroy(ActorDestroyReason why)
|
||||
(mTabChildGlobal->mMessageManager.get())->Disconnect();
|
||||
mTabChildGlobal->mMessageManager = nullptr;
|
||||
}
|
||||
|
||||
if (Id() != 0) {
|
||||
NestedTabChildMap().erase(Id());
|
||||
}
|
||||
@ -2546,6 +2556,7 @@ TabChild::InitTabChildGlobal(FrameScriptLoading aScriptLoading)
|
||||
root->SetParentTarget(scope);
|
||||
|
||||
chromeHandler->AddEventListener(NS_LITERAL_STRING("DOMMetaAdded"), this, false);
|
||||
chromeHandler->AddEventListener(NS_LITERAL_STRING("FullZoomChange"), this, false);
|
||||
}
|
||||
|
||||
if (aScriptLoading != DONT_LOAD_SCRIPTS && !mTriedBrowserInit) {
|
||||
|
@ -56,6 +56,9 @@ this.SystemMessagePermissionsTable = {
|
||||
"bluetooth-opp-transfer-start": {
|
||||
"bluetooth": []
|
||||
},
|
||||
"cellbroadcast-received": {
|
||||
"cellbroadcast": []
|
||||
},
|
||||
"connection": { },
|
||||
"captive-portal": {
|
||||
"wifi-manage": []
|
||||
|
@ -10,9 +10,8 @@ const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
Cu.import("resource://gre/modules/NetUtil.jsm");
|
||||
Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
|
||||
const RIL_MMSSERVICE_CONTRACTID = "@mozilla.org/mms/rilmmsservice;1";
|
||||
const RIL_MMSSERVICE_CID = Components.ID("{217ddd76-75db-4210-955d-8806cd8d87f9}");
|
||||
@ -54,6 +53,7 @@ const _HTTP_STATUS_USER_CANCELLED = -1;
|
||||
const _HTTP_STATUS_RADIO_DISABLED = -2;
|
||||
const _HTTP_STATUS_NO_SIM_CARD = -3;
|
||||
const _HTTP_STATUS_ACQUIRE_TIMEOUT = -4;
|
||||
const _HTTP_STATUS_FAILED_TO_ROUTE = -5;
|
||||
|
||||
// Non-standard MMS status for internal use.
|
||||
const _MMS_ERROR_MESSAGE_DELETED = -1;
|
||||
@ -63,6 +63,7 @@ const _MMS_ERROR_SIM_CARD_CHANGED = -4;
|
||||
const _MMS_ERROR_SHUTDOWN = -5;
|
||||
const _MMS_ERROR_USER_CANCELLED_NO_REASON = -6;
|
||||
const _MMS_ERROR_SIM_NOT_MATCHED = -7;
|
||||
const _MMS_ERROR_FAILED_TO_ROUTE = -8;
|
||||
|
||||
const CONFIG_SEND_REPORT_NEVER = 0;
|
||||
const CONFIG_SEND_REPORT_DEFAULT_NO = 1;
|
||||
@ -158,6 +159,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "gRil",
|
||||
"@mozilla.org/ril;1",
|
||||
"nsIRadioInterfaceLayer");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager",
|
||||
"@mozilla.org/network/manager;1",
|
||||
"nsINetworkManager");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "MMS", function() {
|
||||
let MMS = {};
|
||||
Cu.import("resource://gre/modules/MmsPduHelper.jsm", MMS);
|
||||
@ -202,6 +207,7 @@ function MmsConnection(aServiceId) {
|
||||
this.serviceId = aServiceId;
|
||||
this.radioInterface = gRil.getRadioInterface(aServiceId);
|
||||
this.pendingCallbacks = [];
|
||||
this.hostsToRoute = [];
|
||||
this.connectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
this.disconnectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
};
|
||||
@ -216,7 +222,8 @@ MmsConnection.prototype = {
|
||||
|
||||
setApnSetting: function(network) {
|
||||
this.mmsc = network.mmsc;
|
||||
this.mmsProxy = network.mmsProxy;
|
||||
// Workaround an xpconnect issue with undefined string objects. See bug 808220.
|
||||
this.mmsProxy = (network === "undefined") ? undefined : network.mmsProxy;
|
||||
this.mmsPort = network.mmsPort;
|
||||
},
|
||||
|
||||
@ -252,6 +259,12 @@ MmsConnection.prototype = {
|
||||
/** MMS network connection reference count. */
|
||||
refCount: 0,
|
||||
|
||||
// cache of hosts to be accessed when this connection is alive.
|
||||
hostsToRoute: null,
|
||||
|
||||
// cache of the networkInterface acquired during this connection.
|
||||
networkInterface: null,
|
||||
|
||||
connectTimer: null,
|
||||
|
||||
disconnectTimer: null,
|
||||
@ -274,9 +287,29 @@ MmsConnection.prototype = {
|
||||
*/
|
||||
onDisconnectTimerTimeout: function() {
|
||||
if (DEBUG) debug("onDisconnectTimerTimeout: deactivate the MMS data call.");
|
||||
if (this.connected) {
|
||||
this.radioInterface.deactivateDataCallByType("mms");
|
||||
|
||||
if (!this.connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
let deactivateMmsDataCall = (aError) => {
|
||||
if (aError) debug("Failed to removeHostRoute: " + aError);
|
||||
|
||||
// Clear cache.
|
||||
this.hostsToRoute = [];
|
||||
this.networkInterface = null;
|
||||
|
||||
this.radioInterface.deactivateDataCallByType("mms");
|
||||
};
|
||||
|
||||
let promises =
|
||||
this.hostsToRoute.map(function(aHost) {
|
||||
return gNetworkManager.removeHostRoute(this.networkInterface, aHost);
|
||||
}, this);
|
||||
|
||||
return Promise.all(promises)
|
||||
.then(() => deactivateMmsDataCall(),
|
||||
(aError) => deactivateMmsDataCall(aError));
|
||||
},
|
||||
|
||||
init: function() {
|
||||
@ -393,6 +426,10 @@ MmsConnection.prototype = {
|
||||
if (DEBUG) debug("acquire: buffer the MMS request and setup the MMS data call.");
|
||||
this.radioInterface.setupDataCallByType("mms");
|
||||
|
||||
// Clear cache when setup new connection.
|
||||
this.hostsToRoute = [];
|
||||
this.networkInterface = null;
|
||||
|
||||
// Set a timer to clear the buffered MMS requests if the
|
||||
// MMS network fails to be connected within a time period.
|
||||
this.connectTimer.
|
||||
@ -429,6 +466,34 @@ MmsConnection.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Helper to ensure the routing of each transaction.
|
||||
*
|
||||
* @param url
|
||||
* Optional url for retrieving mms.
|
||||
*
|
||||
* @return a Promise resolved if added or rejected, otherwise.
|
||||
*/
|
||||
ensureRouting: function(url) {
|
||||
let host = this.mmsProxy;
|
||||
|
||||
if (!this.mmsProxy) {
|
||||
host = url;
|
||||
}
|
||||
|
||||
try {
|
||||
let uri = Services.io.newURI(host, null, null);
|
||||
host = uri.host;
|
||||
} catch (e) {}
|
||||
|
||||
return gNetworkManager.addHostRoute(this.networkInterface, host)
|
||||
.then(() => {
|
||||
if (this.hostsToRoute.indexOf(host) < 0) {
|
||||
this.hostsToRoute.push(host);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
shutdown: function() {
|
||||
Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
|
||||
Services.obs.removeObserver(this, kNetworkConnStateChangedTopic);
|
||||
@ -467,6 +532,8 @@ MmsConnection.prototype = {
|
||||
|
||||
this.connected = connected;
|
||||
if (!this.connected) {
|
||||
this.hostsToRoute = [];
|
||||
this.networkInterface = null;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -474,10 +541,13 @@ MmsConnection.prototype = {
|
||||
// which is going to be used for the HTTP requests later.
|
||||
this.setApnSetting(network);
|
||||
|
||||
// Cache connected network.
|
||||
this.networkInterface = network;
|
||||
|
||||
if (DEBUG) debug("Got the MMS network connected! Resend the buffered " +
|
||||
"MMS requests: number: " + this.pendingCallbacks.length);
|
||||
this.connectTimer.cancel();
|
||||
this.flushPendingCallbacks(_HTTP_STATUS_ACQUIRE_CONNECTION_SUCCESS)
|
||||
this.flushPendingCallbacks(_HTTP_STATUS_ACQUIRE_CONNECTION_SUCCESS);
|
||||
break;
|
||||
}
|
||||
case NS_XPCOM_SHUTDOWN_OBSERVER_ID: {
|
||||
@ -646,13 +716,23 @@ XPCOMUtils.defineLazyGetter(this, "gMmsTransactionHelper", function() {
|
||||
url = mmsConnection.mmsc;
|
||||
}
|
||||
|
||||
if (DEBUG) debug("sendRequest: register proxy filter to " + url);
|
||||
let proxyFilter = new MmsProxyFilter(mmsConnection, url);
|
||||
gpps.registerFilter(proxyFilter, 0);
|
||||
let startTransaction = function () {
|
||||
if (DEBUG) debug("sendRequest: register proxy filter to " + url);
|
||||
let proxyFilter = new MmsProxyFilter(mmsConnection, url);
|
||||
gpps.registerFilter(proxyFilter, 0);
|
||||
|
||||
cancellable.xhr = this.sendHttpRequest(mmsConnection, method,
|
||||
url, istream, proxyFilter,
|
||||
cancellable.done.bind(cancellable));
|
||||
cancellable.xhr = this.sendHttpRequest(mmsConnection, method,
|
||||
url, istream, proxyFilter,
|
||||
cancellable.done.bind(cancellable));
|
||||
}.bind(this);
|
||||
|
||||
mmsConnection.ensureRouting(url)
|
||||
.then(() => startTransaction(),
|
||||
(aError) => {
|
||||
debug("Failed to ensureRouting: " + aError);
|
||||
|
||||
cancellable.done(_HTTP_STATUS_FAILED_TO_ROUTE);
|
||||
});
|
||||
}).bind(this));
|
||||
|
||||
return cancellable;
|
||||
@ -817,6 +897,8 @@ XPCOMUtils.defineLazyGetter(this, "gMmsTransactionHelper", function() {
|
||||
return _MMS_ERROR_RADIO_DISABLED;
|
||||
case _HTTP_STATUS_NO_SIM_CARD:
|
||||
return _MMS_ERROR_NO_SIM_CARD;
|
||||
case _HTTP_STATUS_FAILED_TO_ROUTE:
|
||||
return _MMS_ERROR_FAILED_TO_ROUTE;
|
||||
case HTTP_STATUS_OK:
|
||||
return MMS.MMS_PDU_ERROR_OK;
|
||||
default:
|
||||
|
@ -263,8 +263,8 @@ NfcMessageHandler::InitializeNotification(const Parcel& aParcel, EventOptions& a
|
||||
aOptions.mMajorVersion = aParcel.readInt32();
|
||||
aOptions.mMinorVersion = aParcel.readInt32();
|
||||
|
||||
if (aOptions.mMajorVersion != NFCD_MAJOR_VERSION &&
|
||||
aOptions.mMinorVersion != NFCD_MAJOR_VERSION) {
|
||||
if (aOptions.mMajorVersion != NFCD_MAJOR_VERSION ||
|
||||
aOptions.mMinorVersion != NFCD_MINOR_VERSION) {
|
||||
CHROMIUM_LOG("NFCD version mismatched. majorVersion: %d, minorVersion: %d",
|
||||
aOptions.mMajorVersion, aOptions.mMinorVersion);
|
||||
}
|
||||
|
@ -22,39 +22,6 @@ this.DEBUG_ALL = false;
|
||||
this.DEBUG_CONTENT_HELPER = false || DEBUG_ALL;
|
||||
this.DEBUG_NFC = false || DEBUG_ALL;
|
||||
|
||||
// Current version
|
||||
this.NFC_MAJOR_VERSION = 1;
|
||||
this.NFC_MINOR_VERSION = 7;
|
||||
|
||||
this.NFC_REQUEST_CONFIG = 0;
|
||||
this.NFC_REQUEST_CONNECT = 1;
|
||||
this.NFC_REQUEST_CLOSE = 2;
|
||||
this.NFC_REQUEST_GET_DETAILS = 3;
|
||||
this.NFC_REQUEST_READ_NDEF = 4;
|
||||
this.NFC_REQUEST_WRITE_NDEF = 5;
|
||||
this.NFC_REQUEST_MAKE_NDEF_READ_ONLY = 6;
|
||||
|
||||
this.NFC_RESPONSE_GENERAL = 1000;
|
||||
this.NFC_RESPONSE_CONFIG = 1001;
|
||||
this.NFC_RESPONSE_READ_NDEF_DETAILS = 1002;
|
||||
this.NFC_RESPONSE_READ_NDEF = 1003;
|
||||
|
||||
this.NFC_NOTIFICATION_INITIALIZED = 2000;
|
||||
this.NFC_NOTIFICATION_TECH_DISCOVERED = 2001;
|
||||
this.NFC_NOTIFICATION_TECH_LOST = 2002;
|
||||
|
||||
this.NFC_TECHS = {
|
||||
0:"NDEF",
|
||||
1:"NDEF_WRITEABLE",
|
||||
2:"NDEF_FORMATABLE",
|
||||
3:"P2P",
|
||||
4:"NFC_A",
|
||||
5:"NFC_B",
|
||||
6:"NFC_F",
|
||||
7:"NFC_V",
|
||||
8:"NFC_ISO_DEP"
|
||||
};
|
||||
|
||||
// nfcd error codes
|
||||
this.NFC_SUCCESS = 0;
|
||||
this.NFC_ERROR_IO = -1;
|
||||
|
@ -340,12 +340,6 @@ NetworkManager.prototype = {
|
||||
gNetworkService.removeDefaultRoute(network);
|
||||
this.setAndConfigureActive();
|
||||
#ifdef MOZ_B2G_RIL
|
||||
// Resolve and add extra host route. For example, mms proxy or mmsc.
|
||||
// IMPORTANT: The offline state of DNSService will be set implicitly in
|
||||
// setAndConfigureActive() by modifying Services.io.offline.
|
||||
// Always setExtraHostRoute() after setAndConfigureActive().
|
||||
this.setExtraHostRoute(network);
|
||||
|
||||
// Update data connection when Wifi connected/disconnected
|
||||
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_WIFI) {
|
||||
for (let i = 0; i < this.mRil.numRadioInterfaces; i++) {
|
||||
@ -366,8 +360,7 @@ NetworkManager.prototype = {
|
||||
if (this.isNetworkTypeMobile(network.type)) {
|
||||
this.removeHostRoutes(network);
|
||||
}
|
||||
// Remove extra host route. For example, mms proxy or mmsc.
|
||||
this.removeExtraHostRoute(network);
|
||||
|
||||
// Remove secondary default route for dun.
|
||||
if (network.type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_DUN) {
|
||||
this.removeSecondaryDefaultRoute(network);
|
||||
@ -455,6 +448,56 @@ NetworkManager.prototype = {
|
||||
this.setAndConfigureActive();
|
||||
},
|
||||
|
||||
_updateRoutes: function(doAdd, ipAddresses, networkName, gateways) {
|
||||
let promises = [];
|
||||
|
||||
ipAddresses.forEach((aIpAddress) => {
|
||||
let gateway = this.selectGateway(gateways, aIpAddress);
|
||||
if (gateway) {
|
||||
promises.push((doAdd)
|
||||
? gNetworkService.addHostRoute(networkName, gateway, aIpAddress)
|
||||
: gNetworkService.removeHostRoute(networkName, gateway, aIpAddress));
|
||||
}
|
||||
});
|
||||
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
isValidatedNetwork: function(network) {
|
||||
let isValid = false;
|
||||
try {
|
||||
isValid = (this.getNetworkId(network) in this.networkInterfaces);
|
||||
} catch (e) {
|
||||
debug("Invalid network interface: " + e);
|
||||
}
|
||||
|
||||
return isValid;
|
||||
},
|
||||
|
||||
addHostRoute: function(network, host) {
|
||||
if (!this.isValidatedNetwork(network)) {
|
||||
return Promise.reject("Invalid network interface.");
|
||||
}
|
||||
|
||||
return this.resolveHostname(host)
|
||||
.then((ipAddresses) => this._updateRoutes(true,
|
||||
ipAddresses,
|
||||
network.name,
|
||||
network.getGateways()));
|
||||
},
|
||||
|
||||
removeHostRoute: function(network, host) {
|
||||
if (!this.isValidatedNetwork(network)) {
|
||||
return Promise.reject("Invalid network interface.");
|
||||
}
|
||||
|
||||
return this.resolveHostname(host)
|
||||
.then((ipAddresses) => this._updateRoutes(false,
|
||||
ipAddresses,
|
||||
network.name,
|
||||
network.getGateways()));
|
||||
},
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
isNetworkTypeSecondaryMobile: function(type) {
|
||||
return (type == Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS ||
|
||||
@ -470,35 +513,16 @@ NetworkManager.prototype = {
|
||||
|
||||
setHostRoutes: function(network) {
|
||||
let hosts = network.getDnses().concat(network.httpProxyHost);
|
||||
let gateways = network.getGateways();
|
||||
let promises = [];
|
||||
|
||||
for (let i = 0; i < hosts.length; i++) {
|
||||
let host = hosts[i];
|
||||
let gateway = this.selectGateway(gateways, host);
|
||||
if (gateway && host) {
|
||||
promises.push(gNetworkService.addHostRoute(network.name, gateway, host));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
return this._updateRoutes(true, hosts, network.name, network.getGateways());
|
||||
},
|
||||
|
||||
removeHostRoutes: function(network) {
|
||||
let hosts = network.getDnses().concat(network.httpProxyHost);
|
||||
let gateways = network.getGateways();
|
||||
let promises = [];
|
||||
|
||||
for (let i = 0; i < hosts.length; i++) {
|
||||
let host = hosts[i];
|
||||
let gateway = this.selectGateway(gateways, host);
|
||||
if (gateway && host) {
|
||||
promises.push(gNetworkService.removeHostRoute(network.name, gateway, host));
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
return this._updateRoutes(false, hosts, network.name, network.getGateways());
|
||||
},
|
||||
#endif
|
||||
|
||||
selectGateway: function(gateways, host) {
|
||||
for (let i = 0; i < gateways.length; i++) {
|
||||
@ -511,88 +535,7 @@ NetworkManager.prototype = {
|
||||
return null;
|
||||
},
|
||||
|
||||
setExtraHostRoute: function(network) {
|
||||
if (network.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!(network instanceof Ci.nsIRilNetworkInterface)) {
|
||||
let errorMsg = "Network for MMS must be an instance of " +
|
||||
"nsIRilNetworkInterface";
|
||||
debug(errorMsg);
|
||||
return Promise.reject(errorMsg);
|
||||
}
|
||||
|
||||
network = network.QueryInterface(Ci.nsIRilNetworkInterface);
|
||||
|
||||
debug("Adding mmsproxy and/or mmsc route for " + network.name);
|
||||
|
||||
let hostToResolve = network.mmsProxy;
|
||||
// Workaround an xpconnect issue with undefined string objects.
|
||||
// See bug 808220
|
||||
if (!hostToResolve || hostToResolve === "undefined") {
|
||||
hostToResolve = network.mmsc;
|
||||
}
|
||||
|
||||
let mmsHosts = this.resolveHostname([hostToResolve]);
|
||||
if (mmsHosts.length == 0) {
|
||||
let errorMsg = "No valid hostnames can be added. Stop adding host route.";
|
||||
debug(errorMsg);
|
||||
return Promise.reject(errorMsg);
|
||||
}
|
||||
|
||||
let gateways = network.getGateways();
|
||||
let promises = [];
|
||||
for (let i = 0; i < mmsHosts.length; i++) {
|
||||
let gateway = this.selectGateway(gateways, mmsHosts[i]);
|
||||
if (gateway) {
|
||||
promises.push(gNetworkService.addHostRoute(network.name, gateway,
|
||||
mmsHosts[i]));
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
removeExtraHostRoute: function(network) {
|
||||
if (network.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE_MMS) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (!(network instanceof Ci.nsIRilNetworkInterface)) {
|
||||
let errorMsg = "Network for MMS must be an instance of " +
|
||||
"nsIRilNetworkInterface";
|
||||
debug(errorMsg);
|
||||
return Promise.reject(errorMsg);
|
||||
}
|
||||
|
||||
network = network.QueryInterface(Ci.nsIRilNetworkInterface);
|
||||
|
||||
debug("Removing mmsproxy and/or mmsc route for " + network.name);
|
||||
|
||||
let hostToResolve = network.mmsProxy;
|
||||
// Workaround an xpconnect issue with undefined string objects.
|
||||
// See bug 808220
|
||||
if (!hostToResolve || hostToResolve === "undefined") {
|
||||
hostToResolve = network.mmsc;
|
||||
}
|
||||
|
||||
let mmsHosts = this.resolveHostname([hostToResolve]);
|
||||
if (mmsHosts.length == 0) {
|
||||
let errorMsg = "No valid hostnames can be removed. Stop removing host route.";
|
||||
debug(errorMsg);
|
||||
return Promise.reject(errorMsg);
|
||||
}
|
||||
|
||||
let gateways = network.getGateways();
|
||||
let promises = [];
|
||||
for (let i = 0; i < mmsHosts.length; i++) {
|
||||
let gateway = this.selectGateway(gateways, mmsHosts[i]);
|
||||
if (gateway) {
|
||||
promises.push(gNetworkService.removeHostRoute(network.name, gateway,
|
||||
mmsHosts[i]));
|
||||
}
|
||||
}
|
||||
return Promise.all(promises);
|
||||
},
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
setSecondaryDefaultRoute: function(network) {
|
||||
let gateways = network.getGateways();
|
||||
for (let i = 0; i < gateways.length; i++) {
|
||||
@ -713,43 +656,46 @@ NetworkManager.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
#ifdef MOZ_B2G_RIL
|
||||
resolveHostname: function(hosts) {
|
||||
let retval = [];
|
||||
|
||||
for (let hostname of hosts) {
|
||||
// Sanity check for null, undefined and empty string... etc.
|
||||
if (!hostname) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
let uri = Services.io.newURI(hostname, null, null);
|
||||
hostname = uri.host;
|
||||
} catch (e) {}
|
||||
|
||||
// An extra check for hostnames that cannot be made by newURI(...).
|
||||
// For example, an IP address like "10.1.1.1".
|
||||
if (hostname.match(this.REGEXP_IPV4) ||
|
||||
hostname.match(this.REGEXP_IPV6)) {
|
||||
retval.push(hostname);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
let hostnameIps = gDNSService.resolve(hostname, 0);
|
||||
while (hostnameIps.hasMore()) {
|
||||
retval.push(hostnameIps.getNextAddrAsString());
|
||||
debug("Found IP at: " + JSON.stringify(retval));
|
||||
}
|
||||
} catch (e) {
|
||||
debug("Failed to resolve '" + hostname + "', exception: " + e);
|
||||
}
|
||||
resolveHostname: function(hostname) {
|
||||
// Sanity check for null, undefined and empty string... etc.
|
||||
if (!hostname) {
|
||||
return Promise.reject(new Error("hostname is empty: " + hostname));
|
||||
}
|
||||
|
||||
return retval;
|
||||
if (hostname.match(this.REGEXP_IPV4) ||
|
||||
hostname.match(this.REGEXP_IPV6)) {
|
||||
return Promise.resolve([hostname]);
|
||||
}
|
||||
|
||||
let deferred = Promise.defer();
|
||||
let onLookupComplete = (aRequest, aRecord, aStatus) => {
|
||||
if (!Components.isSuccessCode(aStatus)) {
|
||||
deferred.reject(new Error(
|
||||
"Failed to resolve '" + hostname + "', with status: " + aStatus));
|
||||
return;
|
||||
}
|
||||
|
||||
let retval = [];
|
||||
while (aRecord.hasMore()) {
|
||||
retval.push(aRecord.getNextAddrAsString());
|
||||
}
|
||||
|
||||
if (!retval.length) {
|
||||
deferred.reject(new Error("No valid address after DNS lookup!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) debug("hostname is resolved: " + hostname);
|
||||
if (DEBUG) debug("Addresses: " + JSON.stringify(retval));
|
||||
|
||||
deferred.resolve(retval);
|
||||
};
|
||||
|
||||
// TODO: Bug 992772 - Resolve the hostname with specified networkInterface.
|
||||
gDNSService.asyncResolve(hostname, 0, onLookupComplete, Services.tm.mainThread);
|
||||
|
||||
return deferred.promise;
|
||||
},
|
||||
#endif
|
||||
|
||||
convertConnectionType: function(network) {
|
||||
// If there is internal interface change (e.g., MOBILE_MMS, MOBILE_SUPL),
|
||||
|
@ -2284,6 +2284,7 @@ RadioInterface.prototype = {
|
||||
break;
|
||||
case "cellbroadcast-received":
|
||||
message.timestamp = Date.now();
|
||||
this.broadcastCbsSystemMessage(message);
|
||||
gMessageManager.sendCellBroadcastMessage("RIL:CellBroadcastReceived",
|
||||
this.clientId, message);
|
||||
break;
|
||||
@ -3310,6 +3311,48 @@ 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".
|
||||
*/
|
||||
|
@ -97,7 +97,7 @@ interface nsINetworkInterface : nsISupports
|
||||
/**
|
||||
* Manage network interfaces.
|
||||
*/
|
||||
[scriptable, uuid(f3193805-c070-4d23-bd5c-a439eb8610c3)]
|
||||
[scriptable, uuid(19822018-2454-11e4-baa7-2b5894f0af6f)]
|
||||
interface nsINetworkManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -196,4 +196,34 @@ interface nsINetworkManager : nsISupports
|
||||
in nsINetworkInterface networkInterface,
|
||||
in jsval config,
|
||||
in nsIWifiTetheringCallback callback);
|
||||
|
||||
/**
|
||||
* Add host route to the specified network into routing table.
|
||||
*
|
||||
* @param network
|
||||
* The network interface where the host to be routed to.
|
||||
* @param host
|
||||
* The host to be added.
|
||||
* The host will be resolved in advance if it's not an ip-address.
|
||||
*
|
||||
* @return a Promise
|
||||
* resolved if added; rejected, otherwise.
|
||||
*/
|
||||
jsval addHostRoute(in nsINetworkInterface network,
|
||||
in DOMString host);
|
||||
|
||||
/**
|
||||
* Remove host route to the specified network from routing table.
|
||||
*
|
||||
* @param network
|
||||
* The network interface where the routing to be removed from.
|
||||
* @param host
|
||||
* The host routed to the network.
|
||||
* The host will be resolved in advance if it's not an ip-address.
|
||||
*
|
||||
* @return a Promise
|
||||
* resolved if removed; rejected, otherwise.
|
||||
*/
|
||||
jsval removeHostRoute(in nsINetworkInterface network,
|
||||
in DOMString host);
|
||||
};
|
||||
|
@ -2529,78 +2529,106 @@ RilObject.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
_serviceCodeToKeyString: function(serviceCode) {
|
||||
switch (serviceCode) {
|
||||
case MMI_SC_CFU:
|
||||
case MMI_SC_CF_BUSY:
|
||||
case MMI_SC_CF_NO_REPLY:
|
||||
case MMI_SC_CF_NOT_REACHABLE:
|
||||
case MMI_SC_CF_ALL:
|
||||
case MMI_SC_CF_ALL_CONDITIONAL:
|
||||
return MMI_KS_SC_CALL_FORWARDING;
|
||||
case MMI_SC_PIN:
|
||||
return MMI_KS_SC_PIN;
|
||||
case MMI_SC_PIN2:
|
||||
return MMI_KS_SC_PIN2;
|
||||
case MMI_SC_PUK:
|
||||
return MMI_KS_SC_PUK;
|
||||
case MMI_SC_PUK2:
|
||||
return MMI_KS_SC_PUK2;
|
||||
case MMI_SC_IMEI:
|
||||
return MMI_KS_SC_IMEI;
|
||||
case MMI_SC_CLIP:
|
||||
return MMI_KS_SC_CLIP;
|
||||
case MMI_SC_CLIR:
|
||||
return MMI_KS_SC_CLIR;
|
||||
case MMI_SC_BAOC:
|
||||
case MMI_SC_BAOIC:
|
||||
case MMI_SC_BAOICxH:
|
||||
case MMI_SC_BAIC:
|
||||
case MMI_SC_BAICr:
|
||||
case MMI_SC_BA_ALL:
|
||||
case MMI_SC_BA_MO:
|
||||
case MMI_SC_BA_MT:
|
||||
return MMI_KS_SC_CALL_BARRING;
|
||||
case MMI_SC_CALL_WAITING:
|
||||
return MMI_SC_CALL_WAITING;
|
||||
default:
|
||||
return MMI_KS_SC_USSD;
|
||||
}
|
||||
},
|
||||
|
||||
sendMMI: function(options) {
|
||||
if (DEBUG) {
|
||||
this.context.debug("SendMMI " + JSON.stringify(options));
|
||||
}
|
||||
let mmiString = options.mmi;
|
||||
let mmi = this._parseMMI(mmiString);
|
||||
|
||||
let _sendMMIError = (function(errorMsg, mmiServiceCode) {
|
||||
let mmi = this._parseMMI(options.mmi);
|
||||
if (DEBUG) {
|
||||
this.context.debug("MMI " + JSON.stringify(mmi));
|
||||
}
|
||||
|
||||
let _sendMMIError = (function(errorMsg) {
|
||||
options.success = false;
|
||||
options.errorMsg = errorMsg;
|
||||
if (mmiServiceCode) {
|
||||
options.mmiServiceCode = mmiServiceCode;
|
||||
}
|
||||
this.sendChromeMessage(options);
|
||||
}).bind(this);
|
||||
|
||||
function _isValidPINPUKRequest(mmiServiceCode) {
|
||||
// It's neither a valid mmi code nor an ongoing ussd.
|
||||
if (!mmi && !this._ussdSession) {
|
||||
_sendMMIError(MMI_ERROR_KS_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
options.mmiServiceCode = mmi ?
|
||||
this._serviceCodeToKeyString(mmi.serviceCode) : MMI_KS_SC_USSD;
|
||||
|
||||
function _isValidPINPUKRequest() {
|
||||
// The only allowed MMI procedure for ICC PIN, PIN2, PUK and PUK2 handling
|
||||
// is "Registration" (**).
|
||||
if (!mmi.procedure || mmi.procedure != MMI_PROCEDURE_REGISTRATION ) {
|
||||
_sendMMIError(MMI_ERROR_KS_INVALID_ACTION, mmiServiceCode);
|
||||
if (mmi.procedure != MMI_PROCEDURE_REGISTRATION ) {
|
||||
_sendMMIError(MMI_ERROR_KS_INVALID_ACTION);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mmi.sia || !mmi.sia.length || !mmi.sib || !mmi.sib.length ||
|
||||
!mmi.sic || !mmi.sic.length) {
|
||||
_sendMMIError(MMI_ERROR_KS_ERROR, mmiServiceCode);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mmi.sib != mmi.sic) {
|
||||
_sendMMIError(MMI_ERROR_KS_MISMATCH_PIN, mmiServiceCode);
|
||||
if (!mmi.sia || !mmi.sib || !mmi.sic) {
|
||||
_sendMMIError(MMI_ERROR_KS_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mmi.sia.length < 4 || mmi.sia.length > 8 ||
|
||||
mmi.sib.length < 4 || mmi.sib.length > 8 ||
|
||||
mmi.sic.length < 4 || mmi.sic.length > 8) {
|
||||
_sendMMIError(MMI_ERROR_KS_INVALID_PIN, mmiServiceCode);
|
||||
_sendMMIError(MMI_ERROR_KS_INVALID_PIN);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mmi.sib != mmi.sic) {
|
||||
_sendMMIError(MMI_ERROR_KS_MISMATCH_PIN);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
let _isRadioAvailable = (function(mmiServiceCode) {
|
||||
let _isRadioAvailable = (function() {
|
||||
if (this.radioState !== GECKO_RADIOSTATE_READY) {
|
||||
_sendMMIError(GECKO_ERROR_RADIO_NOT_AVAILABLE, mmiServiceCode);
|
||||
_sendMMIError(GECKO_ERROR_RADIO_NOT_AVAILABLE);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}).bind(this);
|
||||
|
||||
// If we couldn't parse the MMI code, we'll send it as an USSD request.
|
||||
if (mmi === null) {
|
||||
if (this._ussdSession) {
|
||||
if (!_isRadioAvailable(MMI_KS_SC_USSD)) {
|
||||
return;
|
||||
}
|
||||
options.ussd = mmiString;
|
||||
this.sendUSSD(options);
|
||||
return;
|
||||
}
|
||||
|
||||
_sendMMIError(MMI_ERROR_KS_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
this.context.debug("MMI " + JSON.stringify(mmi));
|
||||
}
|
||||
|
||||
// We check if the MMI service code is supported and in that case we
|
||||
// trigger the appropriate RIL request if possible.
|
||||
let sc = mmi.serviceCode;
|
||||
@ -2612,14 +2640,13 @@ RilObject.prototype = {
|
||||
case MMI_SC_CF_NOT_REACHABLE:
|
||||
case MMI_SC_CF_ALL:
|
||||
case MMI_SC_CF_ALL_CONDITIONAL:
|
||||
if (!_isRadioAvailable(MMI_KS_SC_CALL_FORWARDING)) {
|
||||
if (!_isRadioAvailable()) {
|
||||
return;
|
||||
}
|
||||
// Call forwarding requires at least an action, given by the MMI
|
||||
// procedure, and a reason, given by the MMI service code, but there
|
||||
// is no way that we get this far without a valid procedure or service
|
||||
// code.
|
||||
options.mmiServiceCode = MMI_KS_SC_CALL_FORWARDING;
|
||||
options.action = MMI_PROC_TO_CF_ACTION[mmi.procedure];
|
||||
options.reason = MMI_SC_TO_CF_REASON[sc];
|
||||
options.number = mmi.sia;
|
||||
@ -2640,12 +2667,10 @@ RilObject.prototype = {
|
||||
// an MMI code of the form **04*OLD_PIN*NEW_PIN*NEW_PIN#, where old PIN
|
||||
// should be entered as the SIA parameter and the new PIN as SIB and
|
||||
// SIC.
|
||||
if (!_isRadioAvailable(MMI_KS_SC_PIN) ||
|
||||
!_isValidPINPUKRequest(MMI_KS_SC_PIN)) {
|
||||
if (!_isRadioAvailable() || !_isValidPINPUKRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.mmiServiceCode = MMI_KS_SC_PIN;
|
||||
options.pin = mmi.sia;
|
||||
options.newPin = mmi.sib;
|
||||
this.changeICCPIN(options);
|
||||
@ -2657,12 +2682,10 @@ RilObject.prototype = {
|
||||
// enter and MMI code of the form **042*OLD_PIN2*NEW_PIN2*NEW_PIN2#,
|
||||
// where the old PIN2 should be entered as the SIA parameter and the
|
||||
// new PIN2 as SIB and SIC.
|
||||
if (!_isRadioAvailable(MMI_KS_SC_PIN2) ||
|
||||
!_isValidPINPUKRequest(MMI_KS_SC_PIN2)) {
|
||||
if (!_isRadioAvailable() || !_isValidPINPUKRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.mmiServiceCode = MMI_KS_SC_PIN2;
|
||||
options.pin = mmi.sia;
|
||||
options.newPin = mmi.sib;
|
||||
this.changeICCPIN2(options);
|
||||
@ -2674,12 +2697,10 @@ RilObject.prototype = {
|
||||
// enter an MMI code of the form **05*PUK*NEW_PIN*NEW_PIN#, where PUK
|
||||
// should be entered as the SIA parameter and the new PIN as SIB and
|
||||
// SIC.
|
||||
if (!_isRadioAvailable(MMI_KS_SC_PUK) ||
|
||||
!_isValidPINPUKRequest(MMI_KS_SC_PUK)) {
|
||||
if (!_isRadioAvailable() || !_isValidPINPUKRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.mmiServiceCode = MMI_KS_SC_PUK;
|
||||
options.puk = mmi.sia;
|
||||
options.newPin = mmi.sib;
|
||||
this.enterICCPUK(options);
|
||||
@ -2691,12 +2712,10 @@ RilObject.prototype = {
|
||||
// enter an MMI code of the form **052*PUK2*NEW_PIN2*NEW_PIN2#, where
|
||||
// PUK2 should be entered as the SIA parameter and the new PIN2 as SIB
|
||||
// and SIC.
|
||||
if (!_isRadioAvailable(MMI_KS_SC_PUK2) ||
|
||||
!_isValidPINPUKRequest(MMI_KS_SC_PUK2)) {
|
||||
if (!_isRadioAvailable() || !_isValidPINPUKRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.mmiServiceCode = MMI_KS_SC_PUK2;
|
||||
options.puk = mmi.sia;
|
||||
options.newPin = mmi.sib;
|
||||
this.enterICCPUK2(options);
|
||||
@ -2710,7 +2729,6 @@ RilObject.prototype = {
|
||||
return;
|
||||
}
|
||||
// If we already had the device's IMEI, we just send it to chrome.
|
||||
options.mmiServiceCode = MMI_KS_SC_IMEI;
|
||||
options.success = true;
|
||||
options.statusMessage = this.IMEI;
|
||||
this.sendChromeMessage(options);
|
||||
@ -2718,12 +2736,11 @@ RilObject.prototype = {
|
||||
|
||||
// CLIP
|
||||
case MMI_SC_CLIP:
|
||||
options.mmiServiceCode = MMI_KS_SC_CLIP;
|
||||
options.procedure = mmi.procedure;
|
||||
if (options.procedure === MMI_PROCEDURE_INTERROGATION) {
|
||||
this.queryCLIP(options);
|
||||
} else {
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED, MMI_KS_SC_CLIP);
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
|
||||
}
|
||||
return;
|
||||
|
||||
@ -2732,7 +2749,6 @@ RilObject.prototype = {
|
||||
// point in the future. In the mean time we handle temporary CLIR MMI
|
||||
// commands through the dial() function. Please see bug 889737.
|
||||
case MMI_SC_CLIR:
|
||||
options.mmiServiceCode = MMI_KS_SC_CLIR;
|
||||
options.procedure = mmi.procedure;
|
||||
switch (options.procedure) {
|
||||
case MMI_PROCEDURE_INTERROGATION:
|
||||
@ -2745,7 +2761,7 @@ RilObject.prototype = {
|
||||
options.clirMode = CLIR_SUPPRESSION;
|
||||
break;
|
||||
default:
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED, MMI_KS_SC_CLIR);
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
options.isSetCLIR = true;
|
||||
@ -2761,7 +2777,6 @@ RilObject.prototype = {
|
||||
case MMI_SC_BA_ALL:
|
||||
case MMI_SC_BA_MO:
|
||||
case MMI_SC_BA_MT:
|
||||
options.mmiServiceCode = MMI_KS_SC_CALL_BARRING;
|
||||
options.password = mmi.sia || "";
|
||||
options.serviceClass = this._siToServiceClass(mmi.sib);
|
||||
options.facility = MMI_SC_TO_CB_FACILITY[sc];
|
||||
@ -2775,7 +2790,7 @@ RilObject.prototype = {
|
||||
} else if (mmi.procedure === MMI_PROCEDURE_DEACTIVATION) {
|
||||
options.enabled = 0;
|
||||
} else {
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED, MMI_KS_SC_CALL_BARRING);
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
this.setICCFacilityLock(options);
|
||||
@ -2783,11 +2798,10 @@ RilObject.prototype = {
|
||||
|
||||
// Call waiting
|
||||
case MMI_SC_CALL_WAITING:
|
||||
if (!_isRadioAvailable(MMI_KS_SC_CALL_WAITING)) {
|
||||
if (!_isRadioAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.mmiServiceCode = MMI_KS_SC_CALL_WAITING;
|
||||
|
||||
if (mmi.procedure === MMI_PROCEDURE_INTERROGATION) {
|
||||
this._handleQueryMMICallWaiting(options);
|
||||
@ -2799,7 +2813,7 @@ RilObject.prototype = {
|
||||
} else if (mmi.procedure === MMI_PROCEDURE_DEACTIVATION) {
|
||||
options.enabled = false;
|
||||
} else {
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED, MMI_KS_SC_CALL_WAITING);
|
||||
_sendMMIError(MMI_ERROR_KS_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2808,22 +2822,13 @@ RilObject.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the MMI code is not a known code and is a recognized USSD request,
|
||||
// it shall still be sent as a USSD request.
|
||||
if (mmi.fullMMI) {
|
||||
if (!_isRadioAvailable(MMI_KS_SC_USSD)) {
|
||||
return;
|
||||
}
|
||||
|
||||
options.ussd = mmi.fullMMI;
|
||||
options.mmiServiceCode = MMI_KS_SC_USSD;
|
||||
this.sendUSSD(options);
|
||||
// If the MMI code is not a known code, it is treated as an ussd.
|
||||
if (!_isRadioAvailable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// At this point, the MMI string is considered as not valid MMI code and
|
||||
// not valid USSD code.
|
||||
_sendMMIError(MMI_ERROR_KS_ERROR);
|
||||
options.ussd = mmi.fullMMI;
|
||||
this.sendUSSD(options);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2844,7 +2849,6 @@ RilObject.prototype = {
|
||||
* Cancel pending USSD.
|
||||
*/
|
||||
cancelUSSD: function(options) {
|
||||
options.mmiServiceCode = MMI_KS_SC_USSD;
|
||||
this.context.Buf.simpleRequest(REQUEST_CANCEL_USSD, options);
|
||||
},
|
||||
|
||||
@ -6056,7 +6060,6 @@ RilObject.prototype[REQUEST_GET_IMEI] = function REQUEST_GET_IMEI(length, option
|
||||
return;
|
||||
}
|
||||
|
||||
options.mmiServiceCode = MMI_KS_SC_IMEI;
|
||||
options.success = (options.rilRequestError === 0);
|
||||
options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError];
|
||||
if ((!options.success || this.IMEI == null) && !options.errorMsg) {
|
||||
@ -14174,9 +14177,8 @@ SimRecordHelperObject.prototype = {
|
||||
ICCIOHelper.loadNextRecord(options);
|
||||
} else {
|
||||
RIL.iccInfoPrivate.OPL = opl;
|
||||
RIL.overrideICCNetworkName();
|
||||
}
|
||||
|
||||
RIL.overrideICCNetworkName();
|
||||
}
|
||||
|
||||
ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_OPL,
|
||||
@ -14245,9 +14247,8 @@ SimRecordHelperObject.prototype = {
|
||||
}
|
||||
}
|
||||
RIL.iccInfoPrivate.PNN = pnn;
|
||||
RIL.overrideICCNetworkName();
|
||||
}
|
||||
|
||||
RIL.overrideICCNetworkName();
|
||||
}
|
||||
|
||||
let pnn = [];
|
||||
|
@ -459,6 +459,19 @@ TelephonyService.prototype = {
|
||||
return hasConference ? numCalls + 1 : numCalls;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get arbitrary one of active call.
|
||||
*/
|
||||
_getOneActiveCall: function(aClientId) {
|
||||
for (let index in this._currentCalls[aClientId]) {
|
||||
let call = this._currentCalls[aClientId][index];
|
||||
if (call.state === nsITelephonyService.CALL_STATE_CONNECTED) {
|
||||
return call;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
_addCdmaChildCall: function(aClientId, aNumber, aParentId) {
|
||||
let childCall = {
|
||||
callIndex: CDMA_SECOND_CALL_INDEX,
|
||||
@ -509,6 +522,7 @@ TelephonyService.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
cachedDialRequest: null,
|
||||
isDialing: false,
|
||||
|
||||
dial: function(aClientId, aNumber, aIsDialEmergency, aCallback) {
|
||||
@ -563,7 +577,25 @@ TelephonyService.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
this._dialInternal(aClientId, options, aCallback);
|
||||
// Before we dial, we have to hold the active call first.
|
||||
let activeCall = this._getOneActiveCall(aClientId);
|
||||
if (!activeCall) {
|
||||
this._dialInternal(aClientId, options, aCallback);
|
||||
} else {
|
||||
if (DEBUG) debug("There is an active call. Hold it first before dial.");
|
||||
|
||||
this.cachedDialRequest = {
|
||||
clientId: aClientId,
|
||||
options: options,
|
||||
callback: aCallback
|
||||
};
|
||||
|
||||
if (activeCall.isConference) {
|
||||
this.holdConference(aClientId);
|
||||
} else {
|
||||
this.holdCall(aClientId, activeCall.callIndex);
|
||||
}
|
||||
}
|
||||
}, cause => {
|
||||
aCallback.notifyDialError(DIAL_ERROR_BAD_NUMBER);
|
||||
});
|
||||
@ -588,7 +620,7 @@ TelephonyService.prototype = {
|
||||
} else {
|
||||
// RIL doesn't hold the 2nd call. We create one by ourselves.
|
||||
aCallback.notifyDialSuccess(CDMA_SECOND_CALL_INDEX, response.number);
|
||||
this._addCdmaChildCall(aClientId, aNumber, currentCdmaCallIndex);
|
||||
this._addCdmaChildCall(aClientId, response.number, currentCdmaCallIndex);
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -899,6 +931,15 @@ TelephonyService.prototype = {
|
||||
this._currentCalls[aClientId][aCall.callIndex] = call;
|
||||
}
|
||||
|
||||
// Handle cached dial request.
|
||||
if (this.cachedDialRequest && !this._getOneActiveCall()) {
|
||||
if (DEBUG) debug("All calls held. Perform the cached dial request.");
|
||||
|
||||
let request = this.cachedDialRequest;
|
||||
this._dialInternal(request.clientId, request.options, request.callback);
|
||||
this.cachedDialRequest = null;
|
||||
}
|
||||
|
||||
this._notifyAllListeners("callStateChanged", [aClientId,
|
||||
call.callIndex,
|
||||
call.state,
|
||||
|
@ -64,3 +64,4 @@ disabled = Bug 821958
|
||||
[test_temporary_clir.js]
|
||||
[test_outgoing_error_state.js]
|
||||
[test_mmi_code.js]
|
||||
[test_outgoing_auto_hold.js]
|
||||
|
52
dom/telephony/test/marionette/test_outgoing_auto_hold.js
Normal file
@ -0,0 +1,52 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
MARIONETTE_TIMEOUT = 60000;
|
||||
MARIONETTE_HEAD_JS = 'head.js';
|
||||
|
||||
function testAutoHoldCall() {
|
||||
let outCall1;
|
||||
let outCall2;
|
||||
|
||||
return gDial("0900000001")
|
||||
.then(call => { outCall1 = call; })
|
||||
.then(() => gRemoteAnswer(outCall1))
|
||||
.then(() => {
|
||||
is(outCall1.state, "connected");
|
||||
})
|
||||
.then(() => gDial("0900000002"))
|
||||
.then(call => { outCall2 = call; })
|
||||
.then(() => {
|
||||
is(outCall1.state, "held");
|
||||
})
|
||||
.then(() => gRemoteHangUpCalls([outCall1, outCall2]));
|
||||
}
|
||||
|
||||
function testAutoHoldConferenceCall() {
|
||||
let subCall1;
|
||||
let subCall2;
|
||||
let outCall;
|
||||
|
||||
return gSetupConference(["0900000001", "0900000002"])
|
||||
.then(calls => {
|
||||
[subCall1, subCall2] = calls;
|
||||
is(conference.state, "connected");
|
||||
})
|
||||
.then(() => gDial("0900000003"))
|
||||
.then(call => { outCall = call; })
|
||||
.then(() => {
|
||||
is(subCall1.state, "held");
|
||||
is(subCall2.state, "held");
|
||||
is(conference.state, "held");
|
||||
})
|
||||
.then(() => gRemoteHangUpCalls([subCall1, subCall2, outCall]));
|
||||
}
|
||||
|
||||
startTest(function() {
|
||||
testAutoHoldCall()
|
||||
.then(() => testAutoHoldConferenceCall())
|
||||
.then(null, () => {
|
||||
ok(false, 'promise rejects during test.');
|
||||
})
|
||||
.then(finish);
|
||||
});
|
@ -14,7 +14,7 @@ function runAJAXTest() {
|
||||
function onManifestLoad(manifest) {
|
||||
if (manifest.testcases) {
|
||||
AJAXtests = manifest.testcases;
|
||||
runAJAXTest();
|
||||
runAJAXTest();
|
||||
} else {
|
||||
ok(false, "manifest check", "no manifest!?!");
|
||||
SimpleTest.finish();
|
||||
@ -26,5 +26,10 @@ function fetchManifest() {
|
||||
d.addBoth(onManifestLoad);
|
||||
}
|
||||
|
||||
// Double timeout duration. Since this test case takes longer than 300 seconds
|
||||
// on B2G emulator.
|
||||
// See bug 968783.
|
||||
SimpleTest.requestLongerTimeout(2);
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(fetchManifest);
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "prprf.h"
|
||||
|
||||
// Undo the damage done by mozzconf.h
|
||||
#undef compress
|
||||
|
||||
@ -1124,7 +1126,7 @@ MessageChannel::DispatchSyncMessage(const Message& aMsg)
|
||||
Result rv = mListener->OnMessageReceived(aMsg, reply);
|
||||
mDispatchingSyncMessage = false;
|
||||
|
||||
if (!MaybeHandleError(rv, "DispatchSyncMessage")) {
|
||||
if (!MaybeHandleError(rv, aMsg, "DispatchSyncMessage")) {
|
||||
delete reply;
|
||||
reply = new Message();
|
||||
reply->set_sync();
|
||||
@ -1182,7 +1184,7 @@ MessageChannel::DispatchUrgentMessage(const Message& aMsg)
|
||||
mDispatchingUrgentMessageCount--;
|
||||
gDispatchingUrgentMessageCount--;
|
||||
|
||||
if (!MaybeHandleError(rv, "DispatchUrgentMessage")) {
|
||||
if (!MaybeHandleError(rv, aMsg, "DispatchUrgentMessage")) {
|
||||
delete reply;
|
||||
reply = new Message();
|
||||
reply->set_urgent();
|
||||
@ -1204,7 +1206,7 @@ MessageChannel::DispatchRPCMessage(const Message& aMsg)
|
||||
|
||||
Message *reply = nullptr;
|
||||
|
||||
if (!MaybeHandleError(mListener->OnCallReceived(aMsg, reply), "DispatchRPCMessage")) {
|
||||
if (!MaybeHandleError(mListener->OnCallReceived(aMsg, reply), aMsg, "DispatchRPCMessage")) {
|
||||
delete reply;
|
||||
reply = new Message();
|
||||
reply->set_rpc();
|
||||
@ -1228,7 +1230,7 @@ MessageChannel::DispatchAsyncMessage(const Message& aMsg)
|
||||
NS_RUNTIMEABORT("unhandled special message!");
|
||||
}
|
||||
|
||||
MaybeHandleError(mListener->OnMessageReceived(aMsg), "DispatchAsyncMessage");
|
||||
MaybeHandleError(mListener->OnMessageReceived(aMsg), aMsg, "DispatchAsyncMessage");
|
||||
}
|
||||
|
||||
void
|
||||
@ -1296,7 +1298,7 @@ MessageChannel::DispatchInterruptMessage(const Message& aMsg, size_t stackDepth)
|
||||
Result rv = mListener->OnCallReceived(aMsg, reply);
|
||||
--mRemoteStackDepthGuess;
|
||||
|
||||
if (!MaybeHandleError(rv, "DispatchInterruptMessage")) {
|
||||
if (!MaybeHandleError(rv, aMsg, "DispatchInterruptMessage")) {
|
||||
delete reply;
|
||||
reply = new Message();
|
||||
reply->set_interrupt();
|
||||
@ -1556,7 +1558,7 @@ MessageChannel::ReportConnectionError(const char* aChannelName) const
|
||||
}
|
||||
|
||||
bool
|
||||
MessageChannel::MaybeHandleError(Result code, const char* channelName)
|
||||
MessageChannel::MaybeHandleError(Result code, const Message& aMsg, const char* channelName)
|
||||
{
|
||||
if (MsgProcessed == code)
|
||||
return true;
|
||||
@ -1587,7 +1589,12 @@ MessageChannel::MaybeHandleError(Result code, const char* channelName)
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintErrorMessage(mSide, channelName, errorMsg);
|
||||
char printedMsg[512];
|
||||
PR_snprintf(printedMsg, sizeof(printedMsg),
|
||||
"(msgtype=0x%lX,name=%s) %s",
|
||||
aMsg.type(), aMsg.name(), errorMsg);
|
||||
|
||||
PrintErrorMessage(mSide, channelName, printedMsg);
|
||||
|
||||
mListener->OnProcessingError(code);
|
||||
|
||||
|
@ -205,7 +205,7 @@ class MessageChannel : HasResultCodes
|
||||
void OnNotifyMaybeChannelError();
|
||||
void ReportConnectionError(const char* aChannelName) const;
|
||||
void ReportMessageRouteError(const char* channelName) const;
|
||||
bool MaybeHandleError(Result code, const char* channelName);
|
||||
bool MaybeHandleError(Result code, const Message& aMsg, const char* channelName);
|
||||
|
||||
void Clear();
|
||||
|
||||
|
@ -3039,6 +3039,7 @@ nsDocumentViewer::SetFullZoom(float aFullZoom)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool fullZoomChange = (mPageZoom != aFullZoom);
|
||||
mPageZoom = aFullZoom;
|
||||
|
||||
struct ZoomInfo ZoomInfo = { aFullZoom };
|
||||
@ -3052,9 +3053,12 @@ nsDocumentViewer::SetFullZoom(float aFullZoom)
|
||||
// And do the external resources
|
||||
mDocument->EnumerateExternalResources(SetExtResourceFullZoom, &ZoomInfo);
|
||||
|
||||
nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
|
||||
NS_LITERAL_STRING("FullZoomChange"),
|
||||
true, true);
|
||||
// Dispatch FullZoomChange event only if fullzoom value really was been changed
|
||||
if (fullZoomChange) {
|
||||
nsContentUtils::DispatchChromeEvent(mDocument, static_cast<nsIDocument*>(mDocument),
|
||||
NS_LITERAL_STRING("FullZoomChange"),
|
||||
true, true);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1161,10 +1161,10 @@ random == 445004-1.html 445004-1-ref.html # bug 472268
|
||||
skip-if(B2G) fails-if(Android) == 446100-1b.html about:blank
|
||||
skip-if(B2G) fails-if(Android) == 446100-1c.html about:blank
|
||||
== 446100-1d.html about:blank
|
||||
skip-if(B2G&&browserIsRemote) == 446100-1e.html about:blank
|
||||
skip-if(B2G&&browserIsRemote) == 446100-1f.html about:blank
|
||||
== 446100-1e.html about:blank
|
||||
== 446100-1f.html about:blank
|
||||
skip-if(B2G) fails-if(Android) == 446100-1g.html about:blank
|
||||
skip-if(B2G&&browserIsRemote) == 446100-1h.html about:blank
|
||||
== 446100-1h.html about:blank
|
||||
skip-if(B2G) == 447749-1.html 447749-1-ref.html
|
||||
fuzzy(127,2) == 448193.html 448193-ref.html
|
||||
!= 449149-1a.html about:blank
|
||||
@ -1633,8 +1633,8 @@ fails-if(Android&&AndroidVersion!=10&&AndroidVersion!=17) == 617242-1.html 61724
|
||||
!= 618071.html 618071-notref.html
|
||||
== 619117-1.html 619117-1-ref.html
|
||||
HTTP(..) == 619511-1.html 619511-1-ref.html
|
||||
skip-if(Android||(B2G&&browserIsRemote)) HTTP(..) == 621253-1-externalFilter.html 621253-1-ref.html
|
||||
skip-if(Android||(B2G&&browserIsRemote)) == 621253-1-internalFilter.html 621253-1-ref.html
|
||||
skip-if(Android) HTTP(..) == 621253-1-externalFilter.html 621253-1-ref.html
|
||||
skip-if(Android) == 621253-1-internalFilter.html 621253-1-ref.html
|
||||
HTTP(..) == 621253-2-externalFilter.html 621253-2-ref.html
|
||||
== 621253-2-internalFilter.html 621253-2-ref.html
|
||||
skip-if(B2G) random-if(winWidget) fuzzy-if(OSX==10.8,19,17) == 621918-1.svg 621918-1-ref.svg # 1-pixel diacritic positioning discrepancy in rotated text (may depend on platform fonts)
|
||||
|
@ -15,10 +15,10 @@ fuzzy-if(Android,4,34) == image-opacity-02.svg image-opacity-02-ref.svg # Bug 77
|
||||
== image-svg-inline-zoom-in-01b.html ../pass.svg
|
||||
== image-svg-inline-zoom-in-01c.html ../pass.svg
|
||||
== image-svg-inline-zoom-in-01d.html ../pass.svg
|
||||
skip-if(B2G&&browserIsRemote) == image-svg-inline-zoom-out-01a.html ../pass.svg
|
||||
skip-if(B2G&&browserIsRemote) == image-svg-inline-zoom-out-01b.html ../pass.svg
|
||||
skip-if(B2G&&browserIsRemote) == image-svg-inline-zoom-out-01c.html ../pass.svg
|
||||
skip-if(B2G&&browserIsRemote) == image-svg-inline-zoom-out-01d.html ../pass.svg
|
||||
== image-svg-inline-zoom-out-01a.html ../pass.svg
|
||||
== image-svg-inline-zoom-out-01b.html ../pass.svg
|
||||
== image-svg-inline-zoom-out-01c.html ../pass.svg
|
||||
== image-svg-inline-zoom-out-01d.html ../pass.svg
|
||||
== image-svg-inline-sprite-zoom-in-01a.html image-svg-inline-sprite-zoom-in-01-ref.html
|
||||
== image-svg-inline-sprite-zoom-in-01b.html image-svg-inline-sprite-zoom-in-01-ref.html
|
||||
== image-svg-inline-sprite-zoom-out-01a.html image-svg-inline-sprite-zoom-out-01-ref.html
|
||||
|
@ -230,6 +230,11 @@
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity android:name="org.mozilla.gecko.StartPane"
|
||||
android:theme="@style/GeckoStartPane"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true" />
|
||||
|
||||
<activity android:name="org.mozilla.gecko.webapp.Dispatcher"
|
||||
android:noHistory="true" >
|
||||
<intent-filter>
|
||||
|
@ -77,10 +77,12 @@ import org.mozilla.gecko.widget.GeckoActionProvider;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
@ -99,6 +101,7 @@ import android.nfc.NfcEvent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.InputDevice;
|
||||
@ -146,6 +149,7 @@ public class BrowserApp extends GeckoApp
|
||||
|
||||
// Request ID for startActivityForResult.
|
||||
private static final int ACTIVITY_REQUEST_PREFERENCES = 1001;
|
||||
public static final String ACTION_NEW_PROFILE = "org.mozilla.gecko.NEW_PROFILE";
|
||||
|
||||
private BrowserSearch mBrowserSearch;
|
||||
private View mBrowserSearchContainer;
|
||||
@ -209,6 +213,8 @@ public class BrowserApp extends GeckoApp
|
||||
|
||||
private OrderedBroadcastHelper mOrderedBroadcastHelper;
|
||||
|
||||
private BroadcastReceiver mOnboardingReceiver;
|
||||
|
||||
private BrowserHealthReporter mBrowserHealthReporter;
|
||||
|
||||
// The tab to be selected on editing mode exit.
|
||||
@ -551,6 +557,8 @@ public class BrowserApp extends GeckoApp
|
||||
"Updater:Launch",
|
||||
"BrowserToolbar:Visibility");
|
||||
|
||||
registerOnboardingReceiver(this);
|
||||
|
||||
Distribution distribution = Distribution.init(this);
|
||||
|
||||
// Init suggested sites engine in BrowserDB.
|
||||
@ -604,6 +612,25 @@ public class BrowserApp extends GeckoApp
|
||||
}
|
||||
}
|
||||
|
||||
private void registerOnboardingReceiver(Context context) {
|
||||
final LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
|
||||
|
||||
// Receiver for launching first run start pane on new profile creation.
|
||||
mOnboardingReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
launchStartPane(BrowserApp.this);
|
||||
}
|
||||
};
|
||||
|
||||
lbm.registerReceiver(mOnboardingReceiver, new IntentFilter(ACTION_NEW_PROFILE));
|
||||
}
|
||||
|
||||
private void launchStartPane(Context context) {
|
||||
final Intent startIntent = new Intent(context, StartPane.class);
|
||||
context.startActivity(startIntent);
|
||||
}
|
||||
|
||||
private Class<?> getMediaPlayerManager() {
|
||||
if (AppConstants.MOZ_MEDIA_PLAYER) {
|
||||
try {
|
||||
@ -650,6 +677,9 @@ public class BrowserApp extends GeckoApp
|
||||
// Register for Prompt:ShowTop so we can foreground this activity even if it's hidden.
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((GeckoEventListener)this,
|
||||
"Prompt:ShowTop");
|
||||
|
||||
final LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(this);
|
||||
lbm.unregisterReceiver(mOnboardingReceiver);
|
||||
}
|
||||
|
||||
private void setBrowserToolbarListeners() {
|
||||
|
@ -45,6 +45,9 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
private GoogleApiClient apiClient;
|
||||
private RemoteMediaPlayer remoteMediaPlayer;
|
||||
private boolean canMirror;
|
||||
private String mSessionId;
|
||||
private MirrorChannel mMirrorChannel;
|
||||
private boolean mApplicationStarted = false;
|
||||
|
||||
// Callback to start playback of a url on a remote device
|
||||
private class VideoPlayCallback implements ResultCallback<ApplicationConnectionResult>,
|
||||
@ -90,6 +93,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
remoteMediaPlayer = new RemoteMediaPlayer();
|
||||
remoteMediaPlayer.setOnStatusUpdatedListener(this);
|
||||
remoteMediaPlayer.setOnMetadataUpdatedListener(this);
|
||||
mSessionId = result.getSessionId();
|
||||
|
||||
try {
|
||||
Cast.CastApi.setMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace(), remoteMediaPlayer);
|
||||
@ -99,7 +103,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
|
||||
startPlayback();
|
||||
} else {
|
||||
callback.sendError(null);
|
||||
callback.sendError(status.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,7 +126,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
}
|
||||
|
||||
debug("Media load failed " + result.getStatus());
|
||||
callback.sendError(null);
|
||||
callback.sendError(result.getStatus().toString());
|
||||
}
|
||||
});
|
||||
|
||||
@ -133,7 +137,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
debug("Problem opening media during loading", e);
|
||||
}
|
||||
|
||||
callback.sendError(null);
|
||||
callback.sendError("");
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,6 +192,8 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
@Override
|
||||
public void onConnected(Bundle connectionHint) {
|
||||
if (!apiClient.isConnected()) {
|
||||
debug("Connection failed");
|
||||
callback.sendError("Not connected");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -219,14 +225,34 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
callback.sendSuccess(null);
|
||||
}
|
||||
|
||||
public boolean verifySession(final EventCallback callback) {
|
||||
if (apiClient == null || !apiClient.isConnected()) {
|
||||
debug("Can't play. No connection");
|
||||
callback.sendError("Not connected");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSessionId == null) {
|
||||
debug("Can't play. No session");
|
||||
callback.sendError("No session");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void play(final EventCallback callback) {
|
||||
if (!verifySession(callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
remoteMediaPlayer.play(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
|
||||
@Override
|
||||
public void onResult(MediaChannelResult result) {
|
||||
Status status = result.getStatus();
|
||||
if (!status.isSuccess()) {
|
||||
debug("Unable to toggle pause: " + status.getStatusCode());
|
||||
callback.sendError(null);
|
||||
debug("Unable to play: " + status.getStatusCode());
|
||||
callback.sendError(status.toString());
|
||||
} else {
|
||||
callback.sendSuccess(null);
|
||||
}
|
||||
@ -235,13 +261,17 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
}
|
||||
|
||||
public void pause(final EventCallback callback) {
|
||||
if (!verifySession(callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
remoteMediaPlayer.pause(apiClient).setResultCallback(new ResultCallback<MediaChannelResult>() {
|
||||
@Override
|
||||
public void onResult(MediaChannelResult result) {
|
||||
Status status = result.getStatus();
|
||||
if (!status.isSuccess()) {
|
||||
debug("Unable to toggle pause: " + status.getStatusCode());
|
||||
callback.sendError(null);
|
||||
debug("Unable to pause: " + status.getStatusCode());
|
||||
callback.sendError(status.toString());
|
||||
} else {
|
||||
callback.sendSuccess(null);
|
||||
}
|
||||
@ -250,6 +280,10 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
}
|
||||
|
||||
public void end(final EventCallback callback) {
|
||||
if (!verifySession(callback)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Cast.CastApi.stopApplication(apiClient).setResultCallback(new ResultCallback<Status>() {
|
||||
@Override
|
||||
public void onResult(Status result) {
|
||||
@ -257,6 +291,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
try {
|
||||
Cast.CastApi.removeMessageReceivedCallbacks(apiClient, remoteMediaPlayer.getNamespace());
|
||||
remoteMediaPlayer = null;
|
||||
mSessionId = null;
|
||||
apiClient.disconnect();
|
||||
apiClient = null;
|
||||
|
||||
@ -271,18 +306,13 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
}
|
||||
|
||||
if (callback != null) {
|
||||
callback.sendError(null);
|
||||
callback.sendError(result.getStatus().toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String mSessionId;
|
||||
MirrorChannel mMirrorChannel;
|
||||
boolean mApplicationStarted = false;
|
||||
|
||||
class MirrorChannel implements MessageReceivedCallback {
|
||||
|
||||
/**
|
||||
* @return custom namespace
|
||||
*/
|
||||
@ -347,7 +377,7 @@ class ChromeCast implements GeckoMediaPlayer {
|
||||
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Casting:Mirror", route.getId()));
|
||||
} else {
|
||||
callback.sendError(null);
|
||||
callback.sendError(status.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,6 @@
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.mozglue.JNITarget;
|
||||
import org.mozilla.gecko.util.NativeEventListener;
|
||||
import org.mozilla.gecko.util.NativeJSObject;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@ -34,7 +31,7 @@ import android.util.Log;
|
||||
* connection type defined in Network Information API version 3.
|
||||
*/
|
||||
|
||||
public class GeckoNetworkManager extends BroadcastReceiver implements NativeEventListener {
|
||||
public class GeckoNetworkManager extends BroadcastReceiver {
|
||||
private static final String LOGTAG = "GeckoNetworkManager";
|
||||
|
||||
static private final GeckoNetworkManager sInstance = new GeckoNetworkManager();
|
||||
@ -96,8 +93,6 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
|
||||
if (mShouldNotify) {
|
||||
startListening();
|
||||
}
|
||||
|
||||
EventDispatcher.getInstance().registerGeckoThreadListener((NativeEventListener)this, "Wifi:Enable");
|
||||
}
|
||||
|
||||
private void startListening() {
|
||||
@ -117,25 +112,6 @@ public class GeckoNetworkManager extends BroadcastReceiver implements NativeEven
|
||||
if (mShouldNotify) {
|
||||
stopListening();
|
||||
}
|
||||
|
||||
EventDispatcher.getInstance().unregisterGeckoThreadListener((NativeEventListener)this, "Wifi:Enable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(final String event, final NativeJSObject message,
|
||||
final EventCallback callback) {
|
||||
if (event.equals("Wifi:Enable")) {
|
||||
final WifiManager mgr = (WifiManager) mApplicationContext.getSystemService(Context.WIFI_SERVICE);
|
||||
|
||||
if (!mgr.isWifiEnabled()) {
|
||||
mgr.setWifiEnabled(true);
|
||||
} else {
|
||||
// If Wifi is enabled, maybe you need to select a network
|
||||
Intent intent = new Intent(android.provider.Settings.ACTION_WIFI_SETTINGS);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mApplicationContext.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void stopListening() {
|
||||
|
@ -25,6 +25,8 @@ import org.mozilla.gecko.util.INISection;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.support.v4.content.LocalBroadcastManager;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
@ -656,6 +658,10 @@ public final class GeckoProfile {
|
||||
Log.w(LOGTAG, "Couldn't write times.json.", e);
|
||||
}
|
||||
|
||||
LocalBroadcastManager lbm = LocalBroadcastManager.getInstance(mApplicationContext);
|
||||
final Intent intent = new Intent(BrowserApp.ACTION_NEW_PROFILE);
|
||||
lbm.sendBroadcast(intent);
|
||||
|
||||
return profileDir;
|
||||
}
|
||||
|
||||
|
49
mobile/android/base/StartPane.java
Normal file
@ -0,0 +1,49 @@
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.fxa.activities.FxAccountGetStartedActivity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
|
||||
public class StartPane extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle bundle) {
|
||||
super.onCreate(bundle);
|
||||
setContentView(R.layout.onboard_start_pane);
|
||||
|
||||
final Button accountButton = (Button) findViewById(R.id.button_account);
|
||||
accountButton.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showAccountSetup();
|
||||
}
|
||||
});
|
||||
|
||||
final Button browserButton = (Button) findViewById(R.id.button_browser);
|
||||
browserButton.setOnClickListener(new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
showBrowser();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showBrowser() {
|
||||
// StartPane is on the stack above the browser, so just kill this activity.
|
||||
finish();
|
||||
}
|
||||
|
||||
private void showAccountSetup() {
|
||||
final Intent intent = new Intent(this, FxAccountGetStartedActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
finish();
|
||||
}
|
||||
}
|
@ -543,6 +543,7 @@ sync_java_files = [
|
||||
'browserid/verifier/BrowserIDVerifierDelegate.java',
|
||||
'browserid/verifier/BrowserIDVerifierException.java',
|
||||
'browserid/VerifyingPublicKey.java',
|
||||
'fxa/AccountLoader.java',
|
||||
'fxa/activities/FxAccountAbstractActivity.java',
|
||||
'fxa/activities/FxAccountAbstractSetupActivity.java',
|
||||
'fxa/activities/FxAccountConfirmAccountActivity.java',
|
||||
|
184
mobile/android/base/fxa/AccountLoader.java
Normal file
@ -0,0 +1,184 @@
|
||||
/* 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/. */
|
||||
|
||||
package org.mozilla.gecko.fxa;
|
||||
|
||||
import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
|
||||
import org.mozilla.gecko.sync.setup.SyncAccounts;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
|
||||
/**
|
||||
* A Loader that queries and updates based on the existence of Firefox and
|
||||
* legacy Sync Android Accounts.
|
||||
*
|
||||
* The loader returns an Android Account (of either Account type) if an account
|
||||
* exists, and null to indicate no Account is present.
|
||||
*
|
||||
* The loader listens for Accounts added and deleted, and also Accounts being
|
||||
* updated by Sync or another Activity, via the use of
|
||||
* {@link AndroidFxAccount#setState(org.mozilla.gecko.fxa.login.State)}.
|
||||
* Be careful of message loops if you update the account state from an activity
|
||||
* that uses this loader.
|
||||
*
|
||||
* This implementation is based on
|
||||
* <a href="http://www.androiddesignpatterns.com/2012/08/implementing-loaders.html">http://www.androiddesignpatterns.com/2012/08/implementing-loaders.html</a>.
|
||||
*/
|
||||
public class AccountLoader extends AsyncTaskLoader<Account> {
|
||||
protected Account account = null;
|
||||
protected BroadcastReceiver broadcastReceiver = null;
|
||||
|
||||
public AccountLoader(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
// Task that performs the asynchronous load **/
|
||||
@Override
|
||||
public Account loadInBackground() {
|
||||
final Context context = getContext();
|
||||
Account foundAccount = FirefoxAccounts.getFirefoxAccount(context);
|
||||
if (foundAccount == null) {
|
||||
final Account[] syncAccounts = SyncAccounts.syncAccounts(context);
|
||||
if (syncAccounts != null && syncAccounts.length > 0) {
|
||||
foundAccount = syncAccounts[0];
|
||||
}
|
||||
}
|
||||
return foundAccount;
|
||||
}
|
||||
|
||||
// Deliver the results to the registered listener.
|
||||
@Override
|
||||
public void deliverResult(Account data) {
|
||||
if (isReset()) {
|
||||
// The Loader has been reset; ignore the result and invalidate the data.
|
||||
releaseResources(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Hold a reference to the old data so it doesn't get garbage collected.
|
||||
// We must protect it until the new data has been delivered.
|
||||
Account oldData = account;
|
||||
account = data;
|
||||
|
||||
if (isStarted()) {
|
||||
// If the Loader is in a started state, deliver the results to the
|
||||
// client. The superclass method does this for us.
|
||||
super.deliverResult(data);
|
||||
}
|
||||
|
||||
// Invalidate the old data as we don't need it any more.
|
||||
if (oldData != null && oldData != data) {
|
||||
releaseResources(oldData);
|
||||
}
|
||||
}
|
||||
|
||||
// The Loader’s state-dependent behavior.
|
||||
@Override
|
||||
protected void onStartLoading() {
|
||||
if (account != null) {
|
||||
// Deliver any previously loaded data immediately.
|
||||
deliverResult(account);
|
||||
}
|
||||
|
||||
// Begin monitoring the underlying data source.
|
||||
if (broadcastReceiver == null) {
|
||||
broadcastReceiver = makeNewObserver();
|
||||
registerObserver(broadcastReceiver);
|
||||
}
|
||||
|
||||
if (takeContentChanged() || account == null) {
|
||||
// When the observer detects a change, it should call onContentChanged()
|
||||
// on the Loader, which will cause the next call to takeContentChanged()
|
||||
// to return true. If this is ever the case (or if the current data is
|
||||
// null), we force a new load.
|
||||
forceLoad();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStopLoading() {
|
||||
// The Loader is in a stopped state, so we should attempt to cancel the
|
||||
// current load (if there is one).
|
||||
cancelLoad();
|
||||
|
||||
// Note that we leave the observer as is. Loaders in a stopped state
|
||||
// should still monitor the data source for changes so that the Loader
|
||||
// will know to force a new load if it is ever started again.
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReset() {
|
||||
// Ensure the loader has been stopped. In CursorLoader and the template
|
||||
// this code follows (see the class comment), this is onStopLoading, which
|
||||
// appears to not set the started flag (see Loader itself).
|
||||
stopLoading();
|
||||
|
||||
// At this point we can release the resources associated with 'mData'.
|
||||
if (account != null) {
|
||||
releaseResources(account);
|
||||
account = null;
|
||||
}
|
||||
|
||||
// The Loader is being reset, so we should stop monitoring for changes.
|
||||
if (broadcastReceiver != null) {
|
||||
final BroadcastReceiver observer = broadcastReceiver;
|
||||
broadcastReceiver = null;
|
||||
unregisterObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCanceled(Account data) {
|
||||
// Attempt to cancel the current asynchronous load.
|
||||
super.onCanceled(data);
|
||||
|
||||
// The load has been canceled, so we should release the resources
|
||||
// associated with 'data'.
|
||||
releaseResources(data);
|
||||
}
|
||||
|
||||
private void releaseResources(Account data) {
|
||||
// For a simple List, there is nothing to do. For something like a Cursor, we
|
||||
// would close it in this method. All resources associated with the Loader
|
||||
// should be released here.
|
||||
}
|
||||
|
||||
// Observer which receives notifications when the data changes.
|
||||
protected BroadcastReceiver makeNewObserver() {
|
||||
final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
// Must be called on the main thread of the process. We register the
|
||||
// broadcast receiver with a null Handler (see registerObserver), which
|
||||
// ensures we're on the main thread when we receive this intent.
|
||||
onContentChanged();
|
||||
}
|
||||
};
|
||||
return broadcastReceiver;
|
||||
}
|
||||
|
||||
protected void registerObserver(BroadcastReceiver observer) {
|
||||
final IntentFilter intentFilter = new IntentFilter();
|
||||
// Android Account added or removed.
|
||||
intentFilter.addAction(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
|
||||
// Firefox Account internal state changed.
|
||||
intentFilter.addAction(FxAccountConstants.ACCOUNT_STATE_CHANGED_ACTION);
|
||||
|
||||
// null means: "the main thread of the process will be used." We must call
|
||||
// onContentChanged on the main thread of the process; this ensures we do.
|
||||
final Handler handler = null;
|
||||
getContext().registerReceiver(observer, intentFilter, FxAccountConstants.PER_ACCOUNT_TYPE_PERMISSION, handler);
|
||||
}
|
||||
|
||||
protected void unregisterObserver(BroadcastReceiver observer) {
|
||||
getContext().unregisterReceiver(observer);
|
||||
}
|
||||
}
|
@ -67,4 +67,14 @@ public class FxAccountConstants {
|
||||
* received only by Firefox channels sharing the same Android Firefox Account type.
|
||||
*/
|
||||
public static final String PER_ACCOUNT_TYPE_PERMISSION = "@MOZ_ANDROID_SHARED_FXACCOUNT_TYPE@.permission.PER_ACCOUNT_TYPE";
|
||||
|
||||
/**
|
||||
* This action is broadcast when an Android Firefox Account's internal state
|
||||
* is changed.
|
||||
* <p>
|
||||
* It is protected by signing-level permission PER_ACCOUNT_TYPE_PERMISSION and
|
||||
* can be received only by Firefox versions sharing the same Android Firefox
|
||||
* Account type.
|
||||
*/
|
||||
public static final String ACCOUNT_STATE_CHANGED_ACTION = "@MOZ_ANDROID_SHARED_FXACCOUNT_TYPE@.accounts.ACCOUNT_STATE_CHANGED_ACTION";
|
||||
}
|
||||
|
@ -160,7 +160,8 @@ public class FxAccountUpdateCredentialsActivity extends FxAccountAbstractSetupAc
|
||||
fxAccount.dump();
|
||||
}
|
||||
|
||||
redirectToActivity(FxAccountStatusActivity.class);
|
||||
setResult(RESULT_OK);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ import org.mozilla.gecko.fxa.login.State.StateLabel;
|
||||
import org.mozilla.gecko.fxa.login.StateFactory;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.setup.Constants;
|
||||
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
@ -483,6 +484,13 @@ public class AndroidFxAccount {
|
||||
" to state " + state.getStateLabel().toString());
|
||||
updateBundleValue(BUNDLE_KEY_STATE_LABEL, state.getStateLabel().name());
|
||||
updateBundleValue(BUNDLE_KEY_STATE, state.toJSONObject().toJSONString());
|
||||
broadcastAccountStateChangedIntent();
|
||||
}
|
||||
|
||||
protected void broadcastAccountStateChangedIntent() {
|
||||
final Intent intent = new Intent(FxAccountConstants.ACCOUNT_STATE_CHANGED_ACTION);
|
||||
intent.putExtra(Constants.JSON_KEY_ACCOUNT, account.name);
|
||||
context.sendBroadcast(intent, FxAccountConstants.PER_ACCOUNT_TYPE_PERMISSION);
|
||||
}
|
||||
|
||||
public synchronized State getState() {
|
||||
|
@ -140,23 +140,10 @@ public class BookmarksPanel extends HomeFragment {
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
// Reattach the fragment, forcing a reinflation of its view.
|
||||
// We use commitAllowingStateLoss() instead of commit() here to avoid
|
||||
// an IllegalStateException. If the phone is rotated while Fennec
|
||||
// is in the background, onConfigurationChanged() is fired.
|
||||
// onConfigurationChanged() is called before onResume(), so
|
||||
// using commit() would throw an IllegalStateException since it can't
|
||||
// be used between the Activity's onSaveInstanceState() and
|
||||
// onResume().
|
||||
if (isVisible()) {
|
||||
// The parent stack is saved just so that the folder state can be
|
||||
// restored on rotation.
|
||||
mSavedParentStack = mListAdapter.getParentStack();
|
||||
|
||||
getFragmentManager().beginTransaction()
|
||||
.detach(this)
|
||||
.attach(this)
|
||||
.commitAllowingStateLoss();
|
||||
}
|
||||
}
|
||||
|
||||
|