--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="0292e64ef8451df104dcf9ac3b2c6749b81684dd"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="85f9690323b235f4dcf2901ea2240d3c60fc22a0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,17 +12,17 @@
<!--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="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
<copyfile dest="Makefile" src="core/root.mk"/>
</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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
@@ -123,14 +123,14 @@
<project name="platform/system/security" path="system/security" revision="f48ff68fedbcdc12b570b7699745abb6e7574907"/>
<project name="platform/system/vold" path="system/vold" revision="8de05d4a52b5a91e7336e6baa4592f945a6ddbea"/>
<default remote="caf" revision="refs/tags/android-4.3_r2.1" sync-j="4"/>
<!-- Emulator specific things -->
<project name="android-development" path="development" remote="b2g" revision="dab55669da8f48b6e57df95d5af9f16b4a87b0b1"/>
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
<project name="device_generic_goldfish" path="device/generic/goldfish" remote="b2g" revision="09485b73629856b21b2ed6073e327ab0e69a1189"/>
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
- <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="9a00b3db898a83ef0766baa93e935e525572899e"/>
+ <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="bb11a0417efa7e6a08ed1cb2d5d6a13a3100abd3"/>
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="72e3a520e3c700839f07ba0113fd527b923c3330"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="baaf899afb158b9530690002f3656e958e3eb047"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
</manifest>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was git://codeaurora.org/-->
<remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
<!--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="65fba428f8d76336b33ddd9e15900357953600ba">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<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="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<!-- Stock Android things -->
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="0292e64ef8451df104dcf9ac3b2c6749b81684dd"/>
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="85f9690323b235f4dcf2901ea2240d3c60fc22a0"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -13,17 +13,17 @@
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<!-- B2G specific things. -->
<project name="platform_build" path="build" remote="b2g" revision="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
- <project name="gaia" path="gaia" remote="mozillaorg" revision="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
{
"git": {
"git_revision": "",
"remote": "",
"branch": ""
},
- "revision": "9f480d1c52a46cac8e9a0be04bdb0d73810bc596",
+ "revision": "2eae294604eb70e0e6eaee76b17e155ffd031107",
"repo_path": "/integration/gaia-central"
}
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
<!--original fetch url was https://git.mozilla.org/releases-->
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/inari/sources.xml
+++ b/b2g/config/inari/sources.xml
@@ -14,17 +14,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
<project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
--- a/b2g/config/leo/sources.xml
+++ b/b2g/config/leo/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/b2g/config/mako/sources.xml
+++ b/b2g/config/mako/sources.xml
@@ -12,17 +12,17 @@
<!--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="e6383e6e785cc3ea237e902beb1092f9aa88e29d">
<copyfile dest="Makefile" src="core/root.mk"/>
</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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
<project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
<!-- Stock Android things -->
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
<project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,17 +12,17 @@
<!--original fetch url was git://github.com/apitrace/-->
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="2a165bebfa19b11b697837409f9550dd2917c46c">
<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="d25852a189c9707b144eb5f82d08384eb066c0fd"/>
+ <project name="gaia.git" path="gaia" remote="mozillaorg" revision="6a2eb4b3664fb3e6f5c87db2af8485b7424f9ecb"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="266bca6e60dad43e395f38b66edabe8bdc882334"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="ce95d372e6d285725b96490afdaaf489ad8f9ca9"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="8d6c36d74ba9aefbc8c3618fc93dd4907a0dbf5e"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->
<project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
--- a/browser/base/content/browser-customization.js
+++ b/browser/base/content/browser-customization.js
@@ -34,17 +34,16 @@ let CustomizationHandler = {
childNode.setAttribute("disabled", true);
let cmd = document.getElementById("cmd_CustomizeToolbars");
cmd.setAttribute("disabled", "true");
UpdateUrlbarSearchSplitterState();
CombinedStopReload.uninit();
- CombinedBackForward.uninit();
PlacesToolbarHelper.customizeStart();
DownloadsButton.customizeStart();
// The additional padding on the sides of the browser
// can cause the customize tab to get clipped.
let tabContainer = gBrowser.tabContainer;
if (tabContainer.getAttribute("overflow") == "true") {
let tabstrip = tabContainer.mTabstrip;
@@ -82,17 +81,16 @@ let CustomizationHandler = {
}
PlacesToolbarHelper.customizeDone();
DownloadsButton.customizeDone();
// The url bar splitter state is dependent on whether stop/reload
// and the location bar are combined, so we need this ordering
CombinedStopReload.init();
- CombinedBackForward.init();
UpdateUrlbarSearchSplitterState();
// Update the urlbar
if (gURLBar) {
URLBarSetURI();
XULBrowserWindow.asyncUpdateUI();
}
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -255,25 +255,17 @@ function UpdateBackForwardCommands(aWebN
var forwardDisabled = forwardBroadcaster.hasAttribute("disabled");
if (backDisabled == aWebNavigation.canGoBack) {
if (backDisabled)
backBroadcaster.removeAttribute("disabled");
else
backBroadcaster.setAttribute("disabled", true);
}
- let canGoForward = aWebNavigation.canGoForward;
- if (forwardDisabled) {
- // Force the button to either be hidden (if we are already disabled,
- // and should be), or to show if we're about to un-disable it:
- // otherwise no transition will occur and it'll never show:
- CombinedBackForward.setForwardButtonOcclusion(!canGoForward);
- }
-
- if (forwardDisabled == canGoForward) {
+ if (forwardDisabled == aWebNavigation.canGoForward) {
if (forwardDisabled)
forwardBroadcaster.removeAttribute("disabled");
else
forwardBroadcaster.setAttribute("disabled", true);
}
}
/**
@@ -915,17 +907,16 @@ var gBrowserInit = {
gURLBar.setAttribute("readonly", "true");
gURLBar.setAttribute("enablehistory", "false");
}
goSetCommandEnabled("cmd_newNavigatorTab", false);
}
// Misc. inits.
CombinedStopReload.init();
- CombinedBackForward.init();
gPrivateBrowsingUI.init();
TabsInTitlebar.init();
// Wait until chrome is painted before executing code not critical to making the window visible
this._boundDelayedStartup = this._delayedStartup.bind(this, mustLoadSidebar);
window.addEventListener("MozAfterPaint", this._boundDelayedStartup);
this._loadHandled = true;
@@ -1262,17 +1253,16 @@ var gBrowserInit = {
if (desc && !desc.get) {
DeveloperToolbar.destroy();
}
// First clean up services initialized in gBrowserInit.onLoad (or those whose
// uninit methods don't depend on the services having been initialized).
CombinedStopReload.uninit();
- CombinedBackForward.uninit();
gGestureSupport.init(false);
gHistorySwipeAnimation.uninit();
FullScreen.cleanup();
#ifdef MOZ_SERVICES_SYNC
@@ -3794,17 +3784,16 @@ var XULBrowserWindow = {
} catch (e) {}
gIdentityHandler.checkIdentity(this._state, uri);
},
// simulate all change notifications after switching tabs
onUpdateCurrentBrowser: function XWB_onUpdateCurrentBrowser(aStateFlags, aStatus, aMessage, aTotalProgress) {
if (FullZoom.updateBackgroundTabs)
FullZoom.onLocationChange(gBrowser.currentURI, true);
- CombinedBackForward.setForwardButtonOcclusion(!gBrowser.webProgress.canGoForward);
var nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
var loadingDone = aStateFlags & nsIWebProgressListener.STATE_STOP;
// use a pseudo-object instead of a (potentially nonexistent) channel for getting
// a correct error message - and make sure that the UI is always either in
// loading (STATE_START) or done (STATE_STOP) mode
this.onStateChange(
gBrowser.webProgress,
{ URI: gBrowser.currentURI },
@@ -3869,53 +3858,16 @@ var LinkTargetDisplay = {
_hide: function () {
clearTimeout(this._timer);
XULBrowserWindow.updateStatusField();
}
};
-let CombinedBackForward = {
- init: function() {
- this.forwardButton = document.getElementById("forward-button");
- // Add a transition listener to the url bar to hide the forward button
- // when necessary
- if (gURLBar)
- gURLBar.addEventListener("transitionend", this);
- // On startup, or if the user customizes, our listener isn't attached,
- // and no transitions fire anyway, so we need to make sure we've hidden the
- // button if necessary:
- if (this.forwardButton && this.forwardButton.hasAttribute("disabled")) {
- this.setForwardButtonOcclusion(true);
- }
- },
- uninit: function() {
- if (gURLBar)
- gURLBar.removeEventListener("transitionend", this);
- },
- handleEvent: function(aEvent) {
- if (aEvent.type == "transitionend" &&
- (aEvent.propertyName == "margin-left" || aEvent.propertyName == "margin-right") &&
- this.forwardButton.hasAttribute("disabled")) {
- this.setForwardButtonOcclusion(true);
- }
- },
- setForwardButtonOcclusion: function(shouldBeOccluded) {
- if (!this.forwardButton)
- return;
-
- let hasAttribute = this.forwardButton.hasAttribute("occluded-by-urlbar");
- if (shouldBeOccluded && !hasAttribute)
- this.forwardButton.setAttribute("occluded-by-urlbar", "true");
- else if (!shouldBeOccluded && hasAttribute)
- this.forwardButton.removeAttribute("occluded-by-urlbar");
- }
-}
-
var CombinedStopReload = {
init: function () {
if (this._initialized)
return;
let reload = document.getElementById("urlbar-reload-button");
let stop = document.getElementById("urlbar-stop-button");
if (!stop || !reload || reload.nextSibling != stop)
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -651,31 +651,24 @@
class="chromeclass-location" overflows="false">
<toolbarbutton id="back-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
label="&backCmd.label;"
command="Browser:BackOrBackDuplicate"
cui-areatype="toolbar"
onclick="checkForMiddleClick(this, event);"
tooltip="back-button-tooltip"
context="backForwardMenu"/>
- <toolbarbutton id="forward-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
- label="&forwardCmd.label;"
- command="Browser:ForwardOrForwardDuplicate"
- cui-areatype="toolbar"
- onclick="checkForMiddleClick(this, event);"
- tooltip="forward-button-tooltip"
- context="backForwardMenu"/>
- <dummyobservertarget hidden="true"
- onbroadcast="if (this.getAttribute('disabled') == 'true')
- this.parentNode.setAttribute('forwarddisabled', 'true');
- else
- this.parentNode.removeAttribute('forwarddisabled');">
- <observes element="Browser:ForwardOrForwardDuplicate" attribute="disabled"/>
- </dummyobservertarget>
- <hbox id="urlbar-wrapper" flex="1" align="center">
+ <hbox id="urlbar-wrapper" flex="1">
+ <toolbarbutton id="forward-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
+ label="&forwardCmd.label;"
+ command="Browser:ForwardOrForwardDuplicate"
+ cui-areatype="toolbar"
+ onclick="checkForMiddleClick(this, event);"
+ tooltip="forward-button-tooltip"
+ context="backForwardMenu"/>
<textbox id="urlbar" flex="1"
placeholder="&urlbar.placeholder2;"
type="autocomplete"
autocompletesearch="urlinline history"
autocompletesearchparam="enable-actions"
autocompletepopup="PopupAutoCompleteRichResult"
completeselectedindex="true"
tabscrolling="true"
@@ -1183,32 +1176,23 @@
oncommand="DeveloperToolbar.hide();"
tooltiptext="&devToolbarCloseButton.tooltiptext;"/>
#endif
</toolbar>
</vbox>
<svg:svg height="0">
#include tab-shape.inc.svg
-
+ <svg:clipPath id="urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
#ifndef XP_MACOSX
- <svg:clipPath id="keyhole-forward-clip-path" clipPathUnits="objectBoundingBox">
- <svg:path d="m 0,0 c .3,.25 .3,.75, 0,1 l 1,0 0,-1 z"/>
- </svg:clipPath>
- <svg:clipPath id="urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
- <svg:path d="m 0,-5 l 0,7.8 c 2.5,3.2 4,6.2 4,10.2 c 0,4 -1.5,7 -4,10 l 0,22l10000,0 l 0,-50 l -10000,0 z"/>
+ <svg:path d="m 1,-5 l 0,7.8 c 2.5,3.2 4,6.2 4,10.2 c 0,4 -1.5,7 -4,10 l 0,22l10000,0 l 0,-50 l -10000,0 z"/>
+#else
+ <svg:path d="M -11,-5 a 16 16 0 0 1 0,34 l 10000,0 l 0,-34 l -10000,0 z"/>
+#endif
</svg:clipPath>
-#else
- <svg:clipPath id="osx-keyhole-forward-clip-path" clipPathUnits="userSpaceOnUse">
- <svg:path d="M 0,0 a 16 16 0 0 1 0,24 l 10000,0 l 0,-24 l -10000,0 z"/>
- </svg:clipPath>
- <svg:clipPath id="osx-urlbar-back-button-clip-path" clipPathUnits="userSpaceOnUse">
- <svg:path d="M -12,-5 a 16 16 0 0 1 0,34 l 10000,0 l 0,-34 l -10000,0 z"/>
- </svg:clipPath>
-#endif
</svg:svg>
</vbox>
# <iframe id="tab-view"> is dynamically appended as the 2nd child of #tab-view-deck.
# Introducing the iframe dynamically, as needed, was found to be better than
# starting with an empty iframe here in browser.xul from a Ts standpoint.
</deck>
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -1007,22 +1007,22 @@
newBrowser.setAttribute("type", "content-primary");
newBrowser.docShellIsActive =
(window.windowState != window.STATE_MINIMIZED);
this.mCurrentBrowser = newBrowser;
this.mCurrentTab = this.tabContainer.selectedItem;
this.showTab(this.mCurrentTab);
- var backForwardContainer = document.getElementById("urlbar-container");
- if (backForwardContainer) {
- backForwardContainer.setAttribute("switchingtabs", "true");
+ var forwardButtonContainer = document.getElementById("urlbar-wrapper");
+ if (forwardButtonContainer) {
+ forwardButtonContainer.setAttribute("switchingtabs", "true");
window.addEventListener("MozAfterPaint", function removeSwitchingtabsAttr() {
window.removeEventListener("MozAfterPaint", removeSwitchingtabsAttr);
- backForwardContainer.removeAttribute("switchingtabs");
+ forwardButtonContainer.removeAttribute("switchingtabs");
});
}
this._appendStatusPanel();
if (updateBlockedPopups)
this.mCurrentBrowser.updateBlockedPopups(false);
--- a/browser/base/content/test/general/browser_aboutHome.js
+++ b/browser/base/content/test/general/browser_aboutHome.js
@@ -85,67 +85,68 @@ let gTests = [
"Search engine logo's alt text is a nonempty string");
isnot(altText, "undefined",
"Search engine logo's alt text shouldn't be the string 'undefined'");
}
},
// Disabled on Linux for intermittent issues with FHR, see Bug 945667.
-// Disabled always due to bug 992485
{
desc: "Check that performing a search fires a search event and records to " +
"Firefox Health Report.",
setup: function () { },
run: function () {
- // Skip this test always for now since it loads google.com and that causes bug 992485
- return;
-
// Skip this test on Linux.
if (navigator.platform.indexOf("Linux") == 0) { return; }
try {
let cm = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
cm.getCategoryEntry("healthreport-js-provider-default", "SearchesProvider");
} catch (ex) {
// Health Report disabled, or no SearchesProvider.
return Promise.resolve();
}
let numSearchesBefore = 0;
- let deferred = Promise.defer();
+ let searchEventDeferred = Promise.defer();
let doc = gBrowser.contentDocument;
let engineName = doc.documentElement.getAttribute("searchEngineName");
doc.addEventListener("AboutHomeSearchEvent", function onSearch(e) {
let data = JSON.parse(e.detail);
is(data.engineName, engineName, "Detail is search engine name");
// We use executeSoon() to ensure that this code runs after the
// count has been updated in browser.js, since it uses the same
// event.
executeSoon(function () {
getNumberOfSearches(engineName).then(num => {
is(num, numSearchesBefore + 1, "One more search recorded.");
- deferred.resolve();
+ searchEventDeferred.resolve();
});
});
}, true, true);
// Get the current number of recorded searches.
+ let searchStr = "a search";
getNumberOfSearches(engineName).then(num => {
numSearchesBefore = num;
info("Perform a search.");
- doc.getElementById("searchText").value = "a search";
+ doc.getElementById("searchText").value = searchStr;
doc.getElementById("searchSubmit").click();
- gBrowser.stop();
});
- return deferred.promise;
+ let expectedURL = Services.search.currentEngine.
+ getSubmission(searchStr, null, "homepage").
+ uri.spec;
+ let loadPromise = waitForDocLoadAndStopIt(expectedURL);
+
+ return Promise.all([searchEventDeferred.promise, loadPromise]);
}
},
{
desc: "Check snippets map is cleared if cached version is old",
setup: function (aSnippetsMap)
{
aSnippetsMap.set("snippets", "test");
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -287,16 +287,48 @@ function promiseHistoryClearedState(aURI
"history visit " + aURI.spec + " should " + niceStr + " exist");
callbackDone();
});
});
return deferred.promise;
}
+/**
+ * Waits for the next top-level document load in the current browser. The URI
+ * of the document is compared against aExpectedURL. The load is then stopped
+ * before it actually starts.
+ *
+ * @param aExpectedURL
+ * The URL of the document that is expected to load.
+ * @return promise
+ */
+function waitForDocLoadAndStopIt(aExpectedURL) {
+ let deferred = Promise.defer();
+ let progressListener = {
+ onStateChange: function (webProgress, req, flags, status) {
+ info("waitForDocLoadAndStopIt: onStateChange: " + req.name);
+ let docStart = Ci.nsIWebProgressListener.STATE_IS_DOCUMENT |
+ Ci.nsIWebProgressListener.STATE_START;
+ if ((flags & docStart) && webProgress.isTopLevel) {
+ info("waitForDocLoadAndStopIt: Document start: " +
+ req.QueryInterface(Ci.nsIChannel).URI.spec);
+ is(req.originalURI.spec, aExpectedURL,
+ "waitForDocLoadAndStopIt: The expected URL was loaded");
+ req.cancel(Components.results.NS_ERROR_FAILURE);
+ gBrowser.removeProgressListener(progressListener);
+ deferred.resolve();
+ }
+ },
+ };
+ gBrowser.addProgressListener(progressListener);
+ info("waitForDocLoadAndStopIt: Waiting for URL: " + aExpectedURL);
+ return deferred.promise;
+}
+
let FullZoomHelper = {
selectTabAndWaitForLocationChange: function selectTabAndWaitForLocationChange(tab) {
if (!tab)
throw new Error("tab must be given.");
if (gBrowser.selectedTab == tab)
return Promise.resolve();
gBrowser.selectedTab = tab;
--- a/browser/components/downloads/content/downloadsOverlay.xul
+++ b/browser/components/downloads/content/downloadsOverlay.xul
@@ -99,16 +99,20 @@
<richlistbox id="downloadsListBox"
class="plain"
flex="1"
context="downloadsContextMenu"
onmouseover="DownloadsView.onDownloadMouseOver(event);"
onmouseout="DownloadsView.onDownloadMouseOut(event);"
oncontextmenu="DownloadsView.onDownloadContextMenu(event);"
ondragstart="DownloadsView.onDownloadDragStart(event);"/>
+ <description id="emptyDownloads"
+ mousethrough="always">
+ &downloadsPanelEmpty.label;
+ </description>
<vbox id="downloadsFooter">
<hbox id="downloadsSummary"
align="center"
orient="horizontal"
onkeydown="DownloadsSummary.onKeyDown(event);"
onclick="DownloadsSummary.onClick(event);">
<image class="downloadTypeIcon" />
--- a/browser/locales/en-US/chrome/browser/downloads/downloads.dtd
+++ b/browser/locales/en-US/chrome/browser/downloads/downloads.dtd
@@ -79,13 +79,18 @@
<!ENTITY clearDownloadsButton.tooltip "Clears completed, canceled and failed downloads">
<!-- LOCALIZATION NOTE (downloadsListEmpty.label):
This string is shown when there are no items in the Downloads view, when it
is displayed inside a browser tab.
-->
<!ENTITY downloadsListEmpty.label "There are no downloads.">
+<!-- LOCALIZATION NOTE (downloadsPanelEmpty.label):
+ This string is shown when there are no items in the Downloads Panel.
+ -->
+<!ENTITY downloadsPanelEmpty.label "No downloads for this session.">
+
<!-- LOCALIZATION NOTE (downloadsListNoMatch.label):
This string is shown when some search terms are specified, but there are no
results in the Downloads view.
-->
<!ENTITY downloadsListNoMatch.label "Could not find any matching downloads.">
--- a/browser/themes/linux/browser.css
+++ b/browser/themes/linux/browser.css
@@ -10,17 +10,17 @@
@namespace html url("http://www.w3.org/1999/xhtml");
@namespace svg url("http://www.w3.org/2000/svg");
%include ../shared/browser.inc
%include linuxShared.inc
%filter substitution
%define forwardTransitionLength 150ms
-%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
+%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-wrapper
%define conditionalForwardWithUrlbarWidth 30
#menubar-items {
-moz-box-orient: vertical; /* for flex hack */
}
#main-menubar {
-moz-box-flex: 1; /* make menu items expand to fill toolbar height */
@@ -730,45 +730,49 @@ toolbarbutton[sdk-button="true"][cui-are
}
#main-window:not([customizing]) #back-button[disabled] > .toolbarbutton-icon {
box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
0 1px 0 hsla(210,54%,20%,.65) !important;
transition: none;
}
-#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
-#forward-button:-moz-locale-dir(rtl) {
+#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
transform: scaleX(-1);
}
-@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
- opacity: 0;
-}
-
-@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
- transition: opacity @forwardTransitionLength@ ease-out;
-}
-
-@conditionalForwardWithUrlbar@ > #forward-button[occluded-by-urlbar] {
- visibility: hidden;
-}
-
#forward-button {
padding: 0;
}
#forward-button > .toolbarbutton-icon {
background-clip: padding-box;
- clip-path: url("chrome://browser/content/browser.xul#keyhole-forward-clip-path");
- margin-left: -6px;
+ padding-left: 9px;
+ padding-right: 3px;
+ border: 1px solid #9a9a9a;
border-left-style: none;
border-radius: 0;
- padding: 2px 3px 2px 9px;
- border: 1px solid #9a9a9a;
+}
+
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
+ transition: margin-left @forwardTransitionLength@ ease-out;
+}
+
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] {
+ margin-left: -@conditionalForwardWithUrlbarWidth@px;
+}
+
+@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] {
+ /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
+ transition-delay: 100s;
+}
+
+@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
+ /* when not hovered anymore, trigger a new transition to hide the forward button immediately */
+ margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
}
/* tabview menu item */
#menu_tabview {
list-style-image: url(chrome://browser/skin/tabview/tabview.png);
-moz-image-region: rect(0, 80px, 16px, 64px);
}
@@ -898,67 +902,44 @@ toolbarbutton[sdk-button="true"][cui-are
.urlbar-history-dropmarker {
-moz-appearance: toolbarbutton-dropdown;
}
#urlbar-container {
-moz-box-align: center;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
- padding-left: @conditionalForwardWithUrlbarWidth@px;
- -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
- position: relative;
- pointer-events: none;
+@conditionalForwardWithUrlbar@ > #urlbar {
+ -moz-border-start: none;
+ margin-left: 0;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
- -moz-border-start: none;
- margin-left: 0;
- pointer-events: all;
-}
-
-@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
- transition: margin-left @forwardTransitionLength@ ease-out;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(rtl) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
+@conditionalForwardWithUrlbar@ {
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
- margin-left: -@conditionalForwardWithUrlbarWidth@px;
+ -moz-margin-start: -5px;
}
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
- /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
- transition-delay: 100s;
+@conditionalForwardWithUrlbar@:-moz-locale-dir(rtl),
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(rtl) {
+ /* let urlbar-back-button-clip-path clip the urlbar's right side for RTL */
+ transform: scaleX(-1);
}
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar,
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
- /* when switching tabs, or when not hovered anymore, trigger a new transition
- * to hide the forward button immediately */
- margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
- /* let windows-urlbar-back-button-mask clip the urlbar's right side for RTL */
- transform: scaleX(-1);
+@conditionalForwardWithUrlbar@:-moz-locale-dir(rtl) {
+ -moz-box-direction: reverse;
}
#urlbar-icons {
-moz-box-align: center;
}
.urlbar-icon {
cursor: pointer;
@@ -1010,43 +991,43 @@ toolbarbutton[sdk-button="true"][cui-are
border-bottom-right-radius: 1.5px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px;
border-radius: 0;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
+@conditionalForwardWithUrlbar@ > #urlbar > #identity-box {
border-radius: 0;
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
- padding-left: 5px;
- transition: padding-left;
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar > #identity-box {
+ transition: padding-left, padding-right;
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
- padding-right: 5px;
- transition: padding-right;
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+ padding-left: 5px;
}
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+ padding-right: 5px;
+}
+
+@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box {
/* forward button hiding is delayed when hovered */
transition-delay: 100s;
}
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr),
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
padding-left: 5.01px;
}
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
padding-right: 5.01px;
}
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
-moz-margin-end: 4px;
}
@@ -1066,24 +1047,20 @@ toolbarbutton[sdk-button="true"][cui-are
}
%include ../shared/identity-block.inc.css
#page-proxy-favicon {
margin-top: 1px;
margin-bottom: 1px;
-moz-margin-start: 3px;
- -moz-margin-end: 2px;
+ -moz-margin-end: 1px;
-moz-image-region: rect(0, 16px, 16px, 0);
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box > #page-proxy-favicon {
- -moz-margin-end: 1px;
-}
-
#identity-box:hover > #page-proxy-favicon {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#identity-box:hover:active > #page-proxy-favicon,
#identity-box[open=true] > #page-proxy-favicon {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
--- a/browser/themes/linux/downloads/downloads.css
+++ b/browser/themes/linux/downloads/downloads.css
@@ -13,23 +13,32 @@
padding: 4px;
color: inherit;
}
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
display: none;
}
+#downloadsPanel[hasdownloads] > #emptyDownloads {
+ display: none;
+}
+
+#emptyDownloads {
+ padding: 10px 20px;
+ max-width: 40ch;
+}
+
#downloadsHistory {
background: transparent;
color: -moz-nativehyperlinktext;
cursor: pointer;
}
-#downloadsPanel[hasdownloads] > #downloadsFooter {
+#downloadsFooter {
border-top: 1px solid ThreeDShadow;
background-image: linear-gradient(hsla(0,0%,0%,.15), hsla(0,0%,0%,.08) 6px);
}
#downloadsHistory > .button-box {
margin: 1em;
}
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -2,18 +2,18 @@
* 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/. */
@import url("chrome://global/skin/");
%include shared.inc
%filter substitution
%define forwardTransitionLength 150ms
-%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
-%define conditionalForwardWithUrlbarWidth 30
+%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-wrapper
+%define conditionalForwardWithUrlbarWidth 32
%define spaceAboveTabbar 9px
%define toolbarButtonPressed :hover:active:not([disabled="true"]):not([cui-areatype="menu-panel"])
%define windowButtonMarginTop 11px
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
@namespace html url("http://www.w3.org/1999/xhtml");
@namespace svg url("http://www.w3.org/2000/svg");
@@ -1415,30 +1415,27 @@ toolbarbutton[sdk-button="true"][cui-are
}
#back-button:-moz-window-inactive,
#forward-button:-moz-window-inactive {
background-color: rgba(0,0,0,0.04);
border-color: rgba(0,0,0,0.2);
}
-#back-button:-moz-locale-dir(rtl),
-#forward-button:-moz-locale-dir(rtl) {
+#back-button:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
/* Back button styles */
#back-button {
- -moz-margin-end: -7px;
- position: relative;
- z-index: 1;
width: 32px;
height: 32px;
padding: 4px 5px 4px 3px;
+ -moz-margin-end: 0;
border-radius: 10000px;
}
#back-button:not(:-moz-lwtheme) {
height: 33px;
padding: 4px 5px 5px 3px;
margin-bottom: -1px;
background: url(chrome://browser/skin/keyhole-circle.png) 0 0 no-repeat;
@@ -1458,68 +1455,50 @@ toolbarbutton[sdk-button="true"][cui-are
#back-button:not([disabled="true"]):active:hover:not(:-moz-lwtheme),
#back-button[open="true"]:not(:-moz-lwtheme) {
background-position: -32px 0;
}
/* Forward button styles */
#forward-button {
- -moz-margin-start: 0;
- -moz-margin-end: 0;
+ margin-left: -2px;
+ margin-right: 0;
+ padding-left: 2px;
width: 32px;
- clip-path: url(chrome://browser/content/browser.xul#osx-keyhole-forward-clip-path);
}
#forward-button > .toolbarbutton-icon {
/* shift the icon away from the back button */
margin-left: 3px;
margin-right: -1px;
}
-#forward-button:-moz-lwtheme {
- -moz-padding-start: 2px;
- -moz-padding-end: 0;
-}
-
#forward-button:not(:-moz-lwtheme) {
- -moz-padding-start: 2px;
background: linear-gradient(hsl(0,0%,99%), hsl(0,0%,67%)) padding-box;
border: 1px solid;
border-color: hsl(0,0%,31%) hsla(0,0%,29%,.6) hsl(0,0%,27%);
box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35),
0 1px 0 hsla(0,0%,100%,.2);
}
-#urlbar-container:not([switchingtabs]) > #forward-button {
- transition: opacity @forwardTransitionLength@ ease-out;
-}
-
#forward-button:hover:active:not(:-moz-lwtheme) {
background-image: linear-gradient(hsl(0,0%,74%), hsl(0,0%,61%));
box-shadow: inset rgba(0,0,0,.3) 0 -6px 10px,
inset #000 0 1px 3px,
inset rgba(0,0,0,.2) 0 1px 3px,
0 1px 0 hsla(0,0%,100%,.2);
}
#forward-button:-moz-window-inactive:not(:-moz-lwtheme) {
border-color: hsl(0,0%,64%) hsl(0,0%,65%) hsl(0,0%,66%);
background-image: linear-gradient(hsl(0,0%,99%), hsl(0,0%,82%));
box-shadow: inset 0 1px 0 hsla(0,0%,100%,.35);
}
-#urlbar-container:not(:hover) > #forward-button[disabled] {
- opacity: 0;
-}
-
-@conditionalForwardWithUrlbar@ > #forward-button[occluded-by-urlbar] {
- visibility: hidden;
-}
-
@media (-moz-mac-lion-theme) {
#forward-button:not(:-moz-lwtheme) {
background-image: linear-gradient(hsla(0,0%,100%,.73), hsla(0,0%,100%,.05) 85%);
border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.25) hsla(0,0%,0%,.2);
box-shadow: inset 0 1px 0 hsla(0,0%,100%,.2),
inset 0 0 1px hsla(0,0%,100%,.1),
0 1px 0 hsla(0,0%,100%,.2);
}
@@ -1533,16 +1512,34 @@ toolbarbutton[sdk-button="true"][cui-are
}
#forward-button:-moz-window-inactive:not(:-moz-lwtheme) {
background-image: none;
border-color: hsla(0,0%,0%,.2);
}
}
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
+ transition: margin-left @forwardTransitionLength@ ease-out;
+}
+
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] {
+ margin-left: -@conditionalForwardWithUrlbarWidth@px;
+}
+
+@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] {
+ /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
+ transition-delay: 100s;
+}
+
+@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
+ /* when not hovered anymore, trigger a new transition to hide the forward button immediately */
+ margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
+}
+
.unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr),
.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/menu-back.png") !important;
}
.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(ltr),
.unified-nav-back[_moz-menuactive]:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/menu-forward.png") !important;
@@ -1716,69 +1713,46 @@ toolbarbutton[sdk-button="true"][cui-are
-moz-box-align: center;
}
#urlbar {
-moz-padding-end: 4px;
border-radius: @toolbarbuttonCornerRadius@;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
- padding-left: @conditionalForwardWithUrlbarWidth@px;
- -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
- position: relative;
- pointer-events: none;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
+@conditionalForwardWithUrlbar@ > #urlbar {
-moz-border-start: none;
margin-left: 0;
- pointer-events: all;
-}
-
-@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
- transition: margin-left @forwardTransitionLength@ ease-out;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
+}
+
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(rtl) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
- clip-path: url("chrome://browser/content/browser.xul#osx-urlbar-back-button-clip-path");
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
- margin-left: -@conditionalForwardWithUrlbarWidth@px;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
- /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
- transition-delay: 100s;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar,
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
- /* when switching tabs, or when not hovered anymore, trigger a new transition
- * to hide the forward button immediately */
- margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
- /* let osx-urlbar-back-button-clip-path clip the urlbar's right side for RTL */
+@conditionalForwardWithUrlbar@ {
+ clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
+ -moz-margin-start: -6px;
+}
+
+@conditionalForwardWithUrlbar@:-moz-locale-dir(rtl),
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(rtl) {
+ /* let urlbar-back-button-clip-path clip the urlbar's right side for RTL */
transform: scaleX(-1);
}
+@conditionalForwardWithUrlbar@:-moz-locale-dir(rtl) {
+ -moz-box-direction: reverse;
+}
+
#identity-box {
-moz-margin-end: 3px;
padding-top: 1px;
padding-bottom: 1px;
-moz-padding-start: 4px;
-moz-padding-end: 0;
font-size: .9em;
}
@@ -1793,42 +1767,42 @@ toolbarbutton[sdk-button="true"][cui-are
border-bottom-right-radius: 2px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px;
border-radius: 0;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
+@conditionalForwardWithUrlbar@ > #urlbar > #identity-box {
border-radius: 0;
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
- transition: 0s padding-left;
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar > #identity-box {
+ transition: padding-left, padding-right;
+}
+
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 10px;
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
- transition: 0s padding-right;
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 10px;
}
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
- /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
+@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box {
+ /* forward button hiding is delayed when hovered */
transition-delay: 100s;
}
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr),
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 10.01px;
}
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 10.01px;
}
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
-moz-padding-end: 4px;
}
@@ -3395,17 +3369,17 @@ toolbarbutton.chevron > .toolbarbutton-m
}
@media (min-resolution: 2dppx) {
#notification-popup-box {
border-image: url("chrome://browser/skin/urlbar-arrow@2x.png") 0 16 0 0 fill;
}
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box {
+@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar > #notification-popup-box {
padding-left: 7px;
}
#notification-popup-box:-moz-locale-dir(rtl),
.notification-anchor-icon:-moz-locale-dir(rtl) {
transform: scaleX(-1);
}
--- a/browser/themes/osx/downloads/downloads.css
+++ b/browser/themes/osx/downloads/downloads.css
@@ -17,28 +17,37 @@
padding: 4px;
color: inherit;
}
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
display: none;
}
+#downloadsPanel[hasdownloads] > #emptyDownloads {
+ display: none;
+}
+
+#emptyDownloads {
+ padding: 10px 20px;
+ max-width: 40ch;
+}
+
#downloadsFooter {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
#downloadsHistory {
background: transparent;
color: hsl(210,100%,75%);
cursor: pointer;
}
-#downloadsPanel[hasdownloads] > #downloadsFooter {
+#downloadsFooter {
background: #e5e5e5;
border-top: 1px solid hsla(0,0%,0%,.1);
box-shadow: 0 -1px hsla(0,0%,100%,.5) inset, 0 1px 1px hsla(0,0%,0%,.03) inset;
}
#downloadsHistory > .button-box {
color: #808080;
margin: 1em;
@@ -47,21 +56,16 @@
#downloadsPanel[keyfocus] > #downloadsFooter > #downloadsSummary:focus,
#downloadsPanel[keyfocus] > #downloadsFooter > #downloadsHistory:focus {
outline: 2px -moz-mac-focusring solid;
outline-offset: -2px;
-moz-outline-radius-bottomleft: 4px;
-moz-outline-radius-bottomright: 4px;
}
-#downloadsPanel:not([hasdownloads]) > #downloadsFooter > #downloadsHistory:focus {
- -moz-outline-radius-topleft: 4px;
- -moz-outline-radius-topright: 4px;
-}
-
/*** Downloads Summary and List items ***/
#downloadsSummary,
richlistitem[type="download"] {
height: 7em;
-moz-padding-end: 0;
color: inherit;
}
--- a/browser/themes/windows/browser.css
+++ b/browser/themes/windows/browser.css
@@ -9,17 +9,17 @@
@namespace svg url("http://www.w3.org/2000/svg");
%include ../shared/browser.inc
%include windowsShared.inc
%filter substitution
%define toolbarShadowColor hsla(209,67%,12%,0.35)
%define navbarTextboxCustomBorder border-color: rgba(0,0,0,.32);
%define forwardTransitionLength 150ms
-%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-container
+%define conditionalForwardWithUrlbar window:not([chromehidden~="toolbar"]) #urlbar-wrapper
%define conditionalForwardWithUrlbarWidth 30
#menubar-items {
-moz-box-orient: vertical; /* for flex hack */
}
#main-menubar {
-moz-box-flex: 1; /* make menu items expand to fill toolbar height */
@@ -881,46 +881,38 @@ toolbarbutton[sdk-button="true"][cui-are
}
#forward-button > menupopup {
margin-top: 1px !important;
}
#forward-button > .toolbarbutton-icon {
background-clip: padding-box !important;
- /*mask: url(keyhole-forward-mask.svg#mask); XXX: this regresses twinopen */
- clip-path: url(chrome://browser/content/browser.xul#keyhole-forward-clip-path) !important;
- margin-left: -6px !important;
border-left-style: none !important;
border-radius: 0 !important;
padding-left: 9px !important;
padding-right: 3px !important;
}
-%ifdef WINDOWS_AERO
-@media (-moz-os-version: windows-vista),
- (-moz-os-version: windows-win7) {
-%endif
- #forward-button > .toolbarbutton-icon {
- margin-left: -6px !important;
- }
-%ifdef WINDOWS_AERO
-}
-%endif
-
@conditionalForwardWithUrlbar@:not([switchingtabs]) > #forward-button {
- transition: opacity @forwardTransitionLength@ ease-out;
+ transition: margin-left @forwardTransitionLength@ ease-out;
+}
+
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] {
+ margin-left: -@conditionalForwardWithUrlbarWidth@px;
+}
+
+@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] {
+ /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
+ transition-delay: 100s;
}
@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] {
- opacity: 0;
-}
-
-@conditionalForwardWithUrlbar@ > #forward-button[occluded-by-urlbar] {
- visibility: hidden;
+ /* when not hovered anymore, trigger a new transition to hide the forward button immediately */
+ margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
}
#back-button {
padding-top: 3px !important;
padding-bottom: 3px !important;
-moz-padding-start: 5px !important;
-moz-padding-end: 0 !important;
position: relative !important;
@@ -994,18 +986,17 @@ toolbarbutton[sdk-button="true"][cui-are
box-shadow: 0 0 0 1px hsla(210,54%,20%,.55),
0 1px 0 hsla(210,54%,20%,.65) !important;
transition: none;
}
%ifdef WINDOWS_AERO
}
%endif
-#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon,
-#forward-button:-moz-locale-dir(rtl) {
+#back-button:-moz-locale-dir(rtl) > .toolbarbutton-icon {
transform: scaleX(-1);
}
.unified-nav-back[_moz-menuactive]:-moz-locale-dir(ltr),
.unified-nav-forward[_moz-menuactive]:-moz-locale-dir(rtl) {
list-style-image: url("chrome://browser/skin/menu-back.png") !important;
}
@@ -1167,69 +1158,46 @@ toolbarbutton[sdk-button="true"][cui-are
background-color: rgba(255,255,255,.9);
}
#urlbar:-moz-lwtheme[focused]:not([readonly]),
.searchbar-textbox:-moz-lwtheme[focused] {
background-color: white;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper {
- padding-left: @conditionalForwardWithUrlbarWidth@px;
- -moz-margin-start: -@conditionalForwardWithUrlbarWidth@px;
- position: relative;
- pointer-events: none;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar {
+@conditionalForwardWithUrlbar@ > #urlbar {
-moz-border-start: none;
margin-left: 0;
- pointer-events: all;
-}
-
-@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
- transition: margin-left @forwardTransitionLength@ ease-out;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(ltr) {
+}
+
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(ltr) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(rtl) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper {
+@conditionalForwardWithUrlbar@ {
clip-path: url("chrome://browser/content/browser.xul#urlbar-back-button-clip-path");
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar {
- margin-left: -@conditionalForwardWithUrlbarWidth@px;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar {
- /* delay the hiding of the forward button when hovered to avoid accidental clicks on the url bar */
- transition-delay: 100s;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar,
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar {
- /* when switching tabs, or when not hovered anymore, trigger a new transition
- * to hide the forward button immediately */
- margin-left: -@conditionalForwardWithUrlbarWidth@.01px;
-}
-
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar:-moz-locale-dir(rtl) {
- /* let windows-urlbar-back-button-mask clip the urlbar's right side for RTL */
+ -moz-margin-start: -5px;
+}
+
+@conditionalForwardWithUrlbar@:-moz-locale-dir(rtl),
+@conditionalForwardWithUrlbar@ > #urlbar:-moz-locale-dir(rtl) {
+ /* let urlbar-back-button-clip-path clip the urlbar's right side for RTL */
transform: scaleX(-1);
}
+@conditionalForwardWithUrlbar@:-moz-locale-dir(rtl) {
+ -moz-box-direction: reverse;
+}
+
html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
.searchbar-textbox:-moz-lwtheme > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input::-moz-placeholder {
opacity: 1.0;
color: #777;
}
#urlbar-container {
-moz-box-align: center;
@@ -1309,43 +1277,43 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
border-bottom-right-radius: 1.5px;
}
#notification-popup-box:not([hidden]) + #identity-box {
-moz-padding-start: 10px;
border-radius: 0;
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box {
+@conditionalForwardWithUrlbar@ > #urlbar > #identity-box {
border-radius: 0;
}
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@:not([switchingtabs]) > #urlbar > #identity-box {
+ transition: padding-left, padding-right;
+}
+
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
padding-left: 5px;
- transition: padding-left;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled] > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+}
+
+@conditionalForwardWithUrlbar@ > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
padding-right: 5px;
- transition: padding-right;
-}
-
-@conditionalForwardWithUrlbar@[forwarddisabled]:hover:not([switchingtabs]) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box {
+}
+
+@conditionalForwardWithUrlbar@:hover:not([switchingtabs]) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box {
/* forward button hiding is delayed when hovered */
transition-delay: 100s;
}
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr),
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
+@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(ltr) {
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
padding-left: 5.01px;
}
-@conditionalForwardWithUrlbar@[forwarddisabled][switchingtabs] + #urlbar-container > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl),
-@conditionalForwardWithUrlbar@[forwarddisabled]:not(:hover) > #urlbar-wrapper > #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
+@conditionalForwardWithUrlbar@:not(:hover) > #forward-button[disabled] + #urlbar > #notification-popup-box[hidden] + #identity-box:-moz-locale-dir(rtl) {
/* when not hovered anymore, trigger a new non-delayed transition to react to the forward button hiding */
padding-right: 5.01px;
}
#urlbar[pageproxystate="valid"] > #identity-box.chromeUI,
#urlbar[pageproxystate="valid"] > #identity-box.verifiedIdentity {
-moz-margin-end: 4px;
}
@@ -1390,24 +1358,20 @@ html|*.urlbar-input:-moz-lwtheme::-moz-p
/* page proxy icon */
%include ../shared/identity-block.inc.css
#page-proxy-favicon {
margin-top: 1px;
margin-bottom: 1px;
-moz-margin-start: 3px;
- -moz-margin-end: 2px;
+ -moz-margin-end: 1px;
-moz-image-region: rect(0, 16px, 16px, 0);
}
-@conditionalForwardWithUrlbar@ > #urlbar-wrapper > #urlbar > #identity-box > #page-proxy-favicon {
- -moz-margin-end: 1px;
-}
-
#identity-box:hover > #page-proxy-favicon {
-moz-image-region: rect(0, 32px, 16px, 16px);
}
#identity-box:hover:active > #page-proxy-favicon,
#identity-box[open=true] > #page-proxy-favicon {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
--- a/browser/themes/windows/downloads/downloads.css
+++ b/browser/themes/windows/downloads/downloads.css
@@ -13,16 +13,25 @@
padding: 4px;
color: inherit;
}
#downloadsPanel:not([hasdownloads]) > #downloadsListBox {
display: none;
}
+#downloadsPanel[hasdownloads] > #emptyDownloads {
+ display: none;
+}
+
+#emptyDownloads {
+ padding: 10px 20px;
+ max-width: 40ch;
+}
+
#downloadsHistory {
background: transparent;
cursor: pointer;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
@@ -39,46 +48,46 @@
outline-offset: -1px;
}
#downloadsHistory > .button-box {
border: none;
margin: 1em;
}
-#downloadsPanel[hasdownloads] > #downloadsFooter {
+#downloadsFooter {
background-color: hsla(210,4%,10%,.04);
box-shadow: 0 1px 0 hsla(210,4%,10%,.08) inset;
transition-duration: 150ms;
transition-property: background-color;
}
-#downloadsPanel[hasdownloads] > #downloadsFooter:hover {
+#downloadsFooter:hover {
background-color: hsla(210,4%,10%,.05);
}
-#downloadsPanel[hasdownloads] > #downloadsFooter:hover:active {
+#downloadsFooter:hover:active {
background-color: hsla(210,4%,10%,.1);
box-shadow: 0 2px 0 0 hsla(210,4%,10%,.1) inset;
}
%ifdef WINDOWS_AERO
@media (-moz-os-version: windows-vista),
(-moz-os-version: windows-win7) {
%endif
@media (-moz-windows-default-theme) {
- #downloadsPanel[hasdownloads] > #downloadsFooter {
+ #downloadsFooter {
border-bottom-left-radius: 3px;
border-bottom-right-radius: 3px;
transition-duration: 0s;
}
- #downloadsPanel[hasdownloads] > #downloadsFooter,
- #downloadsPanel[hasdownloads] > #downloadsFooter:hover,
- #downloadsPanel[hasdownloads] > #downloadsFooter:hover:active {
+ #downloadsFooter,
+ #downloadsFooter:hover,
+ #downloadsFooter:hover:active {
%ifdef WINDOWS_AERO
background-color: #f1f5fb;
%else
background-color: hsla(216,45%,88%,.98);
%endif
box-shadow: 0px 1px 2px rgb(204,214,234) inset;
}
}
--- a/dom/apps/src/InterAppCommService.js
+++ b/dom/apps/src/InterAppCommService.js
@@ -1,874 +1,28 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/AppsUtils.jsm");
+Cu.import("resource://gre/modules/InterAppCommService.jsm");
-const DEBUG = false;
-function debug(aMsg) {
- dump("-- InterAppCommService: " + Date.now() + ": " + aMsg + "\n");
+function InterAppCommServiceProxy() {
}
-XPCOMUtils.defineLazyServiceGetter(this, "appsService",
- "@mozilla.org/AppsService;1",
- "nsIAppsService");
-
-XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
- "@mozilla.org/parentprocessmessagemanager;1",
- "nsIMessageBroadcaster");
-
-XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator",
- "@mozilla.org/uuid-generator;1",
- "nsIUUIDGenerator");
-
-XPCOMUtils.defineLazyServiceGetter(this, "messenger",
- "@mozilla.org/system-message-internal;1",
- "nsISystemMessagesInternal");
-
-const kMessages =["Webapps:Connect",
- "Webapps:GetConnections",
- "InterAppConnection:Cancel",
- "InterAppMessagePort:PostMessage",
- "InterAppMessagePort:Register",
- "InterAppMessagePort:Unregister",
- "child-process-shutdown"];
-
-function InterAppCommService() {
- Services.obs.addObserver(this, "xpcom-shutdown", false);
- Services.obs.addObserver(this, "inter-app-comm-select-app-result", false);
-
- kMessages.forEach(function(aMsg) {
- ppmm.addMessageListener(aMsg, this);
- }, this);
-
- // This matrix is used for saving the inter-app connection info registered in
- // the app manifest. The object literal is defined as below:
- //
- // {
- // "keyword1": {
- // "subAppManifestURL1": {
- // /* subscribed info */
- // },
- // "subAppManifestURL2": {
- // /* subscribed info */
- // },
- // ...
- // },
- // "keyword2": {
- // "subAppManifestURL3": {
- // /* subscribed info */
- // },
- // ...
- // },
- // ...
- // }
- //
- // For example:
- //
- // {
- // "foo": {
- // "app://subApp1.gaiamobile.org/manifest.webapp": {
- // pageURL: "app://subApp1.gaiamobile.org/handler.html",
- // description: "blah blah",
- // rules: { ... }
- // },
- // "app://subApp2.gaiamobile.org/manifest.webapp": {
- // pageURL: "app://subApp2.gaiamobile.org/handler.html",
- // description: "blah blah",
- // rules: { ... }
- // }
- // },
- // "bar": {
- // "app://subApp3.gaiamobile.org/manifest.webapp": {
- // pageURL: "app://subApp3.gaiamobile.org/handler.html",
- // description: "blah blah",
- // rules: { ... }
- // }
- // }
- // }
- //
- // TODO Bug 908999 - Update registered connections when app gets uninstalled.
- this._registeredConnections = {};
-
- // This matrix is used for saving the permitted connections, which allows
- // the messaging between publishers and subscribers. The object literal is
- // defined as below:
- //
- // {
- // "keyword1": {
- // "pubAppManifestURL1": [
- // "subAppManifestURL1",
- // "subAppManifestURL2",
- // ...
- // ],
- // "pubAppManifestURL2": [
- // "subAppManifestURL3",
- // "subAppManifestURL4",
- // ...
- // ],
- // ...
- // },
- // "keyword2": {
- // "pubAppManifestURL3": [
- // "subAppManifestURL5",
- // ...
- // ],
- // ...
- // },
- // ...
- // }
- //
- // For example:
- //
- // {
- // "foo": {
- // "app://pubApp1.gaiamobile.org/manifest.webapp": [
- // "app://subApp1.gaiamobile.org/manifest.webapp",
- // "app://subApp2.gaiamobile.org/manifest.webapp"
- // ],
- // "app://pubApp2.gaiamobile.org/manifest.webapp": [
- // "app://subApp3.gaiamobile.org/manifest.webapp",
- // "app://subApp4.gaiamobile.org/manifest.webapp"
- // ]
- // },
- // "bar": {
- // "app://pubApp3.gaiamobile.org/manifest.webapp": [
- // "app://subApp5.gaiamobile.org/manifest.webapp",
- // ]
- // }
- // }
- //
- // TODO Bug 908999 - Update allowed connections when app gets uninstalled.
- this._allowedConnections = {};
-
- // This matrix is used for saving the caller info from the content process,
- // which is indexed by a random UUID, to know where to return the promise
- // resolvser's callback when the prompt UI for allowing connections returns.
- // An example of the object literal is shown as below:
- //
- // {
- // "fooID": {
- // outerWindowID: 12,
- // requestID: 34,
- // target: pubAppTarget1
- // },
- // "barID": {
- // outerWindowID: 56,
- // requestID: 78,
- // target: pubAppTarget2
- // }
- // }
- //
- // where |outerWindowID| is the ID of the window requesting the connection,
- // |requestID| is the ID specifying the promise resolver to return,
- // |target| is the target of the process requesting the connection.
- this._promptUICallers = {};
-
- // This matrix is used for saving the pair of message ports, which is indexed
- // by a random UUID, so that each port can know whom it should talk to.
- // An example of the object literal is shown as below:
- //
- // {
- // "UUID1": {
- // keyword: "keyword1",
- // publisher: {
- // manifestURL: "app://pubApp1.gaiamobile.org/manifest.webapp",
- // target: pubAppTarget1,
- // pageURL: "app://pubApp1.gaiamobile.org/caller.html",
- // messageQueue: [...]
- // },
- // subscriber: {
- // manifestURL: "app://subApp1.gaiamobile.org/manifest.webapp",
- // target: subAppTarget1,
- // pageURL: "app://pubApp1.gaiamobile.org/handler.html",
- // messageQueue: [...]
- // }
- // },
- // "UUID2": {
- // keyword: "keyword2",
- // publisher: {
- // manifestURL: "app://pubApp2.gaiamobile.org/manifest.webapp",
- // target: pubAppTarget2,
- // pageURL: "app://pubApp2.gaiamobile.org/caller.html",
- // messageQueue: [...]
- // },
- // subscriber: {
- // manifestURL: "app://subApp2.gaiamobile.org/manifest.webapp",
- // target: subAppTarget2,
- // pageURL: "app://pubApp2.gaiamobile.org/handler.html",
- // messageQueue: [...]
- // }
- // }
- // }
- this._messagePortPairs = {};
-}
-
-InterAppCommService.prototype = {
+InterAppCommServiceProxy.prototype = {
registerConnection: function(aKeyword, aHandlerPageURI, aManifestURI,
aDescription, aRules) {
- let manifestURL = aManifestURI.spec;
- let pageURL = aHandlerPageURI.spec;
-
- if (DEBUG) {
- debug("registerConnection: aKeyword: " + aKeyword +
- " manifestURL: " + manifestURL + " pageURL: " + pageURL +
- " aDescription: " + aDescription +
- " aRules.minimumAccessLevel: " + aRules.minimumAccessLevel +
- " aRules.manifestURLs: " + aRules.manifestURLs +
- " aRules.installOrigins: " + aRules.installOrigins);
- }
-
- let subAppManifestURLs = this._registeredConnections[aKeyword];
- if (!subAppManifestURLs) {
- subAppManifestURLs = this._registeredConnections[aKeyword] = {};
- }
-
- subAppManifestURLs[manifestURL] = {
- pageURL: pageURL,
- description: aDescription,
- rules: aRules,
- manifestURL: manifestURL
- };
- },
-
- _matchMinimumAccessLevel: function(aRules, aAppStatus) {
- if (!aRules || !aRules.minimumAccessLevel) {
- if (DEBUG) {
- debug("rules.minimumAccessLevel is not available. No need to match.");
- }
- return true;
- }
-
- let minAccessLevel = aRules.minimumAccessLevel;
- switch (minAccessLevel) {
- case "web":
- if (aAppStatus == Ci.nsIPrincipal.APP_STATUS_INSTALLED ||
- aAppStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED ||
- aAppStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
- return true;
- }
- break;
- case "privileged":
- if (aAppStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED ||
- aAppStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
- return true;
- }
- break;
- case "certified":
- if (aAppStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
- return true;
- }
- break;
- }
-
- if (DEBUG) {
- debug("rules.minimumAccessLevel is not matched!" +
- " minAccessLevel: " + minAccessLevel +
- " aAppStatus : " + aAppStatus);
- }
- return false;
- },
-
- _matchManifestURLs: function(aRules, aManifestURL) {
- if (!aRules || !Array.isArray(aRules.manifestURLs)) {
- if (DEBUG) {
- debug("rules.manifestURLs is not available. No need to match.");
- }
- return true;
- }
-
- let manifestURLs = aRules.manifestURLs;
- if (manifestURLs.indexOf(aManifestURL) != -1) {
- return true;
- }
-
- if (DEBUG) {
- debug("rules.manifestURLs is not matched!" +
- " manifestURLs: " + manifestURLs +
- " aManifestURL : " + aManifestURL);
- }
- return false;
- },
-
- _matchInstallOrigins: function(aRules, aInstallOrigin) {
- if (!aRules || !Array.isArray(aRules.installOrigins)) {
- if (DEBUG) {
- debug("rules.installOrigins is not available. No need to match.");
- }
- return true;
- }
-
- let installOrigins = aRules.installOrigins;
- if (installOrigins.indexOf(aInstallOrigin) != -1) {
- return true;
- }
-
- if (DEBUG) {
- debug("rules.installOrigins is not matched!" +
- " installOrigins: " + installOrigins +
- " installOrigin : " + aInstallOrigin);
- }
- return false;
- },
-
- _matchRules: function(aPubAppManifestURL, aPubRules,
- aSubAppManifestURL, aSubRules) {
- let pubApp = appsService.getAppByManifestURL(aPubAppManifestURL);
- let subApp = appsService.getAppByManifestURL(aSubAppManifestURL);
-
- // TODO Bug 907068 In the initiative step, we only expose this API to
- // certified apps to meet the time line. Eventually, we need to make
- // it available for the non-certified apps as well. For now, only the
- // certified apps can match the rules.
- if (pubApp.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED ||
- subApp.appStatus != Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
- if (DEBUG) {
- debug("Only certified apps are allowed to do connections.");
- }
- return false;
- }
-
- if (!aPubRules && !aSubRules) {
- if (DEBUG) {
- debug("No rules for publisher and subscriber. No need to match.");
- }
- return true;
- }
-
- // Check minimumAccessLevel.
- if (!this._matchMinimumAccessLevel(aPubRules, subApp.appStatus) ||
- !this._matchMinimumAccessLevel(aSubRules, pubApp.appStatus)) {
- return false;
- }
-
- // Check manifestURLs.
- if (!this._matchManifestURLs(aPubRules, aSubAppManifestURL) ||
- !this._matchManifestURLs(aSubRules, aPubAppManifestURL)) {
- return false;
- }
-
- // Check installOrigins.
- if (!this._matchInstallOrigins(aPubRules, subApp.installOrigin) ||
- !this._matchInstallOrigins(aSubRules, pubApp.installOrigin)) {
- return false;
- }
-
- // Check developers.
- // TODO Do we really want to check this? This one seems naive.
-
- if (DEBUG) debug("All rules are matched.");
- return true;
- },
-
- _dispatchMessagePorts: function(aKeyword, aPubAppManifestURL,
- aAllowedSubAppManifestURLs,
- aTarget, aOuterWindowID, aRequestID) {
- if (DEBUG) {
- debug("_dispatchMessagePorts: aKeyword: " + aKeyword +
- " aPubAppManifestURL: " + aPubAppManifestURL +
- " aAllowedSubAppManifestURLs: " + aAllowedSubAppManifestURLs);
- }
-
- if (aAllowedSubAppManifestURLs.length == 0) {
- if (DEBUG) debug("No apps are allowed to connect. Returning.");
- aTarget.sendAsyncMessage("Webapps:Connect:Return:KO",
- { oid: aOuterWindowID, requestID: aRequestID });
- return;
- }
-
- let subAppManifestURLs = this._registeredConnections[aKeyword];
- if (!subAppManifestURLs) {
- if (DEBUG) debug("No apps are subscribed to connect. Returning.");
- aTarget.sendAsyncMessage("Webapps:Connect:Return:KO",
- { oid: aOuterWindowID, requestID: aRequestID });
- return;
- }
-
- let messagePortIDs = [];
- aAllowedSubAppManifestURLs.forEach(function(aAllowedSubAppManifestURL) {
- let subscribedInfo = subAppManifestURLs[aAllowedSubAppManifestURL];
- if (!subscribedInfo) {
- if (DEBUG) {
- debug("The sunscribed info is not available. Skipping: " +
- aAllowedSubAppManifestURL);
- }
- return;
- }
-
- // The message port ID is aimed for identifying the coupling targets
- // to deliver messages with each other. This ID is centrally generated
- // by the parent and dispatched to both the sender and receiver ends
- // for creating their own message ports respectively.
- let messagePortID = UUIDGenerator.generateUUID().toString();
- this._messagePortPairs[messagePortID] = {
- keyword: aKeyword,
- publisher: {
- manifestURL: aPubAppManifestURL
- },
- subscriber: {
- manifestURL: aAllowedSubAppManifestURL
- }
- };
-
- // Fire system message to deliver the message port to the subscriber.
- messenger.sendMessage("connection",
- { keyword: aKeyword,
- messagePortID: messagePortID },
- Services.io.newURI(subscribedInfo.pageURL, null, null),
- Services.io.newURI(subscribedInfo.manifestURL, null, null));
-
- messagePortIDs.push(messagePortID);
- }, this);
-
- if (messagePortIDs.length == 0) {
- if (DEBUG) debug("No apps are subscribed to connect. Returning.");
- aTarget.sendAsyncMessage("Webapps:Connect:Return:KO",
- { oid: aOuterWindowID, requestID: aRequestID });
- return;
- }
-
- // Return the message port IDs to open the message ports for the publisher.
- if (DEBUG) debug("messagePortIDs: " + messagePortIDs);
- aTarget.sendAsyncMessage("Webapps:Connect:Return:OK",
- { keyword: aKeyword,
- messagePortIDs: messagePortIDs,
- oid: aOuterWindowID, requestID: aRequestID });
- },
-
- _connect: function(aMessage, aTarget) {
- let keyword = aMessage.keyword;
- let pubRules = aMessage.rules;
- let pubAppManifestURL = aMessage.manifestURL;
- let outerWindowID = aMessage.outerWindowID;
- let requestID = aMessage.requestID;
-
- let subAppManifestURLs = this._registeredConnections[keyword];
- if (!subAppManifestURLs) {
- if (DEBUG) {
- debug("No apps are subscribed for this connection. Returning.");
- }
- this._dispatchMessagePorts(keyword, pubAppManifestURL, [],
- aTarget, outerWindowID, requestID);
- return;
- }
-
- // Fetch the apps that used to be allowed to connect before, so that
- // users don't need to select/allow them again. That is, we only pop up
- // the prompt UI for the *new* connections.
- let allowedSubAppManifestURLs = [];
- let allowedPubAppManifestURLs = this._allowedConnections[keyword];
- if (allowedPubAppManifestURLs &&
- allowedPubAppManifestURLs[pubAppManifestURL]) {
- allowedSubAppManifestURLs = allowedPubAppManifestURLs[pubAppManifestURL];
- }
-
- // Check rules to see if a subscribed app is allowed to connect.
- let appsToSelect = [];
- for (let subAppManifestURL in subAppManifestURLs) {
- if (allowedSubAppManifestURLs.indexOf(subAppManifestURL) != -1) {
- if (DEBUG) {
- debug("Don't need to select again. Skipping: " + subAppManifestURL);
- }
- continue;
- }
-
- // Only rule-matched publishers/subscribers are allowed to connect.
- let subscribedInfo = subAppManifestURLs[subAppManifestURL];
- let subRules = subscribedInfo.rules;
-
- let matched =
- this._matchRules(pubAppManifestURL, pubRules,
- subAppManifestURL, subRules);
- if (!matched) {
- if (DEBUG) {
- debug("Rules are not matched. Skipping: " + subAppManifestURL);
- }
- continue;
- }
-
- appsToSelect.push({
- manifestURL: subAppManifestURL,
- description: subscribedInfo.description
- });
- }
-
- if (appsToSelect.length == 0) {
- if (DEBUG) {
- debug("No additional apps need to be selected for this connection. " +
- "Just dispatch message ports for the existing connections.");
- }
-
- this._dispatchMessagePorts(keyword, pubAppManifestURL,
- allowedSubAppManifestURLs,
- aTarget, outerWindowID, requestID);
- return;
- }
-
- // Remember the caller info with an UUID so that we can know where to
- // return the promise resolver's callback when the prompt UI returns.
- let callerID = UUIDGenerator.generateUUID().toString();
- this._promptUICallers[callerID] = {
- outerWindowID: outerWindowID,
- requestID: requestID,
- target: aTarget
- };
-
- // TODO Bug 897169 Temporarily disable the notification for popping up
- // the prompt until the UX/UI for the prompt is confirmed.
- //
- // TODO Bug 908191 We need to change the way of interaction between API and
- // run-time prompt from observer notification to xpcom-interface caller.
- //
- /*
- if (DEBUG) debug("appsToSelect: " + appsToSelect);
- Services.obs.notifyObservers(null, "inter-app-comm-select-app",
- JSON.stringify({ callerID: callerID,
- manifestURL: pubAppManifestURL,
- keyword: keyword,
- appsToSelect: appsToSelect }));
- */
-
- // TODO Bug 897169 Simulate the return of the app-selected result by
- // the prompt, which always allows the connection. This dummy codes
- // will be removed when the UX/UI for the prompt is ready.
- if (DEBUG) debug("appsToSelect: " + appsToSelect);
- Services.obs.notifyObservers(null, 'inter-app-comm-select-app-result',
- JSON.stringify({ callerID: callerID,
- manifestURL: pubAppManifestURL,
- keyword: keyword,
- selectedApps: appsToSelect }));
- },
-
- _getConnections: function(aMessage, aTarget) {
- let outerWindowID = aMessage.outerWindowID;
- let requestID = aMessage.requestID;
-
- let connections = [];
- for (let keyword in this._allowedConnections) {
- let allowedPubAppManifestURLs = this._allowedConnections[keyword];
- for (let allowedPubAppManifestURL in allowedPubAppManifestURLs) {
- let allowedSubAppManifestURLs =
- allowedPubAppManifestURLs[allowedPubAppManifestURL];
- allowedSubAppManifestURLs.forEach(function(allowedSubAppManifestURL) {
- connections.push({ keyword: keyword,
- pubAppManifestURL: allowedPubAppManifestURL,
- subAppManifestURL: allowedSubAppManifestURL });
- });
- }
- }
-
- aTarget.sendAsyncMessage("Webapps:GetConnections:Return:OK",
- { connections: connections,
- oid: outerWindowID, requestID: requestID });
- },
-
- _cancelConnection: function(aMessage) {
- let keyword = aMessage.keyword;
- let pubAppManifestURL = aMessage.pubAppManifestURL;
- let subAppManifestURL = aMessage.subAppManifestURL;
-
- let allowedPubAppManifestURLs = this._allowedConnections[keyword];
- if (!allowedPubAppManifestURLs) {
- if (DEBUG) debug("keyword is not found: " + keyword);
- return;
- }
-
- let allowedSubAppManifestURLs =
- allowedPubAppManifestURLs[pubAppManifestURL];
- if (!allowedSubAppManifestURLs) {
- if (DEBUG) debug("publisher is not found: " + pubAppManifestURL);
- return;
- }
-
- let index = allowedSubAppManifestURLs.indexOf(subAppManifestURL);
- if (index == -1) {
- if (DEBUG) debug("subscriber is not found: " + subAppManifestURL);
- return;
- }
-
- if (DEBUG) debug("Cancelling the connection.");
- allowedSubAppManifestURLs.splice(index, 1);
-
- // Clean up the parent entries if needed.
- if (allowedSubAppManifestURLs.length == 0) {
- delete allowedPubAppManifestURLs[pubAppManifestURL];
- if (Object.keys(allowedPubAppManifestURLs).length == 0) {
- delete this._allowedConnections[keyword];
- }
- }
-
- if (DEBUG) debug("Unregistering message ports based on this connection.");
- let messagePortIDs = [];
- for (let messagePortID in this._messagePortPairs) {
- let pair = this._messagePortPairs[messagePortID];
- if (pair.keyword == keyword &&
- pair.publisher.manifestURL == pubAppManifestURL &&
- pair.subscriber.manifestURL == subAppManifestURL) {
- messagePortIDs.push(messagePortID);
- }
- }
- messagePortIDs.forEach(function(aMessagePortID) {
- delete this._messagePortPairs[aMessagePortID];
- }, this);
- },
-
- _identifyMessagePort: function(aMessagePortID, aManifestURL) {
- let pair = this._messagePortPairs[aMessagePortID];
- if (!pair) {
- if (DEBUG) {
- debug("Error! The message port ID is invalid: " + aMessagePortID +
- ", which should have been generated by parent.");
- }
- return null;
- }
-
- // Check it the message port is for publisher.
- if (pair.publisher.manifestURL == aManifestURL) {
- return { pair: pair, isPublisher: true };
- }
-
- // Check it the message port is for subscriber.
- if (pair.subscriber.manifestURL == aManifestURL) {
- return { pair: pair, isPublisher: false };
- }
-
- if (DEBUG) {
- debug("Error! The manifest URL is invalid: " + aManifestURL +
- ", which might be a hacked app.");
- }
- return null;
- },
-
- _registerMessagePort: function(aMessage, aTarget) {
- let messagePortID = aMessage.messagePortID;
- let manifestURL = aMessage.manifestURL;
- let pageURL = aMessage.pageURL;
-
- let identity = this._identifyMessagePort(messagePortID, manifestURL);
- if (!identity) {
- if (DEBUG) {
- debug("Cannot identify the message port. Failed to register.");
- }
- return;
- }
-
- if (DEBUG) debug("Registering message port for " + manifestURL);
- let pair = identity.pair;
- let isPublisher = identity.isPublisher;
-
- let sender = isPublisher ? pair.publisher : pair.subscriber;
- sender.target = aTarget;
- sender.pageURL = pageURL;
- sender.messageQueue = [];
-
- // Check if the other port has queued messages. Deliver them if needed.
- if (DEBUG) {
- debug("Checking if the other port used to send messages but queued.");
- }
- let receiver = isPublisher ? pair.subscriber : pair.publisher;
- if (receiver.messageQueue) {
- while (receiver.messageQueue.length) {
- let message = receiver.messageQueue.shift();
- if (DEBUG) debug("Delivering message: " + JSON.stringify(message));
- sender.target.sendAsyncMessage("InterAppMessagePort:OnMessage",
- { message: message,
- manifestURL: sender.manifestURL,
- pageURL: sender.pageURL,
- messagePortID: messagePortID });
- }
- }
- },
-
- _unregisterMessagePort: function(aMessage) {
- let messagePortID = aMessage.messagePortID;
- let manifestURL = aMessage.manifestURL;
-
- let identity = this._identifyMessagePort(messagePortID, manifestURL);
- if (!identity) {
- if (DEBUG) {
- debug("Cannot identify the message port. Failed to unregister.");
- }
- return;
- }
-
- if (DEBUG) {
- debug("Unregistering message port for " + manifestURL);
- }
- delete this._messagePortPairs[messagePortID];
- },
-
- _removeTarget: function(aTarget) {
- if (!aTarget) {
- if (DEBUG) debug("Error! aTarget cannot be null/undefined in any way.");
- return
- }
-
- if (DEBUG) debug("Unregistering message ports based on this target.");
- let messagePortIDs = [];
- for (let messagePortID in this._messagePortPairs) {
- let pair = this._messagePortPairs[messagePortID];
- if (pair.publisher.target === aTarget ||
- pair.subscriber.target === aTarget) {
- messagePortIDs.push(messagePortID);
- }
- }
- messagePortIDs.forEach(function(aMessagePortID) {
- delete this._messagePortPairs[aMessagePortID];
- }, this);
- },
-
- _postMessage: function(aMessage) {
- let messagePortID = aMessage.messagePortID;
- let manifestURL = aMessage.manifestURL;
- let message = aMessage.message;
-
- let identity = this._identifyMessagePort(messagePortID, manifestURL);
- if (!identity) {
- if (DEBUG) debug("Cannot identify the message port. Failed to post.");
- return;
- }
-
- let pair = identity.pair;
- let isPublisher = identity.isPublisher;
-
- let receiver = isPublisher ? pair.subscriber : pair.publisher;
- if (!receiver.target) {
- if (DEBUG) {
- debug("The receiver's target is not ready yet. Queuing the message.");
- }
- let sender = isPublisher ? pair.publisher : pair.subscriber;
- sender.messageQueue.push(message);
- return;
- }
-
- if (DEBUG) debug("Delivering message: " + JSON.stringify(message));
- receiver.target.sendAsyncMessage("InterAppMessagePort:OnMessage",
- { manifestURL: receiver.manifestURL,
- pageURL: receiver.pageURL,
- messagePortID: messagePortID,
- message: message });
- },
-
- _handleSelectcedApps: function(aData) {
- let callerID = aData.callerID;
- let caller = this._promptUICallers[callerID];
- if (!caller) {
- if (DEBUG) debug("Error! Cannot find the caller.");
- return;
- }
-
- delete this._promptUICallers[callerID];
-
- let outerWindowID = caller.outerWindowID;
- let requestID = caller.requestID;
- let target = caller.target;
-
- let manifestURL = aData.manifestURL;
- let keyword = aData.keyword;
- let selectedApps = aData.selectedApps;
-
- if (selectedApps.length == 0) {
- if (DEBUG) debug("No apps are selected to connect.")
- this._dispatchMessagePorts(keyword, manifestURL, [],
- target, outerWindowID, requestID);
- return;
- }
-
- // Find the entry of allowed connections to add the selected apps.
- let allowedPubAppManifestURLs = this._allowedConnections[keyword];
- if (!allowedPubAppManifestURLs) {
- allowedPubAppManifestURLs = this._allowedConnections[keyword] = {};
- }
- let allowedSubAppManifestURLs = allowedPubAppManifestURLs[manifestURL];
- if (!allowedSubAppManifestURLs) {
- allowedSubAppManifestURLs = allowedPubAppManifestURLs[manifestURL] = [];
- }
-
- // Add the selected app into the existing set of allowed connections.
- selectedApps.forEach(function(aSelectedApp) {
- let allowedSubAppManifestURL = aSelectedApp.manifestURL;
- if (allowedSubAppManifestURLs.indexOf(allowedSubAppManifestURL) == -1) {
- allowedSubAppManifestURLs.push(allowedSubAppManifestURL);
- }
- });
-
- // Finally, dispatch the message ports for the allowed connections,
- // including the old connections and the newly selected connection.
- this._dispatchMessagePorts(keyword, manifestURL, allowedSubAppManifestURLs,
- target, outerWindowID, requestID);
- },
-
- receiveMessage: function(aMessage) {
- if (DEBUG) debug("receiveMessage: name: " + aMessage.name);
- let message = aMessage.json;
- let target = aMessage.target;
-
- // To prevent the hacked child process from sending commands to parent
- // to do illegal connections, we need to check its manifest URL.
- if (aMessage.name !== "child-process-shutdown" &&
- // TODO: fix bug 988142 to re-enable "InterAppMessagePort:Unregister".
- aMessage.name !== "InterAppMessagePort:Unregister" &&
- kMessages.indexOf(aMessage.name) != -1) {
- if (!target.assertContainApp(message.manifestURL)) {
- if (DEBUG) {
- debug("Got message from a process carrying illegal manifest URL.");
- }
- return null;
- }
- }
-
- switch (aMessage.name) {
- case "Webapps:Connect":
- this._connect(message, target);
- break;
- case "Webapps:GetConnections":
- this._getConnections(message, target);
- break;
- case "InterAppConnection:Cancel":
- this._cancelConnection(message);
- break;
- case "InterAppMessagePort:PostMessage":
- this._postMessage(message);
- break;
- case "InterAppMessagePort:Register":
- this._registerMessagePort(message, target);
- break;
- case "InterAppMessagePort:Unregister":
- this._unregisterMessagePort(message);
- break;
- case "child-process-shutdown":
- this._removeTarget(target);
- break;
- }
- },
-
- observe: function(aSubject, aTopic, aData) {
- switch (aTopic) {
- case "xpcom-shutdown":
- Services.obs.removeObserver(this, "xpcom-shutdown");
- Services.obs.removeObserver(this, "inter-app-comm-select-app-result");
- kMessages.forEach(function(aMsg) {
- ppmm.removeMessageListener(aMsg, this);
- }, this);
- ppmm = null;
- break;
- case "inter-app-comm-select-app-result":
- if (DEBUG) debug("inter-app-comm-select-app-result: " + aData);
- this._handleSelectcedApps(JSON.parse(aData));
- break;
- }
+ InterAppCommService.
+ registerConnection(aKeyword, aHandlerPageURI, aManifestURI,
+ aDescription, aRules);
},
classID: Components.ID("{3dd15ce6-e7be-11e2-82bc-77967e7a63e6}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterAppCommService,
- Ci.nsIObserver])
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterAppCommService])
}
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InterAppCommService]);
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InterAppCommServiceProxy]);
copy from dom/apps/src/InterAppCommService.js
copy to dom/apps/src/InterAppCommService.jsm
--- a/dom/apps/src/InterAppCommService.js
+++ b/dom/apps/src/InterAppCommService.jsm
@@ -1,16 +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/. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
+this.EXPORTED_SYMBOLS = ["InterAppCommService"];
+
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/AppsUtils.jsm");
const DEBUG = false;
function debug(aMsg) {
dump("-- InterAppCommService: " + Date.now() + ": " + aMsg + "\n");
}
@@ -34,187 +36,205 @@ XPCOMUtils.defineLazyServiceGetter(this,
const kMessages =["Webapps:Connect",
"Webapps:GetConnections",
"InterAppConnection:Cancel",
"InterAppMessagePort:PostMessage",
"InterAppMessagePort:Register",
"InterAppMessagePort:Unregister",
"child-process-shutdown"];
-function InterAppCommService() {
- Services.obs.addObserver(this, "xpcom-shutdown", false);
- Services.obs.addObserver(this, "inter-app-comm-select-app-result", false);
+/**
+ * This module contains helpers for Inter-App Communication API [1] related
+ * purposes, which plays the role of the central service receiving messages
+ * from and interacting with the content processes.
+ *
+ * [1] https://wiki.mozilla.org/WebAPI/Inter_App_Communication_Alt_proposal
+ */
- kMessages.forEach(function(aMsg) {
- ppmm.addMessageListener(aMsg, this);
- }, this);
+this.InterAppCommService = {
+ init: function() {
+ Services.obs.addObserver(this, "xpcom-shutdown", false);
+ Services.obs.addObserver(this, "inter-app-comm-select-app-result", false);
+
+ kMessages.forEach(function(aMsg) {
+ ppmm.addMessageListener(aMsg, this);
+ }, this);
- // This matrix is used for saving the inter-app connection info registered in
- // the app manifest. The object literal is defined as below:
- //
- // {
- // "keyword1": {
- // "subAppManifestURL1": {
- // /* subscribed info */
- // },
- // "subAppManifestURL2": {
- // /* subscribed info */
- // },
- // ...
- // },
- // "keyword2": {
- // "subAppManifestURL3": {
- // /* subscribed info */
- // },
- // ...
- // },
- // ...
- // }
- //
- // For example:
- //
- // {
- // "foo": {
- // "app://subApp1.gaiamobile.org/manifest.webapp": {
- // pageURL: "app://subApp1.gaiamobile.org/handler.html",
- // description: "blah blah",
- // rules: { ... }
- // },
- // "app://subApp2.gaiamobile.org/manifest.webapp": {
- // pageURL: "app://subApp2.gaiamobile.org/handler.html",
- // description: "blah blah",
- // rules: { ... }
- // }
- // },
- // "bar": {
- // "app://subApp3.gaiamobile.org/manifest.webapp": {
- // pageURL: "app://subApp3.gaiamobile.org/handler.html",
- // description: "blah blah",
- // rules: { ... }
- // }
- // }
- // }
- //
- // TODO Bug 908999 - Update registered connections when app gets uninstalled.
- this._registeredConnections = {};
+ // This matrix is used for saving the inter-app connection info registered in
+ // the app manifest. The object literal is defined as below:
+ //
+ // {
+ // "keyword1": {
+ // "subAppManifestURL1": {
+ // /* subscribed info */
+ // },
+ // "subAppManifestURL2": {
+ // /* subscribed info */
+ // },
+ // ...
+ // },
+ // "keyword2": {
+ // "subAppManifestURL3": {
+ // /* subscribed info */
+ // },
+ // ...
+ // },
+ // ...
+ // }
+ //
+ // For example:
+ //
+ // {
+ // "foo": {
+ // "app://subApp1.gaiamobile.org/manifest.webapp": {
+ // pageURL: "app://subApp1.gaiamobile.org/handler.html",
+ // description: "blah blah",
+ // rules: { ... }
+ // },
+ // "app://subApp2.gaiamobile.org/manifest.webapp": {
+ // pageURL: "app://subApp2.gaiamobile.org/handler.html",
+ // description: "blah blah",
+ // rules: { ... }
+ // }
+ // },
+ // "bar": {
+ // "app://subApp3.gaiamobile.org/manifest.webapp": {
+ // pageURL: "app://subApp3.gaiamobile.org/handler.html",
+ // description: "blah blah",
+ // rules: { ... }
+ // }
+ // }
+ // }
+ //
+ // TODO Bug 908999 - Update registered connections when app gets uninstalled.
+ this._registeredConnections = {};
- // This matrix is used for saving the permitted connections, which allows
- // the messaging between publishers and subscribers. The object literal is
- // defined as below:
- //
- // {
- // "keyword1": {
- // "pubAppManifestURL1": [
- // "subAppManifestURL1",
- // "subAppManifestURL2",
- // ...
- // ],
- // "pubAppManifestURL2": [
- // "subAppManifestURL3",
- // "subAppManifestURL4",
- // ...
- // ],
- // ...
- // },
- // "keyword2": {
- // "pubAppManifestURL3": [
- // "subAppManifestURL5",
- // ...
- // ],
- // ...
- // },
- // ...
- // }
- //
- // For example:
- //
- // {
- // "foo": {
- // "app://pubApp1.gaiamobile.org/manifest.webapp": [
- // "app://subApp1.gaiamobile.org/manifest.webapp",
- // "app://subApp2.gaiamobile.org/manifest.webapp"
- // ],
- // "app://pubApp2.gaiamobile.org/manifest.webapp": [
- // "app://subApp3.gaiamobile.org/manifest.webapp",
- // "app://subApp4.gaiamobile.org/manifest.webapp"
- // ]
- // },
- // "bar": {
- // "app://pubApp3.gaiamobile.org/manifest.webapp": [
- // "app://subApp5.gaiamobile.org/manifest.webapp",
- // ]
- // }
- // }
- //
- // TODO Bug 908999 - Update allowed connections when app gets uninstalled.
- this._allowedConnections = {};
+ // This matrix is used for saving the permitted connections, which allows
+ // the messaging between publishers and subscribers. The object literal is
+ // defined as below:
+ //
+ // {
+ // "keyword1": {
+ // "pubAppManifestURL1": [
+ // "subAppManifestURL1",
+ // "subAppManifestURL2",
+ // ...
+ // ],
+ // "pubAppManifestURL2": [
+ // "subAppManifestURL3",
+ // "subAppManifestURL4",
+ // ...
+ // ],
+ // ...
+ // },
+ // "keyword2": {
+ // "pubAppManifestURL3": [
+ // "subAppManifestURL5",
+ // ...
+ // ],
+ // ...
+ // },
+ // ...
+ // }
+ //
+ // For example:
+ //
+ // {
+ // "foo": {
+ // "app://pubApp1.gaiamobile.org/manifest.webapp": [
+ // "app://subApp1.gaiamobile.org/manifest.webapp",
+ // "app://subApp2.gaiamobile.org/manifest.webapp"
+ // ],
+ // "app://pubApp2.gaiamobile.org/manifest.webapp": [
+ // "app://subApp3.gaiamobile.org/manifest.webapp",
+ // "app://subApp4.gaiamobile.org/manifest.webapp"
+ // ]
+ // },
+ // "bar": {
+ // "app://pubApp3.gaiamobile.org/manifest.webapp": [
+ // "app://subApp5.gaiamobile.org/manifest.webapp",
+ // ]
+ // }
+ // }
+ //
+ // TODO Bug 908999 - Update allowed connections when app gets uninstalled.
+ this._allowedConnections = {};
- // This matrix is used for saving the caller info from the content process,
- // which is indexed by a random UUID, to know where to return the promise
- // resolvser's callback when the prompt UI for allowing connections returns.
- // An example of the object literal is shown as below:
- //
- // {
- // "fooID": {
- // outerWindowID: 12,
- // requestID: 34,
- // target: pubAppTarget1
- // },
- // "barID": {
- // outerWindowID: 56,
- // requestID: 78,
- // target: pubAppTarget2
- // }
- // }
- //
- // where |outerWindowID| is the ID of the window requesting the connection,
- // |requestID| is the ID specifying the promise resolver to return,
- // |target| is the target of the process requesting the connection.
- this._promptUICallers = {};
+ // This matrix is used for saving the caller info from the content process,
+ // which is indexed by a random UUID, to know where to return the promise
+ // resolvser's callback when the prompt UI for allowing connections returns.
+ // An example of the object literal is shown as below:
+ //
+ // {
+ // "fooID": {
+ // outerWindowID: 12,
+ // requestID: 34,
+ // target: pubAppTarget1
+ // },
+ // "barID": {
+ // outerWindowID: 56,
+ // requestID: 78,
+ // target: pubAppTarget2
+ // }
+ // }
+ //
+ // where |outerWindowID| is the ID of the window requesting the connection,
+ // |requestID| is the ID specifying the promise resolver to return,
+ // |target| is the target of the process requesting the connection.
+ this._promptUICallers = {};
- // This matrix is used for saving the pair of message ports, which is indexed
- // by a random UUID, so that each port can know whom it should talk to.
- // An example of the object literal is shown as below:
- //
- // {
- // "UUID1": {
- // keyword: "keyword1",
- // publisher: {
- // manifestURL: "app://pubApp1.gaiamobile.org/manifest.webapp",
- // target: pubAppTarget1,
- // pageURL: "app://pubApp1.gaiamobile.org/caller.html",
- // messageQueue: [...]
- // },
- // subscriber: {
- // manifestURL: "app://subApp1.gaiamobile.org/manifest.webapp",
- // target: subAppTarget1,
- // pageURL: "app://pubApp1.gaiamobile.org/handler.html",
- // messageQueue: [...]
- // }
- // },
- // "UUID2": {
- // keyword: "keyword2",
- // publisher: {
- // manifestURL: "app://pubApp2.gaiamobile.org/manifest.webapp",
- // target: pubAppTarget2,
- // pageURL: "app://pubApp2.gaiamobile.org/caller.html",
- // messageQueue: [...]
- // },
- // subscriber: {
- // manifestURL: "app://subApp2.gaiamobile.org/manifest.webapp",
- // target: subAppTarget2,
- // pageURL: "app://pubApp2.gaiamobile.org/handler.html",
- // messageQueue: [...]
- // }
- // }
- // }
- this._messagePortPairs = {};
-}
+ // This matrix is used for saving the pair of message ports, which is indexed
+ // by a random UUID, so that each port can know whom it should talk to.
+ // An example of the object literal is shown as below:
+ //
+ // {
+ // "UUID1": {
+ // keyword: "keyword1",
+ // publisher: {
+ // manifestURL: "app://pubApp1.gaiamobile.org/manifest.webapp",
+ // target: pubAppTarget1,
+ // pageURL: "app://pubApp1.gaiamobile.org/caller.html",
+ // messageQueue: [...]
+ // },
+ // subscriber: {
+ // manifestURL: "app://subApp1.gaiamobile.org/manifest.webapp",
+ // target: subAppTarget1,
+ // pageURL: "app://pubApp1.gaiamobile.org/handler.html",
+ // messageQueue: [...]
+ // }
+ // },
+ // "UUID2": {
+ // keyword: "keyword2",
+ // publisher: {
+ // manifestURL: "app://pubApp2.gaiamobile.org/manifest.webapp",
+ // target: pubAppTarget2,
+ // pageURL: "app://pubApp2.gaiamobile.org/caller.html",
+ // messageQueue: [...]
+ // },
+ // subscriber: {
+ // manifestURL: "app://subApp2.gaiamobile.org/manifest.webapp",
+ // target: subAppTarget2,
+ // pageURL: "app://pubApp2.gaiamobile.org/handler.html",
+ // messageQueue: [...]
+ // }
+ // }
+ // }
+ this._messagePortPairs = {};
+ },
-InterAppCommService.prototype = {
+ /**
+ * Registration of a page that wants to be connected to other apps through
+ * the Inter-App Communication API.
+ *
+ * @param aKeyword The connection's keyword.
+ * @param aHandlerPageURI The URI of the handler's page.
+ * @param aManifestURI The webapp's manifest URI.
+ * @param aDescription The connection's description.
+ * @param aRules The connection's rules.
+ */
registerConnection: function(aKeyword, aHandlerPageURI, aManifestURI,
aDescription, aRules) {
let manifestURL = aManifestURI.spec;
let pageURL = aHandlerPageURI.spec;
if (DEBUG) {
debug("registerConnection: aKeyword: " + aKeyword +
" manifestURL: " + manifestURL + " pageURL: " + pageURL +
@@ -858,17 +878,12 @@ InterAppCommService.prototype = {
}, this);
ppmm = null;
break;
case "inter-app-comm-select-app-result":
if (DEBUG) debug("inter-app-comm-select-app-result: " + aData);
this._handleSelectcedApps(JSON.parse(aData));
break;
}
- },
-
- classID: Components.ID("{3dd15ce6-e7be-11e2-82bc-77967e7a63e6}"),
+ }
+};
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIInterAppCommService,
- Ci.nsIObserver])
-}
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([InterAppCommService]);
+InterAppCommService.init();
--- a/dom/apps/src/moz.build
+++ b/dom/apps/src/moz.build
@@ -22,16 +22,17 @@ EXTRA_COMPONENTS += [
'Webapps.js',
'Webapps.manifest',
]
EXTRA_JS_MODULES += [
'AppDownloadManager.jsm',
'AppsServiceChild.jsm',
'FreeSpaceWatcher.jsm',
+ 'InterAppCommService.jsm',
'OfflineCacheInstaller.jsm',
'PermissionsInstaller.jsm',
'PermissionsTable.jsm',
'StoreTrustAnchor.jsm',
]
EXTRA_PP_JS_MODULES += [
'AppsUtils.jsm',
new file mode 100644
--- /dev/null
+++ b/dom/apps/tests/unit/test_inter_app_comm_service.js
@@ -0,0 +1,457 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
+
+Cu.import("resource://gre/modules/InterAppCommService.jsm");
+
+let UUIDGenerator = Cc["@mozilla.org/uuid-generator;1"]
+ .getService(Ci.nsIUUIDGenerator);
+
+const MESSAGE_PORT_ID = UUIDGenerator.generateUUID().toString();
+const FAKE_MESSAGE_PORT_ID = UUIDGenerator.generateUUID().toString();
+const OUTER_WINDOW_ID = UUIDGenerator.generateUUID().toString();
+const REQUEST_ID = UUIDGenerator.generateUUID().toString();
+
+const PUB_APP_MANIFEST_URL = "app://pubApp.gaiamobile.org/manifest.webapp";
+const SUB_APP_MANIFEST_URL = "app://subApp.gaiamobile.org/manifest.webapp";
+
+const PUB_APP_PAGE_URL = "app://pubApp.gaiamobile.org/handler.html";
+const SUB_APP_PAGE_URL = "app://subApp.gaiamobile.org/handler.html";
+
+const KEYWORD = "test";
+
+function create_message_port_pair(aMessagePortId,
+ aKeyword,
+ aPubManifestURL,
+ aSubManifestURL) {
+ InterAppCommService._messagePortPairs[aMessagePortId] = {
+ keyword: aKeyword,
+ publisher: {
+ manifestURL: aPubManifestURL
+ },
+ subscriber: {
+ manifestURL: aSubManifestURL
+ }
+ };
+}
+
+function clear_message_port_pairs() {
+ InterAppCommService._messagePortPairs = {};
+}
+
+function register_message_port(aMessagePortId,
+ aManifestURL,
+ aPageURL,
+ aTargetSendAsyncMessage) {
+ let message = {
+ name: "InterAppMessagePort:Register",
+ json: {
+ messagePortID: aMessagePortId,
+ manifestURL: aManifestURL,
+ pageURL: aPageURL
+ },
+ target: {
+ sendAsyncMessage: function(aName, aData) {
+ if (aTargetSendAsyncMessage) {
+ aTargetSendAsyncMessage(aName, aData);
+ }
+ },
+ assertContainApp: function(_manifestURL) {
+ return (aManifestURL == _manifestURL);
+ }
+ }
+ };
+
+ InterAppCommService.receiveMessage(message);
+
+ return message.target;
+}
+
+function register_message_ports(aMessagePortId,
+ aPubTargetSendAsyncMessage,
+ aSubTargetSendAsyncMessage) {
+ let pubTarget = register_message_port(aMessagePortId,
+ PUB_APP_MANIFEST_URL,
+ PUB_APP_PAGE_URL,
+ aPubTargetSendAsyncMessage);
+
+ let subTarget = register_message_port(aMessagePortId,
+ SUB_APP_MANIFEST_URL,
+ SUB_APP_PAGE_URL,
+ aSubTargetSendAsyncMessage);
+
+ return { pubTarget: pubTarget, subTarget: subTarget };
+}
+
+function unregister_message_port(aMessagePortId,
+ aManifestURL) {
+ let message = {
+ name: "InterAppMessagePort:Unregister",
+ json: {
+ messagePortID: aMessagePortId,
+ manifestURL: aManifestURL
+ },
+ target: {
+ assertContainApp: function(_manifestURL) {
+ return (aManifestURL == _manifestURL);
+ }
+ }
+ };
+
+ InterAppCommService.receiveMessage(message);
+}
+
+function remove_target(aTarget) {
+ let message = {
+ name: "child-process-shutdown",
+ target: aTarget
+ };
+
+ InterAppCommService.receiveMessage(message);
+}
+
+function post_message(aMessagePortId,
+ aManifestURL,
+ aMessage) {
+ let message = {
+ name: "InterAppMessagePort:PostMessage",
+ json: {
+ messagePortID: aMessagePortId,
+ manifestURL: aManifestURL,
+ message: aMessage
+ },
+ target: {
+ assertContainApp: function(_manifestURL) {
+ return (aManifestURL == _manifestURL);
+ }
+ }
+ };
+
+ InterAppCommService.receiveMessage(message);
+}
+
+function create_allowed_connections(aKeyword,
+ aPubManifestURL,
+ aSubManifestURL) {
+ let allowedPubAppManifestURLs =
+ InterAppCommService._allowedConnections[aKeyword] = {};
+
+ allowedPubAppManifestURLs[aPubManifestURL] = [aSubManifestURL];
+}
+
+function clear_allowed_connections() {
+ InterAppCommService._allowedConnections = {};
+}
+
+function get_connections(aManifestURL,
+ aOuterWindowID,
+ aRequestID,
+ aTargetSendAsyncMessage) {
+ let message = {
+ name: "Webapps:GetConnections",
+ json: {
+ manifestURL: aManifestURL,
+ outerWindowID: aOuterWindowID,
+ requestID: aRequestID
+ },
+ target: {
+ sendAsyncMessage: function(aName, aData) {
+ if (aTargetSendAsyncMessage) {
+ aTargetSendAsyncMessage(aName, aData);
+ }
+ },
+ assertContainApp: function(_manifestURL) {
+ return (aManifestURL == _manifestURL);
+ }
+ }
+ };
+
+ InterAppCommService.receiveMessage(message);
+}
+
+function cancel_connections(aManifestURL,
+ aKeyword,
+ aPubManifestURL,
+ aSubManifestURL) {
+ let message = {
+ name: "InterAppConnection:Cancel",
+ json: {
+ manifestURL: aManifestURL,
+ keyword: aKeyword,
+ pubAppManifestURL: aPubManifestURL,
+ subAppManifestURL: aSubManifestURL
+ },
+ target: {
+ assertContainApp: function(_manifestURL) {
+ return (aManifestURL == _manifestURL);
+ }
+ }
+ };
+
+ InterAppCommService.receiveMessage(message);
+}
+
+add_test(function test_registerMessagePort() {
+ create_message_port_pair(MESSAGE_PORT_ID,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ let targets = register_message_ports(MESSAGE_PORT_ID);
+
+ let messagePortPair = InterAppCommService._messagePortPairs[MESSAGE_PORT_ID];
+
+ do_check_eq(PUB_APP_PAGE_URL, messagePortPair.publisher.pageURL);
+ do_check_eq(SUB_APP_PAGE_URL, messagePortPair.subscriber.pageURL);
+
+ do_check_true(targets.pubTarget === messagePortPair.publisher.target);
+ do_check_true(targets.subTarget === messagePortPair.subscriber.target);
+
+ clear_message_port_pairs();
+ run_next_test();
+});
+
+add_test(function test_failToRegisterMessagePort() {
+ create_message_port_pair(MESSAGE_PORT_ID,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ let targets = register_message_ports(FAKE_MESSAGE_PORT_ID);
+
+ let messagePortPair = InterAppCommService._messagePortPairs[MESSAGE_PORT_ID];
+
+ // Because it failed to register, the page URLs and targets don't exist.
+ do_check_true(messagePortPair.publisher.pageURL === undefined);
+ do_check_true(messagePortPair.subscriber.pageURL === undefined);
+
+ do_check_true(messagePortPair.publisher.target === undefined);
+ do_check_true(messagePortPair.subscriber.target === undefined);
+
+ clear_message_port_pairs();
+ run_next_test();
+});
+
+add_test(function test_unregisterMessagePort() {
+ create_message_port_pair(MESSAGE_PORT_ID,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ register_message_ports(MESSAGE_PORT_ID);
+
+ unregister_message_port(MESSAGE_PORT_ID, PUB_APP_MANIFEST_URL);
+
+ do_check_true(InterAppCommService._messagePortPairs[MESSAGE_PORT_ID]
+ === undefined);
+
+ clear_message_port_pairs();
+ run_next_test();
+});
+
+add_test(function test_failToUnregisterMessagePort() {
+ create_message_port_pair(MESSAGE_PORT_ID,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ register_message_ports(MESSAGE_PORT_ID);
+
+ unregister_message_port(FAKE_MESSAGE_PORT_ID, PUB_APP_MANIFEST_URL);
+
+ // Because it failed to unregister, the entry still exists.
+ do_check_true(InterAppCommService._messagePortPairs[MESSAGE_PORT_ID]
+ !== undefined);
+
+ clear_message_port_pairs();
+ run_next_test();
+});
+
+add_test(function test_removeTarget() {
+ create_message_port_pair(MESSAGE_PORT_ID,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ let targets = register_message_ports(MESSAGE_PORT_ID);
+
+ remove_target(targets.pubTarget);
+
+ do_check_true(InterAppCommService._messagePortPairs[MESSAGE_PORT_ID]
+ === undefined);
+
+ clear_message_port_pairs();
+ run_next_test();
+});
+
+add_test(function test_postMessage() {
+ create_message_port_pair(MESSAGE_PORT_ID,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ let countPubAppOnMessage = 0;
+ function pubAppOnMessage(aName, aData) {
+ countPubAppOnMessage++;
+
+ do_check_eq(aName, "InterAppMessagePort:OnMessage");
+ do_check_eq(aData.manifestURL, PUB_APP_MANIFEST_URL);
+ do_check_eq(aData.pageURL, PUB_APP_PAGE_URL);
+ do_check_eq(aData.messagePortID, MESSAGE_PORT_ID);
+
+ if (countPubAppOnMessage == 1) {
+ do_check_eq(aData.message.text, "sub app says world");
+
+ post_message(MESSAGE_PORT_ID,
+ PUB_APP_MANIFEST_URL,
+ { text: "pub app says hello again" });
+
+ } else if (countPubAppOnMessage == 2) {
+ do_check_eq(aData.message.text, "sub app says world again");
+
+ clear_message_port_pairs();
+ run_next_test();
+ } else {
+ do_throw("pub app receives an unexpected message")
+ }
+ };
+
+ let countSubAppOnMessage = 0;
+ function subAppOnMessage(aName, aData) {
+ countSubAppOnMessage++;
+
+ do_check_eq(aName, "InterAppMessagePort:OnMessage");
+ do_check_eq(aData.manifestURL, SUB_APP_MANIFEST_URL);
+ do_check_eq(aData.pageURL, SUB_APP_PAGE_URL);
+ do_check_eq(aData.messagePortID, MESSAGE_PORT_ID);
+
+ if (countSubAppOnMessage == 1) {
+ do_check_eq(aData.message.text, "pub app says hello");
+
+ post_message(MESSAGE_PORT_ID,
+ SUB_APP_MANIFEST_URL,
+ { text: "sub app says world" });
+
+ } else if (countSubAppOnMessage == 2) {
+ do_check_eq(aData.message.text, "pub app says hello again");
+
+ post_message(MESSAGE_PORT_ID,
+ SUB_APP_MANIFEST_URL,
+ { text: "sub app says world again" });
+ } else {
+ do_throw("sub app receives an unexpected message")
+ }
+ };
+
+ register_message_ports(MESSAGE_PORT_ID, pubAppOnMessage, subAppOnMessage);
+
+ post_message(MESSAGE_PORT_ID,
+ PUB_APP_MANIFEST_URL,
+ { text: "pub app says hello" });
+});
+
+add_test(function test_registerMessagePort_with_queued_messages() {
+ create_message_port_pair(MESSAGE_PORT_ID,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ register_message_port(MESSAGE_PORT_ID,
+ PUB_APP_MANIFEST_URL,
+ PUB_APP_PAGE_URL);
+
+ post_message(MESSAGE_PORT_ID,
+ PUB_APP_MANIFEST_URL,
+ { text: "pub app says hello" });
+
+ post_message(MESSAGE_PORT_ID,
+ PUB_APP_MANIFEST_URL,
+ { text: "pub app says hello again" });
+
+ let countSubAppOnMessage = 0;
+ function subAppOnMessage(aName, aData) {
+ countSubAppOnMessage++;
+
+ do_check_eq(aName, "InterAppMessagePort:OnMessage");
+ do_check_eq(aData.manifestURL, SUB_APP_MANIFEST_URL);
+ do_check_eq(aData.pageURL, SUB_APP_PAGE_URL);
+ do_check_eq(aData.messagePortID, MESSAGE_PORT_ID);
+
+ if (countSubAppOnMessage == 1) {
+ do_check_eq(aData.message.text, "pub app says hello");
+ } else if (countSubAppOnMessage == 2) {
+ do_check_eq(aData.message.text, "pub app says hello again");
+
+ clear_message_port_pairs();
+ run_next_test();
+ } else {
+ do_throw("sub app receives an unexpected message")
+ }
+ };
+
+ register_message_port(MESSAGE_PORT_ID,
+ SUB_APP_MANIFEST_URL,
+ SUB_APP_PAGE_URL,
+ subAppOnMessage);
+});
+
+add_test(function test_getConnections() {
+ create_allowed_connections(KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ function onGetConnections(aName, aData) {
+ do_check_eq(aName, "Webapps:GetConnections:Return:OK");
+ do_check_eq(aData.oid, OUTER_WINDOW_ID);
+ do_check_eq(aData.requestID, REQUEST_ID);
+
+ let connections = aData.connections;
+ do_check_eq(connections.length, 1);
+ do_check_eq(connections[0].keyword, KEYWORD);
+ do_check_eq(connections[0].pubAppManifestURL, PUB_APP_MANIFEST_URL);
+ do_check_eq(connections[0].subAppManifestURL, SUB_APP_MANIFEST_URL);
+
+ clear_allowed_connections();
+ run_next_test();
+ };
+
+ get_connections(PUB_APP_MANIFEST_URL,
+ OUTER_WINDOW_ID,
+ REQUEST_ID,
+ onGetConnections);
+});
+
+add_test(function test_cancelConnection() {
+ create_allowed_connections(KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ create_message_port_pair(MESSAGE_PORT_ID,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ register_message_ports(MESSAGE_PORT_ID);
+
+ cancel_connections(PUB_APP_MANIFEST_URL,
+ KEYWORD,
+ PUB_APP_MANIFEST_URL,
+ SUB_APP_MANIFEST_URL);
+
+ do_check_true(InterAppCommService._allowedConnections[KEYWORD]
+ === undefined);
+
+ do_check_true(InterAppCommService._messagePortPairs[MESSAGE_PORT_ID]
+ === undefined);
+
+ clear_allowed_connections();
+ clear_message_port_pairs();
+ run_next_test();
+});
+
+function run_test() {
+ do_get_profile();
+
+ run_next_test();
+}
--- a/dom/apps/tests/unit/xpcshell.ini
+++ b/dom/apps/tests/unit/xpcshell.ini
@@ -1,5 +1,6 @@
[DEFAULT]
head =
tail =
+[test_inter_app_comm_service.js]
[test_manifestSanitizer.js]
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -1624,68 +1624,58 @@ int64_t GetPluginLastModifiedTime(const
localfile->GetLastModifiedTime(&fileModTime);
#endif
return fileModTime;
}
bool
GetPluginIsFromExtension(const nsCOMPtr<nsIFile>& pluginFile,
- const nsCOMPtr<nsISimpleEnumerator>& extensionDirs)
+ const nsCOMArray<nsIFile>& extensionDirs)
{
- if (!extensionDirs) {
- return false;
- }
-
- bool hasMore;
- while (NS_SUCCEEDED(extensionDirs->HasMoreElements(&hasMore)) && hasMore) {
- nsCOMPtr<nsISupports> supports;
- nsresult rv = extensionDirs->GetNext(getter_AddRefs(supports));
- if (NS_FAILED(rv)) {
- continue;
- }
-
- nsCOMPtr<nsIFile> extDir(do_QueryInterface(supports, &rv));
- if (NS_FAILED(rv)) {
- continue;
- }
-
- nsCOMPtr<nsIFile> dir;
- if (NS_FAILED(extDir->Clone(getter_AddRefs(dir)))) {
- continue;
- }
-
+ for (uint32_t i = 0; i < extensionDirs.Length(); ++i) {
bool contains;
- if (NS_FAILED(dir->Contains(pluginFile, true, &contains)) || !contains) {
+ if (NS_FAILED(extensionDirs[i]->Contains(pluginFile, true, &contains)) || !contains) {
continue;
}
return true;
}
return false;
}
-nsCOMPtr<nsISimpleEnumerator>
-GetExtensionDirectories()
+void
+GetExtensionDirectories(nsCOMArray<nsIFile>& dirs)
{
nsCOMPtr<nsIProperties> dirService = do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
if (!dirService) {
- return nullptr;
+ return;
}
nsCOMPtr<nsISimpleEnumerator> list;
nsresult rv = dirService->Get(XRE_EXTENSIONS_DIR_LIST,
NS_GET_IID(nsISimpleEnumerator),
getter_AddRefs(list));
if (NS_FAILED(rv)) {
- return nullptr;
+ return;
}
- return list;
+ bool more;
+ while (NS_SUCCEEDED(list->HasMoreElements(&more)) && more) {
+ nsCOMPtr<nsISupports> next;
+ if (NS_FAILED(list->GetNext(getter_AddRefs(next)))) {
+ break;
+ }
+ nsCOMPtr<nsIFile> file = do_QueryInterface(next);
+ if (file) {
+ file->Normalize();
+ dirs.AppendElement(file);
+ }
+ }
}
struct CompareFilesByTime
{
bool
LessThan(const nsCOMPtr<nsIFile>& a, const nsCOMPtr<nsIFile>& b) const
{
return GetPluginLastModifiedTime(a) < GetPluginLastModifiedTime(b);
@@ -1741,20 +1731,18 @@ nsresult nsPluginHost::ScanPluginsDirect
if (nsPluginsDir::IsPluginFile(dirEntry)) {
pluginFiles.AppendElement(dirEntry);
}
}
pluginFiles.Sort(CompareFilesByTime());
- nsCOMPtr<nsISimpleEnumerator> extensionDirs = GetExtensionDirectories();
- if (!extensionDirs) {
- PLUGIN_LOG(PLUGIN_LOG_ALWAYS, ("Could not get extension directories."));
- }
+ nsCOMArray<nsIFile> extensionDirs;
+ GetExtensionDirectories(extensionDirs);
bool warnOutdated = false;
for (int32_t i = (pluginFiles.Length() - 1); i >= 0; i--) {
nsCOMPtr<nsIFile>& localfile = pluginFiles[i];
nsString utf16FilePath;
rv = localfile->GetPath(utf16FilePath);
--- a/dom/plugins/test/testaddon/Makefile.in
+++ b/dom/plugins/test/testaddon/Makefile.in
@@ -1,23 +1,23 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
include $(topsrcdir)/config/rules.mk
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
-plugin_file_name = Test.plugin
+plugin_file_names = Test.plugin SecondTest.plugin
addon_file_name = testaddon_$(TARGET_XPCOM_ABI).xpi
else
-plugin_file_name = $(DLL_PREFIX)nptest$(DLL_SUFFIX)
+plugin_file_names = $(DLL_PREFIX)nptest$(DLL_SUFFIX) $(DLL_PREFIX)npsecondtest$(DLL_SUFFIX)
addon_file_name = testaddon.xpi
endif
# This is so hacky. Waiting on bug 988938.
testdir = $(abspath $(DEPTH)/_tests/xpcshell/dom/plugins/test/unit/)
addonpath = $(testdir)/$(addon_file_name)
libs::
$(NSINSTALL) -D $(testdir)
rm -f $(addonpath)
cd $(srcdir) && zip -rD $(addonpath) install.rdf
- cd $(DIST) && zip -rD $(addonpath) plugins/$(plugin_file_name)
+ cd $(DIST) && zip -rD $(addonpath) $(foreach name,$(plugin_file_names),plugins/$(name))
--- a/dom/plugins/test/unit/head_plugins.js
+++ b/dom/plugins/test/unit/head_plugins.js
@@ -9,37 +9,23 @@ Cu.import("resource://gre/modules/Promis
const gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
const gIsOSX = ("nsILocalFileMac" in Ci);
const gIsLinux = ("@mozilla.org/gnome-gconf-service;1" in Cc) ||
("@mozilla.org/gio-service;1" in Cc);
const gDirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
// Finds the test plugin library
-function get_test_plugin() {
+function get_test_plugin(secondplugin=false) {
var pluginEnum = gDirSvc.get("APluginsDL", Ci.nsISimpleEnumerator);
while (pluginEnum.hasMoreElements()) {
let dir = pluginEnum.getNext().QueryInterface(Ci.nsILocalFile);
+ let name = get_platform_specific_plugin_name(secondplugin);
let plugin = dir.clone();
- // OSX plugin
- plugin.append("Test.plugin");
- if (plugin.exists()) {
- plugin.normalize();
- return plugin;
- }
- plugin = dir.clone();
- // *nix plugin
- plugin.append("libnptest.so");
- if (plugin.exists()) {
- plugin.normalize();
- return plugin;
- }
- // Windows plugin
- plugin = dir.clone();
- plugin.append("nptest.dll");
+ plugin.append(name);
if (plugin.exists()) {
plugin.normalize();
return plugin;
}
}
return null;
}
@@ -88,21 +74,27 @@ function do_get_profile_startup() {
throw Components.results.NS_ERROR_NO_INTERFACE;
}
};
dirSvc.QueryInterface(Components.interfaces.nsIDirectoryService)
.registerProvider(provider);
return file.clone();
}
-function get_platform_specific_plugin_name() {
- if (gIsWindows) return "nptest.dll";
- else if (gIsOSX) return "Test.plugin";
- else if (gIsLinux) return "libnptest.so";
- else return null;
+function get_platform_specific_plugin_name(secondplugin=false) {
+ if (secondplugin) {
+ if (gIsWindows) return "npsecondtest.dll";
+ if (gIsOSX) return "SecondTest.plugin";
+ if (gIsLinux) return "libnpsecondtest.so";
+ } else {
+ if (gIsWindows) return "nptest.dll";
+ if (gIsOSX) return "Test.plugin";
+ if (gIsLinux) return "libnptest.so";
+ }
+ return null;
}
function get_platform_specific_plugin_suffix() {
if (gIsWindows) return ".dll";
else if (gIsOSX) return ".plugin";
else if (gIsLinux) return ".so";
else return null;
}
--- a/dom/plugins/test/unit/test_plugin_default_state_xpi.js
+++ b/dom/plugins/test/unit/test_plugin_default_state_xpi.js
@@ -36,16 +36,21 @@ function run_test() {
run_next_test();
}
add_task(function* test_state() {
// Remove test so we will have only one "Test Plug-in" registered.
// xpcshell tests have plugins in per-test profiles, so that's fine.
let file = get_test_plugin();
file.remove(true);
+ file = get_test_plugin(true);
+ file.remove(true);
+
+ Services.prefs.setIntPref("plugin.default.state", Ci.nsIPluginTag.STATE_CLICKTOPLAY);
+ Services.prefs.setIntPref("plugin.defaultXpi.state", Ci.nsIPluginTag.STATE_ENABLED);
let success = yield installAddon(getTestaddonFilename());
Assert.ok(success, "Should have installed addon.");
let addonDir = getAddonRoot(gProfileDir, ADDON_ID);
let provider = {
classID: Components.ID("{0af6b2d7-a06c-49b7-babc-636d292b0dbb}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
@@ -100,9 +105,13 @@ add_task(function* test_state() {
Assert.ok(!addon.userDisabled, "Addon should not be user disabled");
let testPlugin = get_test_plugintag();
Assert.notEqual(testPlugin, null, "Test plugin should have been found");
Assert.equal(testPlugin.enabledState, Ci.nsIPluginTag.STATE_ENABLED, "Test plugin from addon should have state enabled");
pluginDir.append(testPlugin.filename);
Assert.ok(pluginDir.exists(), "Plugin file should exist in addon directory: " + pluginDir.path);
+
+ testPlugin = get_test_plugintag("Second Test Plug-in");
+ Assert.notEqual(testPlugin, null, "Second test plugin should have been found");
+ Assert.equal(testPlugin.enabledState, Ci.nsIPluginTag.STATE_ENABLED, "Second test plugin from addon should have state enabled");
});
--- a/layout/tools/reftest/b2g_desktop.py
+++ b/layout/tools/reftest/b2g_desktop.py
@@ -59,17 +59,18 @@ class B2GDesktopReftest(RefTest):
if mozinfo.info['debug']:
options.timeout = 420
else:
options.timeout = 300
self.timeout = options.timeout + 30.0
log.info("%s | Running tests: start.", os.path.basename(__file__))
cmd, args = self.build_command_line(options.app,
- ignore_window_size=options.ignoreWindowSize)
+ ignore_window_size=options.ignoreWindowSize,
+ browser_arg=options.browser_arg)
self.runner = FirefoxRunner(profile=self.profile,
binary=cmd,
cmdargs=args,
env=env,
process_class=ProcessHandler,
symbols_path=options.symbolsPath,
kp_kwargs=kp_kwargs)
@@ -118,20 +119,24 @@ class B2GDesktopReftest(RefTest):
# Set a future policy version to avoid the telemetry prompt.
prefs["toolkit.telemetry.prompted"] = 999
prefs["toolkit.telemetry.notifiedOptOut"] = 999
# Set the extra prefs.
profile.set_preferences(prefs)
return profile
- def build_command_line(self, app, ignore_window_size=False):
+ def build_command_line(self, app, ignore_window_size=False,
+ browser_arg=None):
cmd = os.path.abspath(app)
args = ['-marionette']
+ if browser_arg:
+ args += [browser_arg]
+
if not ignore_window_size:
args.extend(['--screen', '800x1000'])
return cmd, args
def _on_output(self, line):
print(line)
# TODO use structured logging
if "TEST-START" in line and "|" in line:
--- a/layout/tools/reftest/runreftestb2g.py
+++ b/layout/tools/reftest/runreftestb2g.py
@@ -26,16 +26,21 @@ class B2GOptions(ReftestOptions):
def __init__(self, automation=None, **kwargs):
defaults = {}
if not automation:
automation = B2GRemoteAutomation(None, "fennec", context_chrome=True)
ReftestOptions.__init__(self, automation)
+ self.add_option("--browser-arg", action="store",
+ type = "string", dest = "browser_arg",
+ help = "Optional command-line arg to pass to the browser")
+ defaults["browser_arg"] = None
+
self.add_option("--b2gpath", action="store",
type = "string", dest = "b2gPath",
help = "path to B2G repo or qemu dir")
defaults["b2gPath"] = None
self.add_option("--marionette", action="store",
type = "string", dest = "marionette",
help = "host:port to use when connecting to Marionette")
--- a/mobile/android/base/BrowserApp.java
+++ b/mobile/android/base/BrowserApp.java
@@ -1915,17 +1915,17 @@ abstract public class BrowserApp extends
}
/**
* Add the provided item to the provided menu, which should be
* the root (mMenu).
*/
private void addAddonMenuItemToMenu(final Menu menu, final MenuItemInfo info) {
info.added = true;
-
+
final Menu destination;
if (info.parent == 0) {
destination = menu;
} else if (info.parent == GECKO_TOOLS_MENU) {
MenuItem tools = menu.findItem(R.id.tools);
destination = tools != null ? tools.getSubMenu() : menu;
} else {
MenuItem parent = menu.findItem(info.parent);
@@ -2051,17 +2051,17 @@ abstract public class BrowserApp extends
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Sets mMenu = menu.
super.onCreateOptionsMenu(menu);
- // Inform the menu about the action-items bar.
+ // Inform the menu about the action-items bar.
if (menu instanceof GeckoMenu &&
HardwareUtils.isTablet()) {
((GeckoMenu) menu).setActionItemBarPresenter(mBrowserToolbar);
}
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.browser_app_menu, mMenu);
@@ -2465,17 +2465,17 @@ abstract public class BrowserApp extends
}
}
return super.onKeyLongPress(keyCode, event);
}
/*
* If the app has been launched a certain number of times, and we haven't asked for feedback before,
* open a new tab with about:feedback when launching the app from the icon shortcut.
- */
+ */
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
String action = intent.getAction();
if (AppConstants.MOZ_ANDROID_BEAM && Build.VERSION.SDK_INT >= 10 && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
String uri = intent.getDataString();
@@ -2567,17 +2567,17 @@ abstract public class BrowserApp extends
}
}).execute();
}
// HomePager.OnNewTabsListener
@Override
public void onNewTabs(String[] urls) {
final EnumSet<OnUrlOpenListener.Flags> flags = EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB);
-
+
for (String url : urls) {
if (!maybeSwitchToTab(url, flags)) {
openUrlAndStopEditing(url, true);
}
}
}
// HomePager.OnUrlOpenListener
--- a/mobile/android/base/gfx/TouchEventHandler.java
+++ b/mobile/android/base/gfx/TouchEventHandler.java
@@ -249,16 +249,18 @@ final class TouchEventHandler implements
MotionEvent event = mEventQueue.poll();
while (true) {
// event being null here is valid and represents a block of events
// that has already been dispatched.
if (event != null) {
dispatchEvent(event, allowDefaultAction);
+ event.recycle();
+ event = null;
}
if (mEventQueue.isEmpty()) {
// we have processed the backlog of events, and are all caught up.
// now we can set clear the hold flag and set the dispatch flag so
// that the handleEvent() function can do the right thing for all
// remaining events in this block (which is still ongoing) without
// having to put them in the queue.
mHoldInQueue = false;
--- a/mobile/android/base/home/PanelItemView.java
+++ b/mobile/android/base/home/PanelItemView.java
@@ -73,16 +73,19 @@ class PanelItemView extends LinearLayout
.into(image);
}
}
private static class ArticleItemView extends PanelItemView {
private ArticleItemView(Context context) {
super(context, R.layout.panel_article_item);
setOrientation(LinearLayout.HORIZONTAL);
+
+ final int padding = getResources().getDimensionPixelSize(R.dimen.article_item_view_padding);
+ setPadding(0, padding, 0, padding);
}
}
private static class ImageItemView extends PanelItemView {
private ImageItemView(Context context) {
super(context, R.layout.panel_image_item);
setOrientation(LinearLayout.VERTICAL);
}
--- a/mobile/android/base/home/TabMenuStrip.java
+++ b/mobile/android/base/home/TabMenuStrip.java
@@ -11,191 +11,90 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
+import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.TextView;
-public class TabMenuStrip extends LinearLayout
- implements HomePager.Decor,
- View.OnFocusChangeListener {
- private static final String LOGTAG = "GeckoTabMenuStrip";
+/**
+ * {@code TabMenuStrip} is the view used to display {@code HomePager} tabs
+ * on tablets. See {@code TabMenuStripLayout} for details about how the
+ * tabs are created and updated.
+ */
+public class TabMenuStrip extends HorizontalScrollView
+ implements HomePager.Decor {
- private HomePager.OnTitleClickListener mOnTitleClickListener;
- private Drawable mStrip;
- private View mSelectedView;
+ // Offset between the selected tab title and the edge of the screen,
+ // except for the first and last tab in the tab strip.
+ private static final int TITLE_OFFSET_DIPS = 24;
- // Data associated with the scrolling of the strip drawable.
- private View toTab;
- private View fromTab;
- private float progress;
-
- // This variable is used to predict the direction of scroll.
- private float mPrevProgress;
+ private final int titleOffset;
+ private final TabMenuStripLayout layout;
public TabMenuStrip(Context context, AttributeSet attrs) {
super(context, attrs);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabMenuStrip);
- final int stripResId = a.getResourceId(R.styleable.TabMenuStrip_strip, -1);
- a.recycle();
+ // Disable the scroll bar.
+ setHorizontalScrollBarEnabled(false);
- if (stripResId != -1) {
- mStrip = getResources().getDrawable(stripResId);
- }
+ titleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
- setWillNotDraw(false);
+ layout = new TabMenuStripLayout(context, attrs);
+ addView(layout, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
}
@Override
public void onAddPagerView(String title) {
- final TextView button = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.tab_menu_strip, this, false);
- button.setText(title.toUpperCase());
-
- addView(button);
- button.setOnClickListener(new ViewClickListener(getChildCount() - 1));
- button.setOnFocusChangeListener(this);
+ layout.onAddPagerView(title);
}
@Override
public void removeAllPagerViews() {
- removeAllViews();
+ layout.removeAllViews();
}
@Override
public void onPageSelected(final int position) {
- mSelectedView = getChildAt(position);
-
- // Callback to measure and draw the strip after the view is visible.
- ViewTreeObserver vto = mSelectedView.getViewTreeObserver();
- if (vto.isAlive()) {
- vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- mSelectedView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
-
- if (mStrip != null) {
- mStrip.setBounds(mSelectedView.getLeft(),
- mSelectedView.getTop(),
- mSelectedView.getRight(),
- mSelectedView.getBottom());
- }
-
- mPrevProgress = position;
- }
- });
- }
+ layout.onPageSelected(position);
}
- // Page scroll animates the drawable and its bounds from the previous to next child view.
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
- if (mStrip == null) {
- return;
- }
+ layout.onPageScrolled(position, positionOffset, positionOffsetPixels);
- setScrollingData(position, positionOffset);
-
- if (fromTab == null || toTab == null) {
+ final View selectedTitle = layout.getChildAt(position);
+ if (selectedTitle == null) {
return;
}
- final int fromTabLeft = fromTab.getLeft();
- final int fromTabRight = fromTab.getRight();
-
- final int toTabLeft = toTab.getLeft();
- final int toTabRight = toTab.getRight();
-
- mStrip.setBounds((int) (fromTabLeft + ((toTabLeft - fromTabLeft) * progress)),
- 0,
- (int) (fromTabRight + ((toTabRight - fromTabRight) * progress)),
- getHeight());
- invalidate();
- }
+ final int selectedTitleOffset = (int) (positionOffset * selectedTitle.getWidth());
- /*
- * position + positionOffset goes from 0 to 2 as we scroll from page 1 to 3.
- * Normalized progress is relative to the the direction the page is being scrolled towards.
- * For this, we maintain direction of scroll with a state, and the child view we are moving towards and away from.
- */
- private void setScrollingData(int position, float positionOffset) {
- if (position >= getChildCount() - 1) {
- return;
- }
-
- final float currProgress = position + positionOffset;
-
- if (mPrevProgress > currProgress) {
- toTab = getChildAt(position);
- fromTab = getChildAt(position + 1);
- progress = 1 - positionOffset;
- } else {
- toTab = getChildAt(position + 1);
- fromTab = getChildAt(position);
- progress = positionOffset;
+ int titleLeft = selectedTitle.getLeft() + selectedTitleOffset;
+ if (position > 0) {
+ titleLeft -= titleOffset;
}
- mPrevProgress = currProgress;
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
-
- if (mStrip != null) {
- mStrip.draw(canvas);
- }
- }
-
- @Override
- public void onFocusChange(View v, boolean hasFocus) {
- if (v == this && hasFocus && getChildCount() > 0) {
- mSelectedView.requestFocus();
- return;
+ int titleRight = selectedTitle.getRight() + selectedTitleOffset;
+ if (position < layout.getChildCount() - 1) {
+ titleRight += titleOffset;
}
- if (!hasFocus) {
- return;
- }
-
- int i = 0;
- final int numTabs = getChildCount();
-
- while (i < numTabs) {
- View view = getChildAt(i);
- if (view == v) {
- view.requestFocus();
- if (isShown()) {
- // A view is focused so send an event to announce the menu strip state.
- sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
- }
- break;
- }
-
- i++;
+ final int scrollX = getScrollX();
+ if (titleLeft < scrollX) {
+ // Tab strip overflows to the left.
+ scrollTo(titleLeft, 0);
+ } else if (titleRight > scrollX + getWidth()) {
+ // Tab strip overflows to the right.
+ scrollTo(titleRight - getWidth(), 0);
}
}
@Override
public void setOnTitleClickListener(HomePager.OnTitleClickListener onTitleClickListener) {
- mOnTitleClickListener = onTitleClickListener;
- }
-
- private class ViewClickListener implements OnClickListener {
- private final int mIndex;
-
- public ViewClickListener(int index) {
- mIndex = index;
- }
-
- @Override
- public void onClick(View view) {
- if (mOnTitleClickListener != null) {
- mOnTitleClickListener.onTitleClicked(mIndex);
- }
- }
+ layout.setOnTitleClickListener(onTitleClickListener);
}
}
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/home/TabMenuStripLayout.java
@@ -0,0 +1,194 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
+ * 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.home;
+
+import org.mozilla.gecko.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityEvent;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * {@code TabMenuStripLayout} is the view that draws the {@code HomePager}
+ * tabs that are displayed in {@code TabMenuStrip}.
+ */
+class TabMenuStripLayout extends LinearLayout
+ implements View.OnFocusChangeListener {
+
+ private HomePager.OnTitleClickListener onTitleClickListener;
+ private Drawable strip;
+ private View selectedView;
+
+ // Data associated with the scrolling of the strip drawable.
+ private View toTab;
+ private View fromTab;
+ private float progress;
+
+ // This variable is used to predict the direction of scroll.
+ private float prevProgress;
+
+ TabMenuStripLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TabMenuStrip);
+ final int stripResId = a.getResourceId(R.styleable.TabMenuStrip_strip, -1);
+ a.recycle();
+
+ if (stripResId != -1) {
+ strip = getResources().getDrawable(stripResId);
+ }
+
+ setWillNotDraw(false);
+ }
+
+ void onAddPagerView(String title) {
+ final TextView button = (TextView) LayoutInflater.from(getContext()).inflate(R.layout.tab_menu_strip, this, false);
+ button.setText(title.toUpperCase());
+
+ addView(button);
+ button.setOnClickListener(new ViewClickListener(getChildCount() - 1));
+ button.setOnFocusChangeListener(this);
+ }
+
+ void onPageSelected(final int position) {
+ selectedView = getChildAt(position);
+
+ // Callback to measure and draw the strip after the view is visible.
+ ViewTreeObserver vto = selectedView.getViewTreeObserver();
+ if (vto.isAlive()) {
+ vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ selectedView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
+
+ if (strip != null) {
+ strip.setBounds(selectedView.getLeft(),
+ selectedView.getTop(),
+ selectedView.getRight(),
+ selectedView.getBottom());
+ }
+
+ prevProgress = position;
+ }
+ });
+ }
+ }
+
+ // Page scroll animates the drawable and its bounds from the previous to next child view.
+ void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+ if (strip == null) {
+ return;
+ }
+
+ setScrollingData(position, positionOffset);
+
+ if (fromTab == null || toTab == null) {
+ return;
+ }
+
+ final int fromTabLeft = fromTab.getLeft();
+ final int fromTabRight = fromTab.getRight();
+
+ final int toTabLeft = toTab.getLeft();
+ final int toTabRight = toTab.getRight();
+
+ strip.setBounds((int) (fromTabLeft + ((toTabLeft - fromTabLeft) * progress)),
+ 0,
+ (int) (fromTabRight + ((toTabRight - fromTabRight) * progress)),
+ getHeight());
+ invalidate();
+ }
+
+ /*
+ * position + positionOffset goes from 0 to 2 as we scroll from page 1 to 3.
+ * Normalized progress is relative to the the direction the page is being scrolled towards.
+ * For this, we maintain direction of scroll with a state, and the child view we are moving towards and away from.
+ */
+ void setScrollingData(int position, float positionOffset) {
+ if (position >= getChildCount() - 1) {
+ return;
+ }
+
+ final float currProgress = position + positionOffset;
+
+ if (prevProgress > currProgress) {
+ toTab = getChildAt(position);
+ fromTab = getChildAt(position + 1);
+ progress = 1 - positionOffset;
+ } else {
+ toTab = getChildAt(position + 1);
+ fromTab = getChildAt(position);
+ progress = positionOffset;
+ }
+
+ prevProgress = currProgress;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (strip != null) {
+ strip.draw(canvas);
+ }
+ }
+
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (v == this && hasFocus && getChildCount() > 0) {
+ selectedView.requestFocus();
+ return;
+ }
+
+ if (!hasFocus) {
+ return;
+ }
+
+ int i = 0;
+ final int numTabs = getChildCount();
+
+ while (i < numTabs) {
+ View view = getChildAt(i);
+ if (view == v) {
+ view.requestFocus();
+ if (isShown()) {
+ // A view is focused so send an event to announce the menu strip state.
+ sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ }
+ break;
+ }
+
+ i++;
+ }
+ }
+
+ void setOnTitleClickListener(HomePager.OnTitleClickListener onTitleClickListener) {
+ this.onTitleClickListener = onTitleClickListener;
+ }
+
+ private class ViewClickListener implements OnClickListener {
+ private final int mIndex;
+
+ public ViewClickListener(int index) {
+ mIndex = index;
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (onTitleClickListener != null) {
+ onTitleClickListener.onTitleClicked(mIndex);
+ }
+ }
+ }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -274,16 +274,17 @@ gbjar.sources += [
'home/ReadingListPanel.java',
'home/ReadingListRow.java',
'home/SearchEngine.java',
'home/SearchEngineRow.java',
'home/SearchLoader.java',
'home/SimpleCursorLoader.java',
'home/SuggestClient.java',
'home/TabMenuStrip.java',
+ 'home/TabMenuStripLayout.java',
'home/TopSitesGridItemView.java',
'home/TopSitesGridView.java',
'home/TopSitesPanel.java',
'home/TopSitesThumbnailView.java',
'home/TwoLinePageRow.java',
'InputMethods.java',
'JavaAddonManager.java',
'LightweightTheme.java',
--- a/mobile/android/base/resources/layout/panel_article_item.xml
+++ b/mobile/android/base/resources/layout/panel_article_item.xml
@@ -3,29 +3,24 @@
- 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/. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView android:id="@+id/image"
android:layout_width="54dp"
android:layout_height="44dp"
- android:layout_marginTop="10dip"
- android:layout_marginBottom="10dip"
android:layout_marginLeft="10dip"
android:scaleType="centerCrop"/>
<LinearLayout android:id="@+id/title_desc_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:paddingTop="15dip"
- android:paddingBottom="15dip"
android:paddingLeft="10dip"
android:paddingRight="10dip"
- android:minHeight="@dimen/page_row_height"
android:gravity="center_vertical"
android:orientation="vertical">
<TextView android:id="@+id/title"
style="@style/Widget.PanelItemView.Title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
--- a/mobile/android/base/resources/values/dimens.xml
+++ b/mobile/android/base/resources/values/dimens.xml
@@ -102,9 +102,12 @@
<dimen name="home_banner_height">72dp</dimen>
<!-- Icon Grid -->
<dimen name="icongrid_columnwidth">128dp</dimen>
<dimen name="icongrid_padding">16dp</dimen>
<!-- PanelGridView dimensions -->
<dimen name="panel_grid_view_column_width">150dp</dimen>
+
+ <!-- ArticleItemView dimensions -->
+ <dimen name="article_item_view_padding">15dp</dimen>
</resources>
--- a/mobile/android/base/tests/BaseTest.java
+++ b/mobile/android/base/tests/BaseTest.java
@@ -433,19 +433,18 @@ abstract class BaseTest extends BaseRobo
public void selectMenuItemByPath(String[] listItems) {
int listLength = listItems.length;
if (listLength > 0) {
selectMenuItem(listItems[0]);
}
if (listLength > 1) {
for (int i = 1; i < listLength; i++) {
String itemName = "^" + listItems[i] + "$";
- if (!waitForPreferencesText(itemName)) {
- mSolo.scrollDown();
- }
+ mAsserter.ok(waitForPreferencesText(itemName), "Waiting for and scrolling once to find item " + itemName, itemName + " found");
+ mAsserter.ok(waitForEnabledText(itemName), "Waiting for enabled text " + itemName, itemName + " option is present and enabled");
mSolo.clickOnText(itemName);
}
}
}
public final void selectMenuItem(String menuItemName) {
// build the item name ready to be used
String itemName = "^" + menuItemName + "$";
--- a/mobile/android/base/tests/MotionEventHelper.java
+++ b/mobile/android/base/tests/MotionEventHelper.java
@@ -21,39 +21,54 @@ class MotionEventHelper {
mSurfaceOffsetY = surfaceOffsetY;
Log.i(LOGTAG, "Initialized using offset (" + mSurfaceOffsetX + "," + mSurfaceOffsetY + ")");
}
public long down(float x, float y) {
Log.d(LOGTAG, "Triggering down at (" + x + "," + y + ")");
long downTime = SystemClock.uptimeMillis();
MotionEvent event = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_DOWN, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0);
- mInstrumentation.sendPointerSync(event);
+ try {
+ mInstrumentation.sendPointerSync(event);
+ } finally {
+ event.recycle();
+ event = null;
+ }
return downTime;
}
public long move(long downTime, float x, float y) {
return move(downTime, SystemClock.uptimeMillis(), x, y);
}
public long move(long downTime, long moveTime, float x, float y) {
Log.d(LOGTAG, "Triggering move to (" + x + "," + y + ")");
MotionEvent event = MotionEvent.obtain(downTime, moveTime, MotionEvent.ACTION_MOVE, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0);
- mInstrumentation.sendPointerSync(event);
+ try {
+ mInstrumentation.sendPointerSync(event);
+ } finally {
+ event.recycle();
+ event = null;
+ }
return downTime;
}
public long up(long downTime, float x, float y) {
return up(downTime, SystemClock.uptimeMillis(), x, y);
}
public long up(long downTime, long upTime, float x, float y) {
Log.d(LOGTAG, "Triggering up at (" + x + "," + y + ")");
MotionEvent event = MotionEvent.obtain(downTime, upTime, MotionEvent.ACTION_UP, mSurfaceOffsetX + x, mSurfaceOffsetY + y, 0);
- mInstrumentation.sendPointerSync(event);
+ try {
+ mInstrumentation.sendPointerSync(event);
+ } finally {
+ event.recycle();
+ event = null;
+ }
return -1L;
}
public Thread dragAsync(final float startX, final float startY, final float endX, final float endY, final long durationMillis) {
Thread t = new Thread() {
@Override
public void run() {
int numEvents = (int)(durationMillis * DRAG_EVENTS_PER_SECOND / 1000);
--- a/mobile/android/base/tests/MotionEventReplayer.java
+++ b/mobile/android/base/tests/MotionEventReplayer.java
@@ -198,18 +198,23 @@ class MotionEventReplayer {
long.class, long.class, int.class, int.class, pointerIds.getClass(),
pointerData.getClass(), int.class, float.class, float.class,
int.class, int.class);
}
event = (MotionEvent)mObtainNanoMethod.invoke(null, downTime, eventTime,
eventTime * 1000000, action, pointerCount, pointerIds, (float[])pointerData,
metaState, xPrecision, yPrecision, deviceId, edgeFlags);
}
- Log.v(LOGTAG, "Injecting " + event.toString());
- mInstrumentation.sendPointerSync(event);
+ try {
+ Log.v(LOGTAG, "Injecting " + event.toString());
+ mInstrumentation.sendPointerSync(event);
+ } finally {
+ event.recycle();
+ event = null;
+ }
eventProperties.clear();
}
} finally {
br.close();
}
}
}
--- a/mobile/android/base/toolbar/BrowserToolbar.java
+++ b/mobile/android/base/toolbar/BrowserToolbar.java
@@ -45,16 +45,17 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
@@ -185,17 +186,20 @@ public class BrowserToolbar extends Them
final Resources res = getResources();
urlBarViewOffset = res.getDimensionPixelSize(R.dimen.url_bar_offset_left);
defaultForwardMargin = res.getDimensionPixelSize(R.dimen.forward_default_offset);
urlDisplayLayout = (ToolbarDisplayLayout) findViewById(R.id.display_layout);
urlBarEntry = findViewById(R.id.url_bar_entry);
urlEditLayout = (ToolbarEditLayout) findViewById(R.id.edit_layout);
urlBarEntryDefaultLayoutParams = (RelativeLayout.LayoutParams) urlBarEntry.getLayoutParams();
- urlBarEntryShrunkenLayoutParams = new RelativeLayout.LayoutParams(urlBarEntryDefaultLayoutParams);
+ // API level 19 adds a RelativeLayout.LayoutParams copy constructor, so we explicitly cast
+ // to ViewGroup.MarginLayoutParams to ensure consistency across platforms.
+ urlBarEntryShrunkenLayoutParams = new RelativeLayout.LayoutParams(
+ (ViewGroup.MarginLayoutParams) urlBarEntryDefaultLayoutParams);
urlBarEntryShrunkenLayoutParams.addRule(RelativeLayout.ALIGN_RIGHT, R.id.edit_layout);
urlBarEntryShrunkenLayoutParams.rightMargin = 0;
// This will clip the translating edge's image at 60% of its width
urlBarTranslatingEdge = (ImageView) findViewById(R.id.url_bar_translating_edge);
if (urlBarTranslatingEdge != null) {
urlBarTranslatingEdge.getDrawable().setLevel(6000);
}
@@ -392,17 +396,17 @@ public class BrowserToolbar extends Them
}
public void refresh() {
urlDisplayLayout.dismissSiteIdentityPopup();
}
public boolean onBackPressed() {
if (isEditing()) {
- stopEditing();
+ cancelEdit();
return true;
}
return urlDisplayLayout.dismissSiteIdentityPopup();
}
public boolean onKey(int keyCode, KeyEvent event) {
if (event.getAction() != KeyEvent.ACTION_DOWN) {
--- a/testing/config/mozharness/b2g_desktop_config.py
+++ b/testing/config/mozharness/b2g_desktop_config.py
@@ -3,17 +3,18 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
config = {
"mochitest_options": [
"--console-level=INFO", "%(test_manifest)s",
"--total-chunks=%(total_chunks)s", "--this-chunk=%(this_chunk)s",
"--profile=%(gaia_profile)s", "--app=%(application)s", "--desktop",
"--utility-path=%(utility_path)s", "--certificate-path=%(cert_path)s",
- "--symbols-path=%(symbols_path)s",
+ "--symbols-path=%(symbols_path)s", "--browser-arg=%(browser_arg)s",
"--quiet"
],
"reftest_options": [
"--desktop", "--profile=%(gaia_profile)s", "--appname=%(application)s",
- "--symbols-path=%(symbols_path)s", "%(test_manifest)s",
+ "--browser-arg=%(browser_arg)s", "--symbols-path=%(symbols_path)s",
+ "%(test_manifest)s"
]
}