author | Ryan VanderMeulen <ryanvm@gmail.com> |
Thu, 30 Oct 2014 16:19:07 -0400 | |
changeset 213239 | bc78d64a2a148dd236cadec6e9d6ad1d1c8cd81a |
parent 213238 | acd029ee3d13abf6106c559b8c8909139891e9cf (current diff) |
parent 213208 | e0b505a37b1c0bdeb1fd9523a49eb36b58d2133d (diff) |
child 213240 | af652f97938d6dd3807d8a7009f3010b798e0cc8 |
push id | 27745 |
push user | cbook@mozilla.com |
push date | Fri, 31 Oct 2014 13:09:12 +0000 |
treeherder | mozilla-central@6bd2071b373f [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 36.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
dom/tv/test/file_app.sjs | file | annotate | diff | comparison | revisions | |
dom/tv/test/file_app.template.webapp | file | annotate | diff | comparison | revisions | |
dom/tv/test/file_tv_non_permitted_app.html | file | annotate | diff | comparison | revisions | |
dom/tv/test/mochitest.ini | file | annotate | diff | comparison | revisions | |
dom/tv/test/mochitest/file_app.sjs | file | annotate | diff | comparison | revisions | |
dom/tv/test/mochitest/file_app.template.webapp | file | annotate | diff | comparison | revisions | |
dom/tv/test/mochitest/file_tv_non_permitted_app.html | file | annotate | diff | comparison | revisions | |
dom/tv/test/mochitest/mochitest.ini | file | annotate | diff | comparison | revisions | |
dom/tv/test/mochitest/test_tv_non_permitted_app.html | file | annotate | diff | comparison | revisions | |
dom/tv/test/moz.build | file | annotate | diff | comparison | revisions | |
dom/tv/test/test_tv_non_permitted_app.html | file | annotate | diff | comparison | revisions |
--- a/b2g/app/b2g.js +++ b/b2g/app/b2g.js @@ -977,18 +977,23 @@ pref("osfile.reset_worker_delay", 5000); // APZC preferences. // // Gaia relies heavily on scroll events for now, so lets fire them // more often than the default value (100). pref("apz.asyncscroll.throttle", 40); pref("apz.pan_repaint_interval", 16); // APZ physics settings, tuned by UX designers +pref("apz.fling_curve_function_x1", "0.0"); +pref("apz.fling_curve_function_y1", "0.0"); +pref("apz.fling_curve_function_x2", "0.58"); +pref("apz.fling_curve_function_y2", "1.0"); +pref("apz.fling_curve_threshold_inches_per_ms", "0.03"); +pref("apz.fling_friction", "0.003"); pref("apz.max_velocity_inches_per_ms", "0.07"); -pref("apz.fling_friction", "0.003"); // Tweak default displayport values to reduce the risk of running out of // memory when zooming in pref("apz.x_skate_size_multiplier", "1.25"); pref("apz.y_skate_size_multiplier", "1.5"); pref("apz.x_stationary_size_multiplier", "1.5"); pref("apz.y_stationary_size_multiplier", "1.8"); pref("apz.enlarge_displayport_when_clipped", true);
--- a/b2g/config/dolphin/sources.xml +++ b/b2g/config/dolphin/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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <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="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
--- 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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea"> <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="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/> <!-- 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="8986df0f82e15ac2798df0b6c2ee3435400677ac"> <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="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/> <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/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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <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="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/>
--- 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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea"> <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="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/> <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/> <!-- Stock Android things --> <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
--- a/b2g/config/flame-kk/sources.xml +++ b/b2g/config/flame-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="3a2947df41a480de1457a6dcdbf46ad0af70d8e0"> <copyfile dest="Makefile" src="core/root.mk"/> </project> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <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="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/> @@ -121,16 +121,18 @@ <project name="platform/system/netd" path="system/netd" revision="a6531f7befb49b1c81bc0de7e51c5482b308e1c5"/> <project name="platform/system/security" path="system/security" revision="ee8068b9e7bfb2770635062fc9c2035be2142bd8"/> <project name="platform/system/vold" path="system/vold" revision="42fa2a0f14f965970a4b629a176bbd2666edf017"/> <project name="platform/external/icu4c" path="external/icu4c" revision="d3ec7428eb276db43b7ed0544e09344a6014806c"/> <remove-project name="platform/frameworks/base"/> <remove-project name="platform/frameworks/native"/> <remove-project name="platform/hardware/libhardware"/> <remove-project name="platform/external/bluetooth/bluedroid"/> + <remove-project name="platform/system/media"/> + <project name="platform/system/media" path="system/media" revision="c1332c21c608f4932a6d7e83450411cde53315ef"/> <!--original fetch url was git://github.com/t2m-foxfone/--> <remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/> <default remote="caf" revision="LNX.LA.3.5.2.1.1" sync-j="4"/> <!-- Flame specific things --> <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="1bb28abbc215f45220620af5cd60a8ac1be93722"/> <project name="device/qcom/common" path="device/qcom/common" revision="54c32c2ddef066fbdf611d29e4b7c47e0363599e"/> <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="48835395daa6a49b281db62c50805bd6ca24077e"/> <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="3c4f041e3e3dc676f2111caf20a186ec0467dbdb"/>
--- a/b2g/config/flame/sources.xml +++ b/b2g/config/flame/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="8986df0f82e15ac2798df0b6c2ee3435400677ac"> <copyfile dest="Makefile" src="core/root.mk"/> </project> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/> - <project name="gaia" path="gaia" remote="mozillaorg" revision="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/> <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": "4763231f664a8a94cbea98b35b84749b51a961c9", + "revision": "5b7182e0e489747ff07ca952f5a99dc21a0226c9", "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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea"> <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="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/> <!-- 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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea"> <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="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="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/nexus-4/sources.xml +++ b/b2g/config/nexus-4/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="8986df0f82e15ac2798df0b6c2ee3435400677ac"> <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="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/> <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="70eb0cb0977d6295e7da8896f9efb9f3ca1c13ea"> <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="cddf7f505c4c280bacb74c22af3fa4959ccb555a"/> + <project name="gaia.git" path="gaia" remote="mozillaorg" revision="8ae6598f3ab7b0c34ac42a73083ddb74266affba"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="45c54a55e31758f7e54e5eafe0d01d387f35897a"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="28be739bcdcbc9eb91c0bdbff1f7d3eab717969b"/> <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/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -309,19 +309,19 @@ skip-if = os == "mac" || e10s # bug 9670 [browser_ctrlTab.js] skip-if = e10s # Bug ????? - thumbnail captures need e10s love (tabPreviews_capture fails with Argument 1 of CanvasRenderingContext2D.drawWindow does not implement interface Window.) [browser_customize_popupNotification.js] skip-if = e10s [browser_datareporting_notification.js] run-if = datareporting [browser_devedition.js] [browser_devices_get_user_media.js] -skip-if = buildapp == 'mulet' || os == "linux" || e10s # linux: bug 976544 & bug 1060315; e10s: Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent? +skip-if = buildapp == 'mulet' || (os == "linux" && debug) || e10s # linux: bug 976544; e10s: bug 1071623 [browser_devices_get_user_media_about_urls.js] -skip-if = e10s # Bug 973001 - appears user media notifications only happen in the child and don't make their way to the parent? +skip-if = e10s # Bug 1071623 [browser_discovery.js] skip-if = e10s # Bug 918663 - DOMLinkAdded events don't make their way to chrome [browser_double_close_tab.js] skip-if = e10s [browser_duplicateIDs.js] [browser_drag.js] skip-if = true # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638. [browser_favicon_change.js]
--- a/browser/base/content/test/general/browser_devices_get_user_media.js +++ b/browser/base/content/test/general/browser_devices_get_user_media.js @@ -173,59 +173,59 @@ function getMediaCaptureState() { return "CameraAndMicrophone"; if (hasVideo.value) return "Camera"; if (hasAudio.value) return "Microphone"; return "none"; } -function closeStream(aAlreadyClosed) { +function* closeStream(aAlreadyClosed) { expectNoObserverCalled(); info("closing the stream"); content.wrappedJSObject.closeStream(); if (!aAlreadyClosed) yield promiseObserverCalled("recording-device-events"); yield promiseNoPopupNotification("webRTC-sharingDevices"); if (!aAlreadyClosed) expectObserverCalled("recording-window-ended"); - assertWebRTCIndicatorStatus(null); + yield* assertWebRTCIndicatorStatus(null); } function checkDeviceSelectors(aAudio, aVideo) { let micSelector = document.getElementById("webRTC-selectMicrophone"); if (aAudio) ok(!micSelector.hidden, "microphone selector visible"); else ok(micSelector.hidden, "microphone selector hidden"); let cameraSelector = document.getElementById("webRTC-selectCamera"); if (aVideo) ok(!cameraSelector.hidden, "camera selector visible"); else ok(cameraSelector.hidden, "camera selector hidden"); } -function checkSharingUI(aExpected) { +function* checkSharingUI(aExpected) { yield promisePopupNotification("webRTC-sharingDevices"); - assertWebRTCIndicatorStatus(aExpected); + yield* assertWebRTCIndicatorStatus(aExpected); } -function checkNotSharing() { +function* checkNotSharing() { is(getMediaCaptureState(), "none", "expected nothing to be shared"); ok(!PopupNotifications.getNotification("webRTC-sharingDevices"), "no webRTC-sharingDevices popup notification"); - assertWebRTCIndicatorStatus(null); + yield* assertWebRTCIndicatorStatus(null); } const permissionError = "error: PermissionDeniedError: The user did not grant permission for the operation."; let gTests = [ { desc: "getUserMedia audio+video", @@ -388,17 +388,17 @@ let gTests = [ }); // reset the menuitems to have no impact on the following tests. enableDevice("Camera", true); enableDevice("Microphone", true); expectObserverCalled("getUserMedia:response:deny"); expectObserverCalled("recording-window-ended"); - checkNotSharing(); + yield checkNotSharing(); } }, { desc: "getUserMedia audio+video, user clicks \"Don't Share\"", run: function checkDontShare() { yield promisePopupNotificationShown("webRTC-shareDevices", () => { info("requesting devices"); @@ -408,17 +408,17 @@ let gTests = [ checkDeviceSelectors(true, true); yield promiseMessage(permissionError, () => { activateSecondaryAction(kActionDeny); }); expectObserverCalled("getUserMedia:response:deny"); expectObserverCalled("recording-window-ended"); - checkNotSharing(); + yield checkNotSharing(); } }, { desc: "getUserMedia audio+video: stop sharing", run: function checkStopSharing() { yield promisePopupNotificationShown("webRTC-shareDevices", () => { info("requesting devices"); @@ -447,17 +447,17 @@ let gTests = [ expectObserverCalled("recording-window-ended"); if (gObservedTopics["recording-device-events"] == 1) { todo(false, "Got the 'recording-device-events' notification twice, likely because of bug 962719"); gObservedTopics["recording-device-events"] = 0; } expectNoObserverCalled(); - checkNotSharing(); + yield checkNotSharing(); // the stream is already closed, but this will do some cleanup anyway yield closeStream(true); } }, { desc: "getUserMedia prompt: Always/Never Share",
--- a/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js +++ b/browser/base/content/test/general/browser_devices_get_user_media_about_urls.js @@ -105,30 +105,30 @@ function getMediaCaptureState() { return "CameraAndMicrophone"; if (hasVideo.value) return "Camera"; if (hasAudio.value) return "Microphone"; return "none"; } -function closeStream(aAlreadyClosed) { +function* closeStream(aAlreadyClosed) { expectNoObserverCalled(); info("closing the stream"); content.wrappedJSObject.closeStream(); if (!aAlreadyClosed) yield promiseObserverCalled("recording-device-events"); yield promiseNoPopupNotification("webRTC-sharingDevices"); if (!aAlreadyClosed) expectObserverCalled("recording-window-ended"); - assertWebRTCIndicatorStatus(null); + yield* assertWebRTCIndicatorStatus(null); } function loadPage(aUrl) { let deferred = Promise.defer(); gTab.linkedBrowser.addEventListener("load", function onload() { gTab.linkedBrowser.removeEventListener("load", onload, true);
--- a/browser/base/content/test/general/head.js +++ b/browser/base/content/test/general/head.js @@ -662,17 +662,32 @@ function assertWebRTCIndicatorStatus(exp is(menu && !menu.hidden, !!expected, "WebRTC menu should be " + expectedState); } if (!("nsISystemStatusBar" in Ci)) { let indicator = Services.wm.getEnumerator("Browser:WebRTCGlobalIndicator"); let hasWindow = indicator.hasMoreElements(); is(hasWindow, !!expected, "popup " + msg); if (hasWindow) { - let docElt = indicator.getNext().document.documentElement; + let document = indicator.getNext().document; + let docElt = document.documentElement; + + if (document.readyState != "complete") { + info("Waiting for the sharing indicator's document to load"); + let deferred = Promise.defer(); + document.addEventListener("readystatechange", + function onReadyStateChange() { + if (document.readyState != "complete") + return; + document.removeEventListener("readystatechange", onReadyStateChange); + deferred.resolve(); + }); + yield deferred.promise; + } + for (let item of ["video", "audio", "screen"]) { let expectedValue = (expected && expected[item]) ? "true" : ""; is(docElt.getAttribute("sharing" + item), expectedValue, item + " global indicator attribute as expected"); } ok(!indicator.hasMoreElements(), "only one global indicator window"); }
--- a/browser/components/customizableui/test/browser.ini +++ b/browser/components/customizableui/test/browser.ini @@ -64,29 +64,29 @@ skip-if = os == "linux" [browser_941083_invalidate_wrapper_cache_createWidget.js] [browser_942581_unregisterArea_keeps_placements.js] [browser_943683_migration_test.js] [browser_944887_destroyWidget_should_destroy_in_palette.js] [browser_945739_showInPrivateBrowsing_customize_mode.js] [browser_947914_button_addons.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_copy.js] -skip-if = os == "linux" # Intermittent failures +skip-if = os == "linux" || e10s # Intermittent failures on Linux, e10s issues are bug 1091561 [browser_947914_button_cut.js] -skip-if = os == "linux" # Intermittent failures +skip-if = os == "linux" || e10s # Intermittent failures on Linux, e10s issues are bug 1091561 [browser_947914_button_find.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_history.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_newPrivateWindow.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_newWindow.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_paste.js] -skip-if = os == "linux" # Intermittent failures +skip-if = os == "linux" || e10s # Intermittent failures on Linux, e10s issues are bug 1091561 [browser_947914_button_print.js] skip-if = os == "linux" || (os == "win" && e10s) # Intermittent failures on Linux, e10s issues on Windows (bug 1088714) [browser_947914_button_savePage.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_zoomIn.js] skip-if = os == "linux" # Intermittent failures [browser_947914_button_zoomOut.js] skip-if = os == "linux" # Intermittent failures
--- a/browser/devtools/canvasdebugger/test/browser.ini +++ b/browser/devtools/canvasdebugger/test/browser.ini @@ -14,17 +14,16 @@ support-files = [browser_canvas-actor-test-03.js] [browser_canvas-actor-test-04.js] [browser_canvas-actor-test-05.js] [browser_canvas-actor-test-06.js] [browser_canvas-actor-test-07.js] [browser_canvas-actor-test-08.js] [browser_canvas-actor-test-09.js] [browser_canvas-actor-test-10.js] -skip-if = e10s # Bug 1058879 - canvas debugger tests disabled with e10s [browser_canvas-frontend-call-highlight.js] [browser_canvas-frontend-call-list.js] [browser_canvas-frontend-call-search.js] [browser_canvas-frontend-call-stack-01.js] [browser_canvas-frontend-call-stack-02.js] [browser_canvas-frontend-call-stack-03.js] [browser_canvas-frontend-clear.js] [browser_canvas-frontend-img-screenshots.js]
--- a/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-10.js +++ b/browser/devtools/canvasdebugger/test/browser_canvas-actor-test-10.js @@ -3,18 +3,17 @@ /** * Tests that the correct framebuffer, renderbuffer and textures are re-bound * after generating screenshots using the actor. */ function ifTestingSupported() { let { target, front } = yield initCanvasDebuggerBackend(WEBGL_BINDINGS_URL); - // XXX - use of |debuggee| here is incompatible with e10s - bug 1058879. - let debuggee = target.window.wrappedJSObject + loadFrameScripts(); let navigated = once(target, "navigate"); yield front.setup({ reload: true }); ok(true, "The front was setup up successfully."); yield navigated; ok(true, "Target automatically navigated when the front was set up."); @@ -32,30 +31,36 @@ function ifTestingSupported() { "The first screenshot has the correct width."); is(firstScreenshot.height, CanvasFront.WEBGL_SCREENSHOT_MAX_HEIGHT, "The first screenshot has the correct height."); is(firstScreenshot.flipped, true, "The first screenshot has the correct 'flipped' flag."); is(firstScreenshot.pixels.length, 0, "The first screenshot should be empty."); - let gl = debuggee.gl; - is(gl.getParameter(gl.FRAMEBUFFER_BINDING), debuggee.customFramebuffer, + is((yield evalInDebuggee("gl.getParameter(gl.FRAMEBUFFER_BINDING) === customFramebuffer")), + true, "The debuggee's gl context framebuffer wasn't changed."); - is(gl.getParameter(gl.RENDERBUFFER_BINDING), debuggee.customRenderbuffer, + is((yield evalInDebuggee("gl.getParameter(gl.RENDERBUFFER_BINDING) === customRenderbuffer")), + true, "The debuggee's gl context renderbuffer wasn't changed."); - is(gl.getParameter(gl.TEXTURE_BINDING_2D), debuggee.customTexture, + is((yield evalInDebuggee("gl.getParameter(gl.TEXTURE_BINDING_2D) === customTexture")), + true, "The debuggee's gl context texture binding wasn't changed."); - is(gl.getParameter(gl.VIEWPORT)[0], 128, + is((yield evalInDebuggee("gl.getParameter(gl.VIEWPORT)[0]")), + 128, "The debuggee's gl context viewport's left coord. wasn't changed."); - is(gl.getParameter(gl.VIEWPORT)[1], 256, + is((yield evalInDebuggee("gl.getParameter(gl.VIEWPORT)[1]")), + 256, "The debuggee's gl context viewport's left coord. wasn't changed."); - is(gl.getParameter(gl.VIEWPORT)[2], 384, + is((yield evalInDebuggee("gl.getParameter(gl.VIEWPORT)[2]")), + 384, "The debuggee's gl context viewport's left coord. wasn't changed."); - is(gl.getParameter(gl.VIEWPORT)[3], 512, + is((yield evalInDebuggee("gl.getParameter(gl.VIEWPORT)[3]")), + 512, "The debuggee's gl context viewport's left coord. wasn't changed."); let secondScreenshot = yield snapshotActor.generateScreenshotFor(functionCalls[1]); is(secondScreenshot.index, 1, "The second screenshot has the correct index."); is(secondScreenshot.width, CanvasFront.WEBGL_SCREENSHOT_MAX_HEIGHT, "The second screenshot has the correct width."); is(secondScreenshot.height, CanvasFront.WEBGL_SCREENSHOT_MAX_HEIGHT, @@ -70,27 +75,33 @@ function ifTestingSupported() { "The second screenshot has the correct red component."); is(new Uint8Array(secondScreenshot.pixels.buffer)[1], 0, "The second screenshot has the correct green component."); is(new Uint8Array(secondScreenshot.pixels.buffer)[2], 255, "The second screenshot has the correct blue component."); is(new Uint8Array(secondScreenshot.pixels.buffer)[3], 255, "The second screenshot has the correct alpha component."); - gl = debuggee.gl; - is(gl.getParameter(gl.FRAMEBUFFER_BINDING), debuggee.customFramebuffer, + is((yield evalInDebuggee("gl.getParameter(gl.FRAMEBUFFER_BINDING) === customFramebuffer")), + true, "The debuggee's gl context framebuffer still wasn't changed."); - is(gl.getParameter(gl.RENDERBUFFER_BINDING), debuggee.customRenderbuffer, + is((yield evalInDebuggee("gl.getParameter(gl.RENDERBUFFER_BINDING) === customRenderbuffer")), + true, "The debuggee's gl context renderbuffer still wasn't changed."); - is(gl.getParameter(gl.TEXTURE_BINDING_2D), debuggee.customTexture, + is((yield evalInDebuggee("gl.getParameter(gl.TEXTURE_BINDING_2D) === customTexture")), + true, "The debuggee's gl context texture binding still wasn't changed."); - is(gl.getParameter(gl.VIEWPORT)[0], 128, + is((yield evalInDebuggee("gl.getParameter(gl.VIEWPORT)[0]")), + 128, "The debuggee's gl context viewport's left coord. still wasn't changed."); - is(gl.getParameter(gl.VIEWPORT)[1], 256, + is((yield evalInDebuggee("gl.getParameter(gl.VIEWPORT)[1]")), + 256, "The debuggee's gl context viewport's left coord. still wasn't changed."); - is(gl.getParameter(gl.VIEWPORT)[2], 384, + is((yield evalInDebuggee("gl.getParameter(gl.VIEWPORT)[2]")), + 384, "The debuggee's gl context viewport's left coord. still wasn't changed."); - is(gl.getParameter(gl.VIEWPORT)[3], 512, + is((yield evalInDebuggee("gl.getParameter(gl.VIEWPORT)[3]")), + 512, "The debuggee's gl context viewport's left coord. still wasn't changed."); yield removeTab(target.tab); finish(); }
--- a/browser/devtools/canvasdebugger/test/head.js +++ b/browser/devtools/canvasdebugger/test/head.js @@ -6,29 +6,31 @@ const { classes: Cc, interfaces: Ci, uti let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); // Disable logging for all the tests. Both the debugger server and frontend will // be affected by this pref. let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log"); Services.prefs.setBoolPref("devtools.debugger.log", false); +let { generateUUID } = Cc['@mozilla.org/uuid-generator;1'].getService(Ci.nsIUUIDGenerator); let { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {}); let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {}); - let { CallWatcherFront } = devtools.require("devtools/server/actors/call-watcher"); let { CanvasFront } = devtools.require("devtools/server/actors/canvas"); let TiltGL = devtools.require("devtools/tilt/tilt-gl"); let TargetFactory = devtools.TargetFactory; let Toolbox = devtools.Toolbox; +let mm = null +const FRAME_SCRIPT_UTILS_URL = "chrome://browser/content/devtools/frame-script-utils.js"; const EXAMPLE_URL = "http://example.com/browser/browser/devtools/canvasdebugger/test/"; const SIMPLE_CANVAS_URL = EXAMPLE_URL + "doc_simple-canvas.html"; const SIMPLE_BITMASKS_URL = EXAMPLE_URL + "doc_simple-canvas-bitmasks.html"; const SIMPLE_CANVAS_TRANSPARENT_URL = EXAMPLE_URL + "doc_simple-canvas-transparent.html"; const SIMPLE_CANVAS_DEEP_STACK_URL = EXAMPLE_URL + "doc_simple-canvas-deep-stack.html"; const WEBGL_ENUM_URL = EXAMPLE_URL + "doc_webgl-enum.html"; const WEBGL_BINDINGS_URL = EXAMPLE_URL + "doc_webgl-bindings.html"; @@ -43,16 +45,25 @@ registerCleanupFunction(() => { Services.prefs.setBoolPref("devtools.canvasdebugger.enabled", gToolEnabled); // Some of yhese tests use a lot of memory due to GL contexts, so force a GC // to help fragmentation. info("Forcing GC after canvas debugger test."); Cu.forceGC(); }); +/** + * Call manually in tests that use frame script utils after initializing + * the shader editor. Call after init but before navigating to different pages. + */ +function loadFrameScripts () { + mm = gBrowser.selectedBrowser.messageManager; + mm.loadFrameScript(FRAME_SCRIPT_UTILS_URL, false); +} + function addTab(aUrl, aWindow) { info("Adding tab: " + aUrl); let deferred = promise.defer(); let targetWindow = aWindow || window; let targetBrowser = targetWindow.gBrowser; targetWindow.focus(); @@ -227,8 +238,35 @@ function initCanvasDebuggerFrontend(aUrl function teardown(aPanel) { info("Destroying the specified canvas debugger."); return promise.all([ once(aPanel, "destroyed"), removeTab(aPanel.target.tab) ]); } + +/** + * Takes a string `script` and evaluates it directly in the content + * in potentially a different process. + */ +function evalInDebuggee (script) { + let deferred = promise.defer(); + + if (!mm) { + throw new Error("`loadFrameScripts()` must be called when using MessageManager."); + } + + let id = generateUUID().toString(); + mm.sendAsyncMessage("devtools:test:eval", { script: script, id: id }); + mm.addMessageListener("devtools:test:eval:response", handler); + + function handler ({ data }) { + if (id !== data.id) { + return; + } + + mm.removeMessageListener("devtools:test:eval:response", handler); + deferred.resolve(data.value); + } + + return deferred.promise; +}
--- a/browser/devtools/commandline/test/browser_cmd_settings.js +++ b/browser/devtools/commandline/test/browser_cmd_settings.js @@ -20,59 +20,59 @@ function spawnTest() { // Setup let options = yield helpers.openTab(TEST_URI); require("devtools/commandline/commands-index"); let gcli = require("gcli/index"); yield gcli.load(); let settings = gcli.settings; - let tiltEnabled = settings.get("devtools.tilt.enabled"); + let hideIntroEnabled = settings.get("devtools.gcli.hideIntro"); let tabSize = settings.get("devtools.editor.tabsize"); let remoteHost = settings.get("devtools.debugger.remote-host"); - let tiltEnabledOrig = prefBranch.getBoolPref("devtools.tilt.enabled"); + let hideIntroOrig = prefBranch.getBoolPref("devtools.gcli.hideIntro"); let tabSizeOrig = prefBranch.getIntPref("devtools.editor.tabsize"); let remoteHostOrig = prefBranch.getComplexValue( "devtools.debugger.remote-host", Components.interfaces.nsISupportsString).data; - info("originally: devtools.tilt.enabled = " + tiltEnabledOrig); + info("originally: devtools.gcli.hideIntro = " + hideIntroOrig); info("originally: devtools.editor.tabsize = " + tabSizeOrig); info("originally: devtools.debugger.remote-host = " + remoteHostOrig); // Actual tests - is(tiltEnabled.value, tiltEnabledOrig, "tiltEnabled default"); + is(hideIntroEnabled.value, hideIntroOrig, "hideIntroEnabled default"); is(tabSize.value, tabSizeOrig, "tabSize default"); is(remoteHost.value, remoteHostOrig, "remoteHost default"); - tiltEnabled.setDefault(); + hideIntroEnabled.setDefault(); tabSize.setDefault(); remoteHost.setDefault(); - let tiltEnabledDefault = tiltEnabled.value; + let hideIntroEnabledDefault = hideIntroEnabled.value; let tabSizeDefault = tabSize.value; let remoteHostDefault = remoteHost.value; - tiltEnabled.value = false; + hideIntroEnabled.value = false; tabSize.value = 42; - remoteHost.value = "example.com" + remoteHost.value = "example.com"; - is(tiltEnabled.value, false, "tiltEnabled basic"); + is(hideIntroEnabled.value, false, "hideIntroEnabled basic"); is(tabSize.value, 42, "tabSize basic"); is(remoteHost.value, "example.com", "remoteHost basic"); - function tiltEnabledCheck(ev) { - is(ev.setting, tiltEnabled, "tiltEnabled event setting"); - is(ev.value, true, "tiltEnabled event value"); - is(ev.setting.value, true, "tiltEnabled event setting value"); + function hideIntroEnabledCheck(ev) { + is(ev.setting, hideIntroEnabled, "hideIntroEnabled event setting"); + is(ev.value, true, "hideIntroEnabled event value"); + is(ev.setting.value, true, "hideIntroEnabled event setting value"); } - tiltEnabled.onChange.add(tiltEnabledCheck); - tiltEnabled.value = true; - is(tiltEnabled.value, true, "tiltEnabled change"); + hideIntroEnabled.onChange.add(hideIntroEnabledCheck); + hideIntroEnabled.value = true; + is(hideIntroEnabled.value, true, "hideIntroEnabled change"); function tabSizeCheck(ev) { is(ev.setting, tabSize, "tabSize event setting"); is(ev.value, 1, "tabSize event value"); is(ev.setting.value, 1, "tabSize event setting value"); } tabSize.onChange.add(tabSizeCheck); tabSize.value = 1; @@ -82,39 +82,39 @@ function spawnTest() { is(ev.setting, remoteHost, "remoteHost event setting"); is(ev.value, "y.com", "remoteHost event value"); is(ev.setting.value, "y.com", "remoteHost event setting value"); } remoteHost.onChange.add(remoteHostCheck); remoteHost.value = "y.com"; is(remoteHost.value, "y.com", "remoteHost change"); - tiltEnabled.onChange.remove(tiltEnabledCheck); + hideIntroEnabled.onChange.remove(hideIntroEnabledCheck); tabSize.onChange.remove(tabSizeCheck); remoteHost.onChange.remove(remoteHostCheck); function remoteHostReCheck(ev) { is(ev.setting, remoteHost, "remoteHost event reset"); is(ev.value, null, "remoteHost event revalue"); is(ev.setting.value, null, "remoteHost event setting revalue"); } remoteHost.onChange.add(remoteHostReCheck); - tiltEnabled.setDefault(); + hideIntroEnabled.setDefault(); tabSize.setDefault(); remoteHost.setDefault(); remoteHost.onChange.remove(remoteHostReCheck); - is(tiltEnabled.value, tiltEnabledDefault, "tiltEnabled reset"); + is(hideIntroEnabled.value, hideIntroEnabledDefault, "hideIntroEnabled reset"); is(tabSize.value, tabSizeDefault, "tabSize reset"); is(remoteHost.value, remoteHostDefault, "remoteHost reset"); // Cleanup - prefBranch.setBoolPref("devtools.tilt.enabled", tiltEnabledOrig); + prefBranch.setBoolPref("devtools.gcli.hideIntro", hideIntroOrig); prefBranch.setIntPref("devtools.editor.tabsize", tabSizeOrig); supportsString.data = remoteHostOrig; prefBranch.setComplexValue("devtools.debugger.remote-host", Components.interfaces.nsISupportsString, supportsString); yield helpers.closeTab(options); }
--- a/browser/devtools/framework/target.js +++ b/browser/devtools/framework/target.js @@ -340,16 +340,20 @@ TabTarget.prototype = { get isAddon() { return !!(this._form && this._form.addonActor); }, get isLocalTab() { return !!this._tab; }, + get isMultiProcess() { + return !this.window; + }, + get isThreadPaused() { return !!this._isThreadPaused; }, /** * Adds remote protocol capabilities to the target, so that it can be used * for tools that support the Remote Debugging Protocol even for local * connections.
--- a/browser/devtools/framework/test/browser_toolbox_options_disable_buttons.js +++ b/browser/devtools/framework/test/browser_toolbox_options_disable_buttons.js @@ -69,37 +69,42 @@ function testPreferenceAndUIStateIsConsi let check = checkNodes.filter(node=>node.id === tool.id)[0]; is (check.checked, isVisible, "Checkbox should be selected based on current pref for " + tool.id); } } function testToggleToolboxButtons() { let checkNodes = [...panelWin.document.querySelectorAll("#enabled-toolbox-buttons-box > checkbox")]; let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")]; - let visibleButtons = toolboxButtonNodes.filter(button=>!button.hasAttribute("hidden")); let toggleableTools = toolbox.toolboxButtons; + // Tilt is disabled in E10S mode so we skip the tilt button if E10S is + // enabled. + if (toolbox.target.isMultiProcess) { + toolboxButtonNodes = [...doc.querySelectorAll(".command-button:not(#command-button-tilt)")]; + } + is (checkNodes.length, toggleableTools.length, "All of the buttons are toggleable." ); is (checkNodes.length, toolboxButtonNodes.length, "All of the DOM buttons are toggleable." ); for (let tool of toggleableTools) { let id = tool.id; let matchedCheckboxes = checkNodes.filter(node=>node.id === id); let matchedButtons = toolboxButtonNodes.filter(button=>button.id === id); ok (matchedCheckboxes.length === 1, "There should be a single toggle checkbox for: " + id); ok (matchedButtons.length === 1, "There should be a DOM button for: " + id); is (matchedButtons[0], tool.button, "DOM buttons should match for: " + id); is (matchedCheckboxes[0].getAttribute("label"), tool.label, - "The label for checkbox matches the tool definition.") + "The label for checkbox matches the tool definition."); is (matchedButtons[0].getAttribute("tooltiptext"), tool.label, - "The tooltip for button matches the tool definition.") + "The tooltip for button matches the tool definition."); } // Store modified pref names so that they can be cleared on error. for (let tool of toggleableTools) { let pref = tool.visibilityswitch; modifiedPrefs.push(pref); }
--- a/browser/devtools/framework/toolbox-options.js +++ b/browser/devtools/framework/toolbox-options.js @@ -177,16 +177,20 @@ OptionsPanel.prototype = { checkbox.setAttribute("id", tool.id); checkbox.setAttribute("label", tool.label); checkbox.setAttribute("checked", InfallibleGetBoolPref(tool.visibilityswitch)); checkbox.addEventListener("command", onCheckboxClick.bind(this, checkbox)); return checkbox; }; for (let tool of toggleableButtons) { + if (this.toolbox.target.isMultiProcess && tool.id === "command-button-tilt") { + continue; + } + enabledToolbarButtonsBox.appendChild(createCommandCheckbox(tool)); } }, setupToolsList: function() { let defaultToolsBox = this.panelDoc.getElementById("default-tools-box"); let additionalToolsBox = this.panelDoc.getElementById("additional-tools-box"); let toolsNotSupportedLabel = this.panelDoc.getElementById("tools-not-supported-label");
--- a/browser/devtools/framework/toolbox.js +++ b/browser/devtools/framework/toolbox.js @@ -686,24 +686,31 @@ Toolbox.prototype = { */ get toolboxButtons() { return ToolboxButtons.map(options => { let button = this.doc.getElementById(options.id); // Some buttons may not exist inside of Browser Toolbox if (!button) { return false; } + + // Disable tilt in E10S mode. Removing it from the list of toolbox buttons + // allows a bunch of tests to pass without modification. + if (this.target.isMultiProcess && options.id === "command-button-tilt") { + return false; + } + return { id: options.id, button: button, label: button.getAttribute("tooltiptext"), visibilityswitch: "devtools." + options.id + ".enabled", isTargetSupported: options.isTargetSupported ? options.isTargetSupported : target => target.isLocalTab - } + }; }).filter(button=>button); }, /** * Ensure the visibility of each toolbox button matches the * preference value. Simply hide buttons that are preffed off. */ setToolboxButtonsVisibility: function() { @@ -719,16 +726,28 @@ Toolbox.prototype = { if (button) { if (on) { button.removeAttribute("hidden"); } else { button.setAttribute("hidden", "true"); } } }); + + // Tilt is handled separately because it is disabled in E10S mode. Because + // we have removed tilt from toolboxButtons we have to deal with it here. + let tiltEnabled = !this.target.isMultiProcess && + Services.prefs.getBoolPref("devtools.command-button-tilt.enabled"); + let tiltButton = this.doc.getElementById("command-button-tilt"); + + if (tiltEnabled) { + tiltButton.removeAttribute("hidden"); + } else { + tiltButton.setAttribute("hidden", "true"); + } }, /** * Build a tab for one tool definition and add to the toolbox * * @param {string} toolDefinition * Tool definition of the tool to build a tab for. */
--- a/browser/devtools/shared/frame-script-utils.js +++ b/browser/devtools/shared/frame-script-utils.js @@ -17,11 +17,20 @@ addMessageListener("devtools:test:reload content.location.reload(data.forceget); }); addMessageListener("devtools:test:console", function ({ data }) { let method = data.shift(); content.console[method].apply(content.console, data); }); +// To eval in content, look at `evalInDebuggee` in the head.js of canvasdebugger +// for an example. +addMessageListener("devtools:test:eval", function ({ data }) { + sendAsyncMessage("devtools:test:eval:response", { + value: content.eval(data.script), + id: data.id + }); +}); + addEventListener("load", function() { sendAsyncMessage("devtools:test:load"); }, true);
--- a/browser/devtools/shared/test/browser.ini +++ b/browser/devtools/shared/test/browser.ini @@ -44,16 +44,18 @@ support-files = [browser_tableWidget_basic.js] [browser_tableWidget_keyboard_interaction.js] [browser_tableWidget_mouse_interaction.js] skip-if = buildapp == 'mulet' [browser_telemetry_button_paintflashing.js] [browser_telemetry_button_responsive.js] [browser_telemetry_button_scratchpad.js] [browser_telemetry_button_tilt.js] +skip-if = e10s # Bug 1086492 - Disable tilt for e10s + # Bug 937166 - Make tilt work in E10S mode [browser_telemetry_sidebar.js] [browser_telemetry_toolbox.js] [browser_telemetry_toolboxtabs_canvasdebugger.js] [browser_telemetry_toolboxtabs_inspector.js] [browser_telemetry_toolboxtabs_jsdebugger.js] [browser_telemetry_toolboxtabs_jsprofiler.js] [browser_telemetry_toolboxtabs_netmonitor.js] [browser_telemetry_toolboxtabs_options.js]
--- a/browser/devtools/tilt/test/browser.ini +++ b/browser/devtools/tilt/test/browser.ini @@ -1,10 +1,11 @@ [DEFAULT] -skip-if = e10s # Bug ?????? - devtools tests disabled with e10s +skip-if = e10s # Bug 1086492 - Disable tilt for e10s + # Bug 937166 - Make tilt work in E10S mode subsuite = devtools support-files = head.js [browser_tilt_01_lazy_getter.js] [browser_tilt_02_notifications-seq.js] [browser_tilt_02_notifications-tabs.js] [browser_tilt_02_notifications.js] [browser_tilt_03_tab_switch.js]
--- a/browser/devtools/tilt/tilt-commands.js +++ b/browser/devtools/tilt/tilt-commands.js @@ -15,23 +15,29 @@ Object.defineProperty(this, "TiltManager }, enumerable: true }); exports.items = [ { name: 'tilt', description: gcli.lookup("tiltDesc"), - manual: gcli.lookup("tiltManual") + manual: gcli.lookup("tiltManual"), + hidden: true }, { name: 'tilt open', description: gcli.lookup("tiltOpenDesc"), manual: gcli.lookup("tiltOpenManual"), + hidden: true, exec: function(args, context) { + if (isMultiProcess(context)) { + return gcli.lookupFormat("notAvailableInE10S", [this.name]); + } + let chromeWindow = context.environment.chromeDocument.defaultView; let Tilt = TiltManager.getTiltForBrowser(chromeWindow); if (!Tilt.currentInstance) { Tilt.toggle(); } } }, { @@ -54,25 +60,30 @@ exports.items = [ if (aTarget.tab) { let browserWindow = aTarget.tab.ownerDocument.defaultView; let tilt = TiltManager.getTiltForBrowser(browserWindow); tilt.off("change", aChangeHandler); } }, }, exec: function(args, context) { + if (isMultiProcess(context)) { + return gcli.lookupFormat("notAvailableInE10S", [this.name]); + } + let chromeWindow = context.environment.chromeDocument.defaultView; let Tilt = TiltManager.getTiltForBrowser(chromeWindow); Tilt.toggle(); } }, { name: 'tilt translate', description: gcli.lookup("tiltTranslateDesc"), manual: gcli.lookup("tiltTranslateManual"), + hidden: true, params: [ { name: "x", type: "number", defaultValue: 0, description: gcli.lookup("tiltTranslateXDesc"), manual: gcli.lookup("tiltTranslateXManual") }, @@ -80,27 +91,32 @@ exports.items = [ name: "y", type: "number", defaultValue: 0, description: gcli.lookup("tiltTranslateYDesc"), manual: gcli.lookup("tiltTranslateYManual") } ], exec: function(args, context) { + if (isMultiProcess(context)) { + return gcli.lookupFormat("notAvailableInE10S", [this.name]); + } + let chromeWindow = context.environment.chromeDocument.defaultView; let Tilt = TiltManager.getTiltForBrowser(chromeWindow); if (Tilt.currentInstance) { Tilt.currentInstance.controller.arcball.translate([args.x, args.y]); } } }, { name: 'tilt rotate', description: gcli.lookup("tiltRotateDesc"), manual: gcli.lookup("tiltRotateManual"), + hidden: true, params: [ { name: "x", type: { name: 'number', min: -360, max: 360, step: 10 }, defaultValue: 0, description: gcli.lookup("tiltRotateXDesc"), manual: gcli.lookup("tiltRotateXManual") }, @@ -115,61 +131,84 @@ exports.items = [ name: "z", type: { name: 'number', min: -360, max: 360, step: 10 }, defaultValue: 0, description: gcli.lookup("tiltRotateZDesc"), manual: gcli.lookup("tiltRotateZManual") } ], exec: function(args, context) { + if (isMultiProcess(context)) { + return gcli.lookupFormat("notAvailableInE10S", [this.name]); + } + let chromeWindow = context.environment.chromeDocument.defaultView; let Tilt = TiltManager.getTiltForBrowser(chromeWindow); if (Tilt.currentInstance) { Tilt.currentInstance.controller.arcball.rotate([args.x, args.y, args.z]); } } }, { name: 'tilt zoom', description: gcli.lookup("tiltZoomDesc"), manual: gcli.lookup("tiltZoomManual"), + hidden: true, params: [ { name: "zoom", type: { name: 'number' }, description: gcli.lookup("tiltZoomAmountDesc"), manual: gcli.lookup("tiltZoomAmountManual") } ], exec: function(args, context) { + if (isMultiProcess(context)) { + return gcli.lookupFormat("notAvailableInE10S", [this.name]); + } + let chromeWindow = context.environment.chromeDocument.defaultView; let Tilt = TiltManager.getTiltForBrowser(chromeWindow); if (Tilt.currentInstance) { Tilt.currentInstance.controller.arcball.zoom(-args.zoom); } } }, { name: 'tilt reset', description: gcli.lookup("tiltResetDesc"), manual: gcli.lookup("tiltResetManual"), + hidden: true, exec: function(args, context) { + if (isMultiProcess(context)) { + return gcli.lookupFormat("notAvailableInE10S", [this.name]); + } + let chromeWindow = context.environment.chromeDocument.defaultView; let Tilt = TiltManager.getTiltForBrowser(chromeWindow); if (Tilt.currentInstance) { Tilt.currentInstance.controller.arcball.reset(); } } }, { name: 'tilt close', description: gcli.lookup("tiltCloseDesc"), manual: gcli.lookup("tiltCloseManual"), + hidden: true, exec: function(args, context) { + if (isMultiProcess(context)) { + return gcli.lookupFormat("notAvailableInE10S", [this.name]); + } + let chromeWindow = context.environment.chromeDocument.defaultView; let Tilt = TiltManager.getTiltForBrowser(chromeWindow); Tilt.destroy(Tilt.currentWindowId); } } ]; + +function isMultiProcess(context) { + return !context.environment.window; +}
--- a/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties +++ b/browser/locales/en-US/chrome/browser/devtools/gclicommands.properties @@ -15,16 +15,20 @@ # LOCALIZATION NOTE (helpDesc) A very short string used to describe the # function of the help command. helpDesc=Get help on the available commands # LOCALIZATION NOTE (helpAvailable) Used in the output of the help command to # explain the contents of the command help table. helpAvailable=Available Commands +# LOCALIZATION NOTE (notAvailableInE10S) Used in the output of any command that +# is not compatible with multiprocess mode (E10S). +notAvailableInE10S=The command '%1$S' is not available in multiprocess mode (E10S) + # LOCALIZATION NOTE (consoleDesc) A very short string used to describe the # function of the console command. consoleDesc=Commands to control the console # LOCALIZATION NOTE (consoleManual) A longer description describing the # set of commands that control the console. consoleManual=Filter, clear and close the web console
--- a/browser/modules/UITour.jsm +++ b/browser/modules/UITour.jsm @@ -96,16 +96,18 @@ this.UITour = { "class", "toolbarbutton-icon"); }, widgetName: "PanelUI-customize", }], ["help", {query: "#PanelUI-help"}], ["home", {query: "#home-button"}], ["loop", {query: "#loop-call-button"}], + ["devtools", {query: "#developer-button"}], + ["webide", {query: "#webide-button"}], ["forget", { query: "#panic-button", widgetName: "panic-button", allowAdd: true }], ["privateWindow", {query: "#privatebrowsing-button"}], ["quit", {query: "#PanelUI-quit"}], ["search", { query: "#searchbar",
--- a/browser/modules/test/browser_UITour_availableTargets.js +++ b/browser/modules/test/browser_UITour_availableTargets.js @@ -4,16 +4,18 @@ "use strict"; let gTestTab; let gContentAPI; let gContentWindow; Components.utils.import("resource:///modules/UITour.jsm"); +let hasWebIDE = Services.prefs.getBoolPref("devtools.webide.widget.enabled"); + function test() { requestLongerTimeout(2); UITourTest(); } function searchEngineTargets() { let engines = Services.search.getVisibleEngines(); return ["searchEngine-" + engine.identifier @@ -29,23 +31,27 @@ let tests = [ "addons", "appMenu", "backForward", "bookmarks", "customize", "help", "home", "loop", + "devtools", "pinnedTab", "privateWindow", "quit", "search", "searchProvider", "urlbar", - ].concat(searchEngineTargets())); + ...searchEngineTargets(), + ...(hasWebIDE ? ["webide"] : []) + ]); + ok(UITour.availableTargetsCache.has(window), "Targets should now be cached"); done(); }); }, function test_availableTargets_changeWidgets(done) { CustomizableUI.removeWidgetFromArea("bookmarks-menu-button"); @@ -55,24 +61,28 @@ let tests = [ ok_targets(data, [ "accountStatus", "addons", "appMenu", "backForward", "customize", "help", "loop", + "devtools", "home", "pinnedTab", "privateWindow", "quit", "search", "searchProvider", "urlbar", - ].concat(searchEngineTargets())); + ...searchEngineTargets(), + ...(hasWebIDE ? ["webide"] : []) + ]); + ok(UITour.availableTargetsCache.has(window), "Targets should now be cached again"); CustomizableUI.reset(); ok(!UITour.availableTargetsCache.has(window), "Targets should not be cached after reset"); done(); }); }, @@ -88,21 +98,24 @@ let tests = [ "addons", "appMenu", "backForward", "bookmarks", "customize", "help", "home", "loop", + "devtools", "pinnedTab", "privateWindow", "quit", "urlbar", + ...(hasWebIDE ? ["webide"] : []) ]); + CustomizableUI.reset(); done(); }); }, ]; function ok_targets(actualData, expectedTargets) { // Depending on how soon after page load this is called, the selected tab icon
--- a/dom/icc/IccCardLockError.cpp +++ b/dom/icc/IccCardLockError.cpp @@ -7,38 +7,35 @@ namespace mozilla { namespace dom { NS_IMPL_ISUPPORTS_INHERITED0(IccCardLockError, DOMError) /* static */ already_AddRefed<IccCardLockError> IccCardLockError::Constructor(const GlobalObject& aGlobal, - const nsAString& aLockType, const nsAString& aName, int16_t aRetryCount, ErrorResult& aRv) { nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobal.GetAsSupports()); if (!window) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } nsRefPtr<IccCardLockError> result = - new IccCardLockError(window, aName, aLockType, aRetryCount); + new IccCardLockError(window, aName, aRetryCount); return result.forget(); } IccCardLockError::IccCardLockError(nsPIDOMWindow* aWindow, const nsAString& aName, - const nsAString& aLockType, int16_t aRetryCount) : DOMError(aWindow, aName) - , mLockType(aLockType) , mRetryCount(aRetryCount) { } JSObject* IccCardLockError::WrapObject(JSContext* aCx) { return IccCardLockErrorBinding::Wrap(aCx, this);
--- a/dom/icc/IccCardLockError.h +++ b/dom/icc/IccCardLockError.h @@ -11,44 +11,36 @@ namespace mozilla { namespace dom { class IccCardLockError MOZ_FINAL : public DOMError { public: NS_DECL_ISUPPORTS_INHERITED IccCardLockError(nsPIDOMWindow* aWindow, const nsAString& aName, - const nsAString& aLockType, int16_t aRetryCount); + int16_t aRetryCount); static already_AddRefed<IccCardLockError> - Constructor(const GlobalObject& aGlobal, const nsAString& aLockType, - const nsAString& aName, int16_t aRetryCount, - ErrorResult& aRv); + Constructor(const GlobalObject& aGlobal, const nsAString& aName, + int16_t aRetryCount, ErrorResult& aRv); virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; // WebIDL interface - void - GetLockType(nsString& aLockType) const - { - aLockType = mLockType; - } - int16_t RetryCount() const { return mRetryCount; } private: ~IccCardLockError() {} private: - nsString mLockType; int16_t mRetryCount; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_IccCardLockError_h
--- a/dom/icc/tests/marionette/test_icc_card_lock.js +++ b/dom/icc/tests/marionette/test_icc_card_lock.js @@ -12,17 +12,16 @@ taskHelper.push(function testPinChangeFa pin: "1111", newPin: "0000"}); ok(request instanceof DOMRequest, "request instanceof " + request.constructor); request.onerror = function onerror() { is(request.error.name, "IncorrectPassword"); - is(request.error.lockType, "pin"); // The default pin retries is 3, failed once becomes to 2 is(request.error.retryCount, 2); // Reset pin retries by passing correct pin code. let resetRequest = icc.setCardLock( {lockType: "pin", pin: "0000", newPin: "0000"});
--- a/dom/icc/tests/marionette/test_stk_display_text.js +++ b/dom/icc/tests/marionette/test_stk_display_text.js @@ -184,11 +184,45 @@ let tests = [ "1E" + "F6" + // 8BIT + Class 2 "546F6F6C6B697420546573742047524F" + "55503A307846302C2038424954", func: testDisplayText, expect: {name: "display_text_cmd_20", commandQualifier: 0x00, text: "Toolkit Test GROUP:0xF0, 8BIT"}}, + // Bug 1088573: this test case is to ensure that we provide |length| argument + // in |integer| format to GsmPDUHelper.readSeptetsToString(). + {command: "D0" + + "81" + // 2-byte length encoded: + "FC" + // 252 + "810301210082028102" + + "8D" + + "81" + // 2-byte length encoded: + "F0" + // 240 + "00" + // 7BIT + "C332A85D9ECFC3E732685E068DDF6DF8" + + "7B5E0691CB20D96D061A87E5E131BD2C" + + "2FCF416537A8FD269741E3771B2E2FCF" + + "E76517685806B5CBF379F85C0695E774" + + "50D86C4E8FD165D0BC2E07C1D9F579BA" + + "5C97CF41E5B13CEC9E83CA7490BB0C22" + + "BFD374103C3C0795E9F232882E7FBBE3" + + "F5B20B24BBCD40E5391DC42E83DCEFB6" + + "585E06B5C3F874BBDE0691CBA071581E" + + "1ED3CBF2F21C14369BD3637458CC2EBB" + + "40C3329D5E0699DFEE313DFD76BBC3EC" + + "34BD0C0A83CAF432280C87CBDF757BB9" + + "0C8287E5207619346D1E73A0783D0D9A" + + "9FCA733A885C96BFEBEC32280C9A6689" + + "CE621654768382D529551A64268B2E", + func: testDisplayText, + expect: {name: "display_text_cmd_21", + commandQualifier: 0x00, + text: "Ce message se compose de 273 caracteres en mode " + + "compresse. Ce message est affiche sur plusieurs " + + "ecrans et ne doit pas etre tronque. 273 est le " + + "nombre maximum de caracteres affichable. Cette " + + "fonctionnalite a ete approuvee par le SMG9 qui s'est " + + "deroule a SYDNEY en AUSTRALIE."}}, ]; runNextTest();
--- a/dom/mobileconnection/Assertions.cpp +++ b/dom/mobileconnection/Assertions.cpp @@ -23,10 +23,29 @@ ASSERT_NETWORK_SELECTION_MODE_EQUALITY(M ASSERT_MOBILE_RADIO_STATE_EQUALITY(Enabling, MOBILE_RADIO_STATE_ENABLING); ASSERT_MOBILE_RADIO_STATE_EQUALITY(Enabled, MOBILE_RADIO_STATE_ENABLED); ASSERT_MOBILE_RADIO_STATE_EQUALITY(Disabling, MOBILE_RADIO_STATE_DISABLING); ASSERT_MOBILE_RADIO_STATE_EQUALITY(Disabled, MOBILE_RADIO_STATE_DISABLED); #undef ASSERT_MOBILE_RADIO_STATE_EQUALITY +#define ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(webidlState, xpidlState) \ + static_assert(static_cast<int32_t>(MobilePreferredNetworkType::webidlState) == nsIMobileConnection::xpidlState, \ + "MobilePreferredNetworkType::" #webidlState " should equal to nsIMobileConnection::" #xpidlState) + +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Wcdma_gsm, PREFERRED_NETWORK_TYPE_WCDMA_GSM); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Gsm, PREFERRED_NETWORK_TYPE_GSM_ONLY); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Wcdma, PREFERRED_NETWORK_TYPE_WCDMA_ONLY); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Wcdma_gsm_auto, PREFERRED_NETWORK_TYPE_WCDMA_GSM_AUTO); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Cdma_evdo, PREFERRED_NETWORK_TYPE_CDMA_EVDO); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Cdma, PREFERRED_NETWORK_TYPE_CDMA_ONLY); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Evdo, PREFERRED_NETWORK_TYPE_EVDO_ONLY); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Wcdma_gsm_cdma_evdo, PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Lte_cdma_evdo, PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Lte_wcdma_gsm, PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Lte_wcdma_gsm_cdma_evdo, PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO); +ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY(Lte, PREFERRED_NETWORK_TYPE_LTE_ONLY); + +#undef ASSERT_PREFERRED_NETWORK_TYPE_EQUALITY + } // namespace dom } // namespace mozilla
--- a/dom/mobileconnection/MobileConnection.cpp +++ b/dom/mobileconnection/MobileConnection.cpp @@ -472,18 +472,17 @@ already_AddRefed<DOMRequest> MobileConnection::SetPreferredNetworkType(MobilePreferredNetworkType& aType, ErrorResult& aRv) { if (!mMobileConnection) { aRv.Throw(NS_ERROR_FAILURE); return nullptr; } - nsAutoString type; - CONVERT_ENUM_TO_STRING(MobilePreferredNetworkType, aType, type); + int32_t type = static_cast<int32_t>(aType); nsRefPtr<DOMRequest> request = new DOMRequest(GetOwner()); nsRefPtr<MobileConnectionCallback> requestCallback = new MobileConnectionCallback(GetOwner(), request); nsresult rv = mMobileConnection->SetPreferredNetworkType(type, requestCallback); if (NS_FAILED(rv)) {
--- a/dom/mobileconnection/MobileConnectionCallback.cpp +++ b/dom/mobileconnection/MobileConnectionCallback.cpp @@ -10,16 +10,23 @@ #include "mozilla/dom/ToJSValue.h" #include "nsJSUtils.h" #include "nsServiceManagerUtils.h" namespace mozilla { namespace dom { namespace mobileconnection { +#define CONVERT_ENUM_TO_STRING(_enumType, _enum, _string) \ +{ \ + uint32_t index = uint32_t(_enum); \ + _string.AssignASCII(_enumType##Values::strings[index].value, \ + _enumType##Values::strings[index].length); \ +} + NS_IMPL_ISUPPORTS(MobileConnectionCallback, nsIMobileConnectionCallback) MobileConnectionCallback::MobileConnectionCallback(nsPIDOMWindow* aWindow, DOMRequest* aRequest) : mWindow(aWindow) , mRequest(aRequest) { } @@ -345,16 +352,28 @@ MobileConnectionCallback::NotifyGetClirS JS_ClearPendingException(cx); return NS_ERROR_TYPE_ERR; } return NotifySuccess(jsResult); }; NS_IMETHODIMP +MobileConnectionCallback::NotifyGetPreferredNetworkTypeSuccess(int32_t aType) +{ + MOZ_ASSERT(aType < static_cast<int32_t>(MobilePreferredNetworkType::EndGuard_)); + MobilePreferredNetworkType type = static_cast<MobilePreferredNetworkType>(aType); + + nsAutoString typeString; + CONVERT_ENUM_TO_STRING(MobilePreferredNetworkType, type, typeString); + + return NotifySuccessWithString(typeString); +}; + +NS_IMETHODIMP MobileConnectionCallback::NotifyError(const nsAString& aName, const nsAString& aMessage, const nsAString& aServiceCode, uint16_t aInfo, uint8_t aArgc) { nsCOMPtr<nsIDOMRequestService> rs = do_GetService(DOMREQUEST_SERVICE_CONTRACTID); NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
--- a/dom/mobileconnection/gonk/MobileConnectionService.js +++ b/dom/mobileconnection/gonk/MobileConnectionService.js @@ -769,17 +769,17 @@ MobileConnectionProvider.prototype = { this._radioInterface.sendWorkerMessage("getPreferredNetworkType", null, (function(aResponse) { if (aResponse.errorMsg) { aCallback.notifyError(aResponse.errorMsg); return false; } - aCallback.notifySuccessWithString(aResponse.type); + aCallback.notifyGetPreferredNetworkTypeSuccess(aResponse.type); return false; }).bind(this)); }, setRoamingPreference: function(aMode, aCallback) { this._radioInterface.sendWorkerMessage("setRoamingPreference", {mode: aMode}, (function(aResponse) {
--- a/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl +++ b/dom/mobileconnection/interfaces/nsIMobileConnectionService.idl @@ -119,17 +119,17 @@ interface nsIMobileConnectionListener : */ void notifyNetworkSelectionModeChanged(); }; %{C++ #define NO_ADDITIONAL_INFORMATION 0 %} -[scriptable, builtinclass, uuid(05568ae9-9873-46c6-9acd-0f6994cde756)] +[scriptable, builtinclass, uuid(413e8bff-9f65-41a0-953f-b82e6cdbc00d)] interface nsIMobileConnectionCallback : nsISupports { /** * notify*Success*() will be called, when request is succeed. */ void notifySuccess(); void notifySuccessWithString(in DOMString result); @@ -161,16 +161,18 @@ interface nsIMobileConnectionCallback : void notifyGetCallBarringSuccess(in unsigned short program, in boolean enabled, in unsigned short serviceClass); void notifyGetClirStatusSuccess(in unsigned short n, in unsigned short m); + void notifyGetPreferredNetworkTypeSuccess(in long type); + /** * notifyError() will be called, when request is failed. */ [optional_argc] void notifyError(in DOMString name, [optional] in DOMString message, [optional] in DOMString serviceCode, [optional] in unsigned short additionalInformation); @@ -228,17 +230,17 @@ interface nsIMobileConnectionService : n %{C++ template<typename T> struct already_AddRefed; already_AddRefed<nsIMobileConnectionService> NS_CreateMobileConnectionService(); %} -[scriptable, uuid(99818dc7-e770-4249-87e2-2de0a928ed08)] +[scriptable, uuid(d6b15551-d290-4e38-9749-d21eb35cdaf1)] interface nsIMobileConnection : nsISupports { /* * ICC service class. */ const long ICC_SERVICE_CLASS_NONE = 0; // not available const long ICC_SERVICE_CLASS_VOICE = (1 << 0); const long ICC_SERVICE_CLASS_DATA = (1 << 1); @@ -305,16 +307,32 @@ interface nsIMobileConnection : nsISuppo * Mobile Radio State. */ const long MOBILE_RADIO_STATE_UNKNOWN = -1; const long MOBILE_RADIO_STATE_ENABLING = 0; const long MOBILE_RADIO_STATE_ENABLED = 1; const long MOBILE_RADIO_STATE_DISABLING = 2; const long MOBILE_RADIO_STATE_DISABLED = 3; + /** + * Preferred network type. + */ + const long PREFERRED_NETWORK_TYPE_WCDMA_GSM = 0; + const long PREFERRED_NETWORK_TYPE_GSM_ONLY = 1; + const long PREFERRED_NETWORK_TYPE_WCDMA_ONLY = 2; + const long PREFERRED_NETWORK_TYPE_WCDMA_GSM_AUTO = 3; + const long PREFERRED_NETWORK_TYPE_CDMA_EVDO = 4; + const long PREFERRED_NETWORK_TYPE_CDMA_ONLY = 5; + const long PREFERRED_NETWORK_TYPE_EVDO_ONLY = 6; + const long PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO = 7; + const long PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO = 8; + const long PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM = 9; + const long PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO = 10; + const long PREFERRED_NETWORK_TYPE_LTE_ONLY = 11; + readonly attribute unsigned long serviceId; /** * Called when any one who is interested in receiving unsolicited messages * from this nsIMobileConnection instance. */ void registerListener(in nsIMobileConnectionListener listener); void unregisterListener(in nsIMobileConnectionListener listener); @@ -413,44 +431,39 @@ interface nsIMobileConnection : nsISuppo * 'GenericFailure'. */ void selectNetworkAutomatically(in nsIMobileConnectionCallback requestCallback); /** * Set preferred network type. * * @param type - * DOMString indicates the desired preferred network type. - * Possible values: 'wcdma/gsm', 'gsm', 'wcdma', 'wcdma/gsm-auto', - * 'cdma/evdo', 'cdma', 'evdo', 'wcdma/gsm/cdma/evdo', - * 'lte/cdma/evdo', 'lte/wcdma/gsm', 'lte/wcdma/gsm/cdma/evdo' or - * 'lte'. + * One of the nsIMobileConnection.PREFERRED_NETWORK_TYPE_* values. * @param requestCallback * Called when request is finished. * * If successful, the notifySuccess() will be called. * * Otherwise, the notifyError() will be called, and the error will be either * 'RadioNotAvailable', 'RequestNotSupported', 'InvalidParameter', * 'IllegalSIMorME', or 'GenericFailure'. */ - void setPreferredNetworkType(in DOMString type, + void setPreferredNetworkType(in long type, in nsIMobileConnectionCallback requestCallback); /** * Query current preferred network type. * * @param requestCallback * Called when request is finished. * - * If successful, the notifySuccessString() will be called. And the result - * will be a string indicating the current preferred network type. The value - * will be either 'wcdma/gsm', 'gsm', 'wcdma', 'wcdma/gsm-auto', 'cdma/evdo', - * 'cdma', 'evdo', 'wcdma/gsm/cdma/evdo', 'lte/cdma/evdo', 'lte/wcdma/gsm', - * 'lte/wcdma/gsm/cdma/evdo' or 'lte'. + * If successful, the notifyGetPreferredNetworkTypeSuccess() will be called, + * and the result 'type' will be one of the + * nsIMobileConnection.PREFERRED_NETWORK_TYPE_* values, indicating the current + * preferred network type. * * Otherwise, the notifyError() will be called, and the error will be either * 'RadioNotAvailable', 'RequestNotSupported', 'IllegalSIMorME', or * 'GenericFailure'. */ void getPreferredNetworkType(in nsIMobileConnectionCallback requestCallback); /**
--- a/dom/mobileconnection/ipc/MobileConnectionChild.cpp +++ b/dom/mobileconnection/ipc/MobileConnectionChild.cpp @@ -173,21 +173,20 @@ NS_IMETHODIMP MobileConnectionChild::SelectNetworkAutomatically(nsIMobileConnectionCallback* aCallback) { return SendRequest(SelectNetworkAutoRequest(), aCallback) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP -MobileConnectionChild::SetPreferredNetworkType(const nsAString& aType, +MobileConnectionChild::SetPreferredNetworkType(int32_t aType, nsIMobileConnectionCallback* aCallback) { - return SendRequest(SetPreferredNetworkTypeRequest(nsAutoString(aType)), - aCallback) + return SendRequest(SetPreferredNetworkTypeRequest(aType), aCallback) ? NS_OK : NS_ERROR_FAILURE; } NS_IMETHODIMP MobileConnectionChild::GetPreferredNetworkType(nsIMobileConnectionCallback* aCallback) { return SendRequest(GetPreferredNetworkTypeRequest(), aCallback) ? NS_OK : NS_ERROR_FAILURE; @@ -657,16 +656,22 @@ MobileConnectionRequestChild::DoReply(co bool MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessClirStatus& aReply) { return NS_SUCCEEDED(mRequestCallback->NotifyGetClirStatusSuccess(aReply.n(), aReply.m())); } bool +MobileConnectionRequestChild::DoReply(const MobileConnectionReplySuccessPreferredNetworkType& aReply) +{ + return NS_SUCCEEDED(mRequestCallback->NotifyGetPreferredNetworkTypeSuccess(aReply.type())); +} + +bool MobileConnectionRequestChild::DoReply(const MobileConnectionReplyError& aReply) { return NS_SUCCEEDED(mRequestCallback->NotifyError(aReply.message())); } bool MobileConnectionRequestChild::DoReply(const MobileConnectionReplyErrorMmi& aReply) { @@ -710,16 +715,18 @@ MobileConnectionRequestChild::Recv__dele case MobileConnectionReply::TMobileConnectionReplySuccessMmi: return DoReply(aReply.get_MobileConnectionReplySuccessMmi()); case MobileConnectionReply::TMobileConnectionReplySuccessCallForwarding: return DoReply(aReply.get_MobileConnectionReplySuccessCallForwarding()); case MobileConnectionReply::TMobileConnectionReplySuccessCallBarring: return DoReply(aReply.get_MobileConnectionReplySuccessCallBarring()); case MobileConnectionReply::TMobileConnectionReplySuccessClirStatus: return DoReply(aReply.get_MobileConnectionReplySuccessClirStatus()); + case MobileConnectionReply::TMobileConnectionReplySuccessPreferredNetworkType: + return DoReply(aReply.get_MobileConnectionReplySuccessPreferredNetworkType()); case MobileConnectionReply::TMobileConnectionReplyError: return DoReply(aReply.get_MobileConnectionReplyError()); case MobileConnectionReply::TMobileConnectionReplyErrorMmi: return DoReply(aReply.get_MobileConnectionReplyErrorMmi()); default: MOZ_CRASH("Received invalid response type!"); }
--- a/dom/mobileconnection/ipc/MobileConnectionChild.h +++ b/dom/mobileconnection/ipc/MobileConnectionChild.h @@ -159,16 +159,19 @@ public: bool DoReply(const MobileConnectionReplySuccessCallBarring& aReply); bool DoReply(const MobileConnectionReplySuccessClirStatus& aReply); bool + DoReply(const MobileConnectionReplySuccessPreferredNetworkType& aReply); + + bool DoReply(const MobileConnectionReplyError& aReply); bool DoReply(const MobileConnectionReplyErrorMmi& aReply); protected: virtual ~MobileConnectionRequestChild()
--- a/dom/mobileconnection/ipc/MobileConnectionParent.cpp +++ b/dom/mobileconnection/ipc/MobileConnectionParent.cpp @@ -638,16 +638,22 @@ MobileConnectionRequestParent::NotifyGet NS_IMETHODIMP MobileConnectionRequestParent::NotifyGetClirStatusSuccess(uint16_t aN, uint16_t aM) { return SendReply(MobileConnectionReplySuccessClirStatus(aN, aM)); } NS_IMETHODIMP +MobileConnectionRequestParent::NotifyGetPreferredNetworkTypeSuccess(int32_t aType) +{ + return SendReply(MobileConnectionReplySuccessPreferredNetworkType(aType)); +} + +NS_IMETHODIMP MobileConnectionRequestParent::NotifyError(const nsAString& aName, const nsAString& aMessage, const nsAString& aServiceCode, uint16_t aInfo, uint8_t aArgc) { if (aArgc == 0) { nsAutoString error(aName);
--- a/dom/mobileconnection/ipc/PMobileConnection.ipdl +++ b/dom/mobileconnection/ipc/PMobileConnection.ipdl @@ -67,17 +67,17 @@ struct SelectNetworkRequest }; struct SelectNetworkAutoRequest { }; struct SetPreferredNetworkTypeRequest { - nsString type; + int32_t type; }; struct GetPreferredNetworkTypeRequest { }; struct SetRoamingPreferenceRequest {
--- a/dom/mobileconnection/ipc/PMobileConnectionRequest.ipdl +++ b/dom/mobileconnection/ipc/PMobileConnectionRequest.ipdl @@ -65,16 +65,21 @@ struct MobileConnectionReplySuccessCallB }; struct MobileConnectionReplySuccessClirStatus { uint16_t n; uint16_t m; }; +struct MobileConnectionReplySuccessPreferredNetworkType +{ + int32_t type; +}; + // Error struct MobileConnectionReplyError { nsString message; }; struct MobileConnectionReplyErrorMmi { @@ -90,16 +95,17 @@ union MobileConnectionReply MobileConnectionReplySuccess; MobileConnectionReplySuccessString; MobileConnectionReplySuccessBoolean; MobileConnectionReplySuccessNetworks; MobileConnectionReplySuccessMmi; MobileConnectionReplySuccessCallForwarding; MobileConnectionReplySuccessCallBarring; MobileConnectionReplySuccessClirStatus; + MobileConnectionReplySuccessPreferredNetworkType; // Error MobileConnectionReplyError; MobileConnectionReplyErrorMmi; }; } // namespace mobileconnection } // namespace dom } // namespace mozilla
--- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp +++ b/dom/system/gonk/GonkGPSGeolocationProvider.cpp @@ -27,32 +27,36 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsINetworkManager.h" #include "nsIObserverService.h" #include "nsJSUtils.h" #include "nsPrintfCString.h" #include "nsServiceManagerUtils.h" #include "nsThreadUtils.h" #include "prtime.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/dom/SettingChangeNotificationBinding.h" #ifdef MOZ_B2G_RIL #include "nsIIccInfo.h" #include "nsIMobileConnectionInfo.h" #include "nsIMobileConnectionService.h" #include "nsIMobileCellInfo.h" #include "nsIRadioInterfaceLayer.h" #endif #ifdef AGPS_TYPE_INVALID #define AGPS_HAVE_DUAL_APN #endif #define FLUSH_AIDE_DATA 0 using namespace mozilla; +using namespace mozilla::dom; static const int kDefaultPeriod = 1000; // ms static bool gDebug_isLoggingEnabled = false; static bool gDebug_isGPSLocationIgnored = false; static const char* kNetworkConnStateChangedTopic = "network-connection-state-changed"; static const char* kMozSettingsChangedTopic = "mozsettings-changed"; // Both of these settings can be toggled in the Gaia Developer settings screen. static const char* kSettingDebugEnabled = "geolocation.debugging.enabled"; @@ -395,19 +399,31 @@ void GonkGPSGeolocationProvider::RequestSettingValue(const char* aKey) { MOZ_ASSERT(aKey); nsCOMPtr<nsISettingsService> ss = do_GetService("@mozilla.org/settingsService;1"); if (!ss) { MOZ_ASSERT(ss); return; } + nsCOMPtr<nsISettingsServiceLock> lock; - ss->CreateLock(nullptr, getter_AddRefs(lock)); - lock->Get(aKey, this); + nsresult rv = ss->CreateLock(nullptr, getter_AddRefs(lock)); + if (NS_FAILED(rv)) { + nsContentUtils::LogMessageToConsole( + "geo: error while createLock setting '%s': %d\n", aKey, rv); + return; + } + + rv = lock->Get(aKey, this); + if (NS_FAILED(rv)) { + nsContentUtils::LogMessageToConsole( + "geo: error while get setting '%s': %d\n", aKey, rv); + return; + } } #ifdef MOZ_B2G_RIL void GonkGPSGeolocationProvider::RequestDataConnection() { MOZ_ASSERT(NS_IsMainThread()); @@ -809,32 +825,32 @@ GonkGPSGeolocationProvider::NetworkLocat return NS_OK; } NS_IMETHODIMP GonkGPSGeolocationProvider::Startup() { MOZ_ASSERT(NS_IsMainThread()); + if (mStarted) { + return NS_OK; + } + RequestSettingValue(kSettingDebugEnabled); RequestSettingValue(kSettingDebugGpsIgnored); // Setup an observer to watch changes to the setting. nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); if (observerService) { nsresult rv = observerService->AddObserver(this, kMozSettingsChangedTopic, false); if (NS_FAILED(rv)) { NS_WARNING("geo: Gonk GPS AddObserver failed"); } } - if (mStarted) { - return NS_OK; - } - if (!mInitThread) { nsresult rv = NS_NewThread(getter_AddRefs(mInitThread)); NS_ENSURE_SUCCESS(rv, rv); } mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::Init), NS_DISPATCH_NORMAL); @@ -863,28 +879,36 @@ GonkGPSGeolocationProvider::Watch(nsIGeo NS_IMETHODIMP GonkGPSGeolocationProvider::Shutdown() { MOZ_ASSERT(NS_IsMainThread()); if (!mStarted) { return NS_OK; } + mStarted = false; if (mNetworkLocationProvider) { mNetworkLocationProvider->Shutdown(); mNetworkLocationProvider = nullptr; } nsCOMPtr<nsIObserverService> obs = services::GetObserverService(); if (obs) { + nsresult rv; #ifdef MOZ_B2G_RIL - obs->RemoveObserver(this, kNetworkConnStateChangedTopic); + rv = obs->RemoveObserver(this, kNetworkConnStateChangedTopic); + if (NS_FAILED(rv)) { + NS_WARNING("geo: Gonk GPS network state RemoveObserver failed"); + } #endif - obs->RemoveObserver(this, kMozSettingsChangedTopic); + rv = obs->RemoveObserver(this, kMozSettingsChangedTopic); + if (NS_FAILED(rv)) { + NS_WARNING("geo: Gonk GPS mozsettings RemoveObserver failed"); + } } mInitThread->Dispatch(NS_NewRunnableMethod(this, &GonkGPSGeolocationProvider::ShutdownGPS), NS_DISPATCH_NORMAL); return NS_OK; } @@ -986,18 +1010,40 @@ GonkGPSGeolocationProvider::Observe(nsIS return NS_OK; } RequestSettingValue("ril.supl.apn"); } #endif if (!strcmp(aTopic, kMozSettingsChangedTopic)) { - RequestSettingValue(kSettingDebugEnabled); - RequestSettingValue(kSettingDebugGpsIgnored); + // Read changed setting value + AutoJSAPI jsapi; + jsapi.Init(); + JSContext* cx = jsapi.cx(); + RootedDictionary<SettingChangeNotification> setting(cx); + if (!WrappedJSToDictionary(cx, aSubject, setting)) { + return NS_OK; + } + + if (setting.mKey.EqualsASCII(kSettingDebugGpsIgnored)) { + nsContentUtils::LogMessageToConsole("geo: received mozsettings-changed: ignoring\n"); + gDebug_isGPSLocationIgnored = + setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false; + if (gDebug_isLoggingEnabled) { + nsContentUtils::LogMessageToConsole("geo: Debug: GPS ignored %d\n", + gDebug_isGPSLocationIgnored); + } + return NS_OK; + } else if (setting.mKey.EqualsASCII(kSettingDebugEnabled)) { + nsContentUtils::LogMessageToConsole("geo: received mozsettings-changed: logging\n"); + gDebug_isLoggingEnabled = + setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false; + return NS_OK; + } } return NS_OK; } /** nsISettingsServiceCallback **/ NS_IMETHODIMP @@ -1015,28 +1061,18 @@ GonkGPSGeolocationProvider::Handle(const nsAutoJSString apn; if (!apn.init(cx, aResult.toString())) { return NS_ERROR_FAILURE; } if (!apn.IsEmpty()) { SetAGpsDataConn(apn); } } - } else + } #endif // MOZ_B2G_RIL - if (aName.EqualsASCII(kSettingDebugGpsIgnored)) { - gDebug_isGPSLocationIgnored = aResult.isBoolean() ? aResult.toBoolean() : false; - if (gDebug_isLoggingEnabled) { - nsContentUtils::LogMessageToConsole("geo: Debug: GPS ignored %d\n", gDebug_isGPSLocationIgnored); - } - return NS_OK; - } else if (aName.EqualsASCII(kSettingDebugEnabled)) { - gDebug_isLoggingEnabled = aResult.isBoolean() ? aResult.toBoolean() : false; - return NS_OK; - } return NS_OK; } NS_IMETHODIMP GonkGPSGeolocationProvider::HandleError(const nsAString& aErrorMessage) { return NS_OK; }
--- a/dom/system/gonk/RILContentHelper.js +++ b/dom/system/gonk/RILContentHelper.js @@ -678,18 +678,17 @@ RILContentHelper.prototype = { delete this._windowsMap[requestId]; if (data.success) { let result = new MobileIccCardLockResult(data); this.fireRequestSuccess(requestId, result); } else { if (data.rilMessageType == "iccSetCardLock" || data.rilMessageType == "iccUnlockCardLock") { - let cardLockError = new requestWindow.IccCardLockError(data.lockType, - data.errorMsg, + let cardLockError = new requestWindow.IccCardLockError(data.errorMsg, data.retryCount); this.fireRequestDetailedError(requestId, cardLockError); } else { this.fireRequestError(requestId, data.errorMsg); } } break; }
--- a/dom/system/gonk/ril_worker.js +++ b/dom/system/gonk/ril_worker.js @@ -1328,18 +1328,18 @@ RilObject.prototype = { /** * Set the preferred network type. * * @param options An object contains a valid value of * RIL_PREFERRED_NETWORK_TYPE_TO_GECKO as its `type` attribute. */ setPreferredNetworkType: function(options) { - let networkType = RIL_PREFERRED_NETWORK_TYPE_TO_GECKO.indexOf(options.type); - if (networkType < 0) { + let networkType = options.type; + if (networkType < 0 || networkType >= RIL_PREFERRED_NETWORK_TYPE_TO_GECKO.length) { options.errorMsg = GECKO_ERROR_INVALID_PARAMETER; this.sendChromeMessage(options); return; } let Buf = this.context.Buf; Buf.newParcel(REQUEST_SET_PREFERRED_NETWORK_TYPE, options); Buf.writeInt32(1); @@ -5869,16 +5869,22 @@ RilObject.prototype[REQUEST_SET_CALL_FOR } this.sendChromeMessage(options); }; RilObject.prototype[REQUEST_QUERY_CALL_WAITING] = function REQUEST_QUERY_CALL_WAITING(length, options) { options.success = (options.rilRequestError === 0); if (!options.success) { options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]; + + if (options.callback) { + // Prevent DataCloneError when sending chrome messages. + delete options.callback; + } + this.sendChromeMessage(options); return; } if (options.callback) { options.callback.call(this, options); return; } @@ -5889,16 +5895,22 @@ RilObject.prototype[REQUEST_QUERY_CALL_W ((Buf.readInt32() & ICC_SERVICE_CLASS_VOICE) == 0x01)); this.sendChromeMessage(options); }; RilObject.prototype[REQUEST_SET_CALL_WAITING] = function REQUEST_SET_CALL_WAITING(length, options) { options.success = (options.rilRequestError === 0); if (!options.success) { options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]; + + if (options.callback) { + // Prevent DataCloneError when sending chrome messages. + delete options.callback; + } + this.sendChromeMessage(options); return; } if (options.callback) { options.callback.call(this, options); return; } @@ -6287,18 +6299,17 @@ RilObject.prototype[REQUEST_SET_PREFERRE }; RilObject.prototype[REQUEST_GET_PREFERRED_NETWORK_TYPE] = function REQUEST_GET_PREFERRED_NETWORK_TYPE(length, options) { if (options.rilRequestError) { options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]; this.sendChromeMessage(options); return; } - let networkType = this.context.Buf.readInt32List()[0]; - options.type = RIL_PREFERRED_NETWORK_TYPE_TO_GECKO[networkType]; + options.type = this.context.Buf.readInt32List()[0]; this.sendChromeMessage(options); }; RilObject.prototype[REQUEST_GET_NEIGHBORING_CELL_IDS] = function REQUEST_GET_NEIGHBORING_CELL_IDS(length, options) { if (options.rilRequestError) { options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[options.rilRequestError]; this.sendChromeMessage(options); return; } @@ -8514,17 +8525,17 @@ GsmPDUHelperObject.prototype = { } }; msg.body = null; msg.data = null; switch (msg.encoding) { case PDU_DCS_MSG_CODING_7BITS_ALPHABET: msg.body = this.readSeptetsToString.call(bufAdapter, - (length * 8 / 7), 0, + Math.floor(length * 8 / 7), 0, PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT); if (msg.hasLanguageIndicator) { msg.language = msg.body.substring(0, 2); msg.body = msg.body.substring(3); } break; @@ -8611,17 +8622,17 @@ GsmPDUHelperObject.prototype = { Buf.seekIncoming(-numOfPages * (CB_MSG_PAGE_INFO_SIZE + 1)); switch (msg.encoding) { case PDU_DCS_MSG_CODING_7BITS_ALPHABET: { let body; msg.body = ""; for (let i = 0; i < numOfPages; i++) { body = this.readSeptetsToString.call(bufAdapter, - (pageLengths[i] * 8 / 7), + Math.floor(pageLengths[i] * 8 / 7), 0, PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT); if (msg.hasLanguageIndicator) { if (!msg.language) { msg.language = body.substring(0, 2); } body = body.substring(3); @@ -8841,17 +8852,17 @@ GsmPDUHelperObject.prototype = { let shouldIncludeCountryInitials = !!(codingInfo & 0x08); let spareBits = codingInfo & 0x07; let resultString; switch (textEncoding) { case 0: // GSM Default alphabet. resultString = this.readSeptetsToString( - ((len - 1) * 8 - spareBits) / 7, 0, + Math.floor(((len - 1) * 8 - spareBits) / 7), 0, PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT); break; case 1: // UCS2 encoded. resultString = this.readUCS2String(len - 1); break; default: @@ -11256,17 +11267,18 @@ StkProactiveCmdHelperObject.prototype = let GsmPDUHelper = this.context.GsmPDUHelper; let text = { codingScheme: GsmPDUHelper.readHexOctet() }; length--; // -1 for the codingScheme. switch (text.codingScheme & 0x0c) { case STK_TEXT_CODING_GSM_7BIT_PACKED: - text.textString = GsmPDUHelper.readSeptetsToString(length * 8 / 7, 0, 0, 0); + text.textString = + GsmPDUHelper.readSeptetsToString(Math.floor(length * 8 / 7), 0, 0, 0); break; case STK_TEXT_CODING_GSM_8BIT: text.textString = this.context.ICCPDUHelper.read8BitUnpackedToString(length); break; case STK_TEXT_CODING_UCS2: text.textString = GsmPDUHelper.readUCS2String(length); break;
--- a/dom/tv/FakeTVService.cpp +++ b/dom/tv/FakeTVService.cpp @@ -1,28 +1,122 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/dom/TVServiceRunnables.h" +#include "mozilla/dom/TVTypes.h" #include "nsCOMPtr.h" #include "nsIMutableArray.h" +#include "nsITimer.h" #include "nsServiceManagerUtils.h" +#include "prtime.h" #include "FakeTVService.h" namespace mozilla { namespace dom { -NS_IMPL_ISUPPORTS(FakeTVService, nsITVService) +NS_IMPL_CYCLE_COLLECTION_CLASS(FakeTVService) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FakeTVService) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceListener) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTuners) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChannels) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrograms) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEITBroadcastedTimer) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScanCompleteTimer) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FakeTVService) + tmp->Shutdown(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mSourceListener) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mTuners) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mChannels) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrograms) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mEITBroadcastedTimer) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mScanCompleteTimer) +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(FakeTVService) +NS_IMPL_CYCLE_COLLECTING_RELEASE(FakeTVService) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FakeTVService) + NS_INTERFACE_MAP_ENTRY(nsITVService) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +FakeTVService::FakeTVService() +{ + Init(); +} + +FakeTVService::~FakeTVService() +{ + Shutdown(); +} + +void +FakeTVService::Init() +{ + const char* sourceTypes1[2] = {"dvb-t", "dvb-c"}; + nsCOMPtr<nsITVTunerData> tunerData1 = MockTuner(NS_LITERAL_STRING("1"), 2, sourceTypes1); + mTuners.AppendElement(tunerData1); + const char* sourceTypes2[1] = {"dvb-s"}; + nsCOMPtr<nsITVTunerData> tunerData2 = MockTuner(NS_LITERAL_STRING("2"), 1, sourceTypes2); + mTuners.AppendElement(tunerData2); + + nsCOMPtr<nsITVChannelData> channelData1 = + MockChannel(NS_LITERAL_STRING("networkId1"), NS_LITERAL_STRING("transportStreamId1"), + NS_LITERAL_STRING("serviceId1"), NS_LITERAL_STRING("tv"), + NS_LITERAL_STRING("1"), NS_LITERAL_STRING("name1"), true, true); + mChannels.AppendElement(channelData1); + nsCOMPtr<nsITVChannelData> channelData2 = + MockChannel(NS_LITERAL_STRING("networkId2"), NS_LITERAL_STRING("transportStreamId2"), + NS_LITERAL_STRING("serviceId2"), NS_LITERAL_STRING("radio"), + NS_LITERAL_STRING("2"), NS_LITERAL_STRING("name2"), true, true); + mChannels.AppendElement(channelData2); + + uint64_t now = PR_Now(); + const char* audioLanguages1[2] = {"eng", "jpn"}; + const char* subtitleLanguages1[2] = {"fre", "spa"}; + nsCOMPtr<nsITVProgramData> programData1 = + MockProgram(NS_LITERAL_STRING("eventId1"), NS_LITERAL_STRING("title1"), + now - 1, 3600000, + NS_LITERAL_STRING("description1"), NS_LITERAL_STRING("rating1"), + 2, audioLanguages1, 2, subtitleLanguages1); + mPrograms.AppendElement(programData1); + nsCOMPtr<nsITVProgramData> programData2 = + MockProgram(NS_LITERAL_STRING("eventId2"), NS_LITERAL_STRING("title2"), + now + 3600000 , 3600000, + NS_LITERAL_STRING(""), NS_LITERAL_STRING(""), + 0, nullptr, 0, nullptr); + mPrograms.AppendElement(programData2); +} + +void +FakeTVService::Shutdown() +{ + if (mEITBroadcastedTimer) { + mEITBroadcastedTimer->Cancel(); + } + if (mScanCompleteTimer) { + mScanCompleteTimer->Cancel(); + } +} /* virtual */ NS_IMETHODIMP FakeTVService::GetSourceListener(nsITVSourceListener** aSourceListener) { + if (!mSourceListener) { + *aSourceListener = nullptr; + return NS_OK; + } + *aSourceListener = mSourceListener; NS_ADDREF(*aSourceListener); return NS_OK; } /* virtual */ NS_IMETHODIMP FakeTVService::SetSourceListener(nsITVSourceListener* aSourceListener) { @@ -37,76 +131,210 @@ FakeTVService::GetTuners(nsITVServiceCal return NS_ERROR_INVALID_ARG; } nsCOMPtr<nsIMutableArray> tunerDataList = do_CreateInstance(NS_ARRAY_CONTRACTID); if (!tunerDataList) { return NS_ERROR_OUT_OF_MEMORY; } - // TODO Implement in follow-up patches. + for (uint32_t i = 0; i < mTuners.Length(); i++) { + tunerDataList->AppendElement(mTuners[i], false); + } nsCOMPtr<nsIRunnable> runnable = new TVServiceNotifyRunnable(aCallback, tunerDataList); return NS_DispatchToCurrentThread(runnable); } /* virtual */ NS_IMETHODIMP FakeTVService::SetSource(const nsAString& aTunerId, const nsAString& aSourceType, nsITVServiceCallback* aCallback) { if (!aCallback) { return NS_ERROR_INVALID_ARG; } - // TODO Implement in follow-up patches. + for (uint32_t i = 0; i < mTuners.Length(); i++) { + nsString tunerId; + mTuners[i]->GetId(tunerId); + if (aTunerId.Equals(tunerId)) { + uint32_t sourceTypeCount; + char** sourceTypes; + mTuners[i]->GetSupportedSourceTypes(&sourceTypeCount, &sourceTypes); + for (uint32_t j = 0; j < sourceTypeCount; j++) { + nsString sourceType; + sourceType.AssignASCII(sourceTypes[j]); + if (aSourceType.Equals(sourceType)) { + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(sourceTypeCount, sourceTypes); + nsCOMPtr<nsIRunnable> runnable = + new TVServiceNotifyRunnable(aCallback, nullptr); + return NS_DispatchToCurrentThread(runnable); + } + } + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(sourceTypeCount, sourceTypes); + } + } nsCOMPtr<nsIRunnable> runnable = - new TVServiceNotifyRunnable(aCallback, nullptr); + new TVServiceNotifyRunnable(aCallback, nullptr, nsITVServiceCallback::TV_ERROR_FAILURE); return NS_DispatchToCurrentThread(runnable); } +class EITBroadcastedCallback : public nsITimerCallback +{ +public: + NS_DECL_ISUPPORTS + + EITBroadcastedCallback(const nsAString& aTunerId, + const nsAString& aSourceType, + nsITVSourceListener* aSourceListener, + nsITVChannelData* aChannelData) + : mTunerId(aTunerId) + , mSourceType(aSourceType) + , mSourceListener(aSourceListener) + , mChannelData(aChannelData) + {} + + NS_IMETHODIMP + Notify(nsITimer* aTimer) + { + // Notify mock EIT broadcasting. + nsITVProgramData** programDataList = + static_cast<nsITVProgramData **>(NS_Alloc(1 * sizeof(nsITVProgramData*))); + programDataList[0] = new TVProgramData(); + programDataList[0]->SetEventId(NS_LITERAL_STRING("eventId")); + programDataList[0]->SetTitle(NS_LITERAL_STRING("title")); + programDataList[0]->SetStartTime(PR_Now() + 3600000); + programDataList[0]->SetDuration(3600000); + programDataList[0]->SetDescription(NS_LITERAL_STRING("description")); + programDataList[0]->SetRating(NS_LITERAL_STRING("rating")); + programDataList[0]->SetAudioLanguages(0, nullptr); + programDataList[0]->SetSubtitleLanguages(0, nullptr); + nsresult rv = mSourceListener->NotifyEITBroadcasted(mTunerId, mSourceType, + mChannelData, + programDataList, 1); + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(1, programDataList); + return rv; + } + +private: + ~EITBroadcastedCallback() {} + + nsString mTunerId; + nsString mSourceType; + nsCOMPtr<nsITVSourceListener> mSourceListener; + nsCOMPtr<nsITVChannelData> mChannelData; +}; + +NS_IMPL_ISUPPORTS(EITBroadcastedCallback, nsITimerCallback) + +class ScanCompleteCallback : public nsITimerCallback +{ +public: + NS_DECL_ISUPPORTS + + ScanCompleteCallback(const nsAString& aTunerId, + const nsAString& aSourceType, + nsITVSourceListener* aSourceListener) + : mTunerId(aTunerId) + , mSourceType(aSourceType) + , mSourceListener(aSourceListener) + {} + + NS_IMETHODIMP + Notify(nsITimer* aTimer) + { + return mSourceListener->NotifyChannelScanComplete(mTunerId, mSourceType); + } + +private: + ~ScanCompleteCallback() {} + + nsString mTunerId; + nsString mSourceType; + nsCOMPtr<nsITVSourceListener> mSourceListener; +}; + +NS_IMPL_ISUPPORTS(ScanCompleteCallback, nsITimerCallback) + /* virtual */ NS_IMETHODIMP FakeTVService::StartScanningChannels(const nsAString& aTunerId, const nsAString& aSourceType, nsITVServiceCallback* aCallback) { if (!aCallback) { return NS_ERROR_INVALID_ARG; } - // TODO Implement in follow-up patches. - nsCOMPtr<nsIRunnable> runnable = new TVServiceNotifyRunnable(aCallback, nullptr); - return NS_DispatchToCurrentThread(runnable); + nsresult rv = NS_DispatchToCurrentThread(runnable); + NS_ENSURE_SUCCESS(rv, rv); + + if (IsAllowed(aTunerId, aSourceType)) { + rv = mSourceListener->NotifyChannelScanned(aTunerId, aSourceType, mChannels[0]); + NS_ENSURE_SUCCESS(rv, rv); + + // Set a timer. |notifyEITBroadcasted| will be called after the timer + // fires (10ms). (The timer could be canceled if |StopScanningChannels| gets + // called before firing.) + mEITBroadcastedTimer = do_CreateInstance(NS_TIMER_CONTRACTID); + NS_ENSURE_TRUE(mEITBroadcastedTimer, NS_ERROR_OUT_OF_MEMORY); + nsRefPtr<EITBroadcastedCallback> eitBroadcastedCb = + new EITBroadcastedCallback(aTunerId, aSourceType, mSourceListener, mChannels[0]); + rv = mEITBroadcastedTimer->InitWithCallback(eitBroadcastedCb, 10, + nsITimer::TYPE_ONE_SHOT); + NS_ENSURE_SUCCESS(rv, rv); + + // Set a timer. |notifyChannelScanComplete| will be called after the timer + // fires (20ms). (The timer could be canceled if |StopScanningChannels| gets + // called before firing.) + mScanCompleteTimer = do_CreateInstance(NS_TIMER_CONTRACTID); + NS_ENSURE_TRUE(mScanCompleteTimer, NS_ERROR_OUT_OF_MEMORY); + nsRefPtr<ScanCompleteCallback> scanCompleteCb = + new ScanCompleteCallback(aTunerId, aSourceType, mSourceListener); + rv = mScanCompleteTimer->InitWithCallback(scanCompleteCb, 20, + nsITimer::TYPE_ONE_SHOT); + NS_ENSURE_SUCCESS(rv, rv); + } + + return NS_OK; } /* virtual */ NS_IMETHODIMP FakeTVService::StopScanningChannels(const nsAString& aTunerId, const nsAString& aSourceType, nsITVServiceCallback* aCallback) { if (!aCallback) { return NS_ERROR_INVALID_ARG; } - // TODO Implement in follow-up patches. + if (mEITBroadcastedTimer) { + mEITBroadcastedTimer->Cancel(); + mEITBroadcastedTimer = nullptr; + } + if (mScanCompleteTimer) { + mScanCompleteTimer->Cancel(); + mScanCompleteTimer = nullptr; + } + nsresult rv = mSourceListener->NotifyChannelScanStopped(aTunerId, aSourceType); + NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIRunnable> runnable = new TVServiceNotifyRunnable(aCallback, nullptr); return NS_DispatchToCurrentThread(runnable); } /* virtual */ NS_IMETHODIMP FakeTVService::ClearScannedChannelsCache() { - // TODO Implement in follow-up patches. - + // Fake service doesn't support channel cache, so there's nothing to do here. return NS_OK; } /* virtual */ NS_IMETHODIMP FakeTVService::SetChannel(const nsAString& aTunerId, const nsAString& aSourceType, const nsAString& aChannelNumber, nsITVServiceCallback* aCallback) @@ -115,20 +343,36 @@ FakeTVService::SetChannel(const nsAStrin return NS_ERROR_INVALID_ARG; } nsCOMPtr<nsIMutableArray> channelDataList = do_CreateInstance(NS_ARRAY_CONTRACTID); if (!channelDataList) { return NS_ERROR_OUT_OF_MEMORY; } - // TODO Implement in follow-up patches. + if (IsAllowed(aTunerId, aSourceType)) { + for (uint32_t i = 0; i < mChannels.Length(); i++) { + nsString channelNumber; + mChannels[i]->GetNumber(channelNumber); + if (aChannelNumber.Equals(channelNumber)) { + channelDataList->AppendElement(mChannels[i], false); + break; + } + } + } - nsCOMPtr<nsIRunnable> runnable = - new TVServiceNotifyRunnable(aCallback, channelDataList); + uint32_t length; + nsresult rv = channelDataList->GetLength(&length); + NS_ENSURE_SUCCESS(rv, rv); + + nsCOMPtr<nsIRunnable> runnable = new TVServiceNotifyRunnable( + aCallback, + (length == 1) ? channelDataList : nullptr, + (length == 1) ? nsITVServiceCallback::TV_ERROR_OK : nsITVServiceCallback::TV_ERROR_FAILURE + ); return NS_DispatchToCurrentThread(runnable); } /* virtual */ NS_IMETHODIMP FakeTVService::GetChannels(const nsAString& aTunerId, const nsAString& aSourceType, nsITVServiceCallback* aCallback) { @@ -136,17 +380,21 @@ FakeTVService::GetChannels(const nsAStri return NS_ERROR_INVALID_ARG; } nsCOMPtr<nsIMutableArray> channelDataList = do_CreateInstance(NS_ARRAY_CONTRACTID); if (!channelDataList) { return NS_ERROR_OUT_OF_MEMORY; } - // TODO Implement in follow-up patches. + if (IsAllowed(aTunerId, aSourceType)) { + for (uint32_t i = 0; i < mChannels.Length(); i++) { + channelDataList->AppendElement(mChannels[i], false); + } + } nsCOMPtr<nsIRunnable> runnable = new TVServiceNotifyRunnable(aCallback, channelDataList); return NS_DispatchToCurrentThread(runnable); } /* virtual */ NS_IMETHODIMP FakeTVService::GetPrograms(const nsAString& aTunerId, @@ -160,17 +408,24 @@ FakeTVService::GetPrograms(const nsAStri return NS_ERROR_INVALID_ARG; } nsCOMPtr<nsIMutableArray> programDataList = do_CreateInstance(NS_ARRAY_CONTRACTID); if (!programDataList) { return NS_ERROR_OUT_OF_MEMORY; } - // TODO Implement in follow-up patches. + // Only return mock programs for the first channel. + nsString channelNumber; + mChannels[0]->GetNumber(channelNumber); + if (IsAllowed(aTunerId, aSourceType) && aChannelNumber.Equals(channelNumber)) { + for (uint32_t i = 0; i < mPrograms.Length(); i++) { + programDataList->AppendElement(mPrograms[i], false); + } + } nsCOMPtr<nsIRunnable> runnable = new TVServiceNotifyRunnable(aCallback, programDataList); return NS_DispatchToCurrentThread(runnable); } /* virtual */ NS_IMETHODIMP FakeTVService::GetOverlayId(const nsAString& aTunerId, @@ -187,10 +442,91 @@ FakeTVService::GetOverlayId(const nsAStr // TODO Implement in follow-up patches. nsCOMPtr<nsIRunnable> runnable = new TVServiceNotifyRunnable(aCallback, overlayIds); return NS_DispatchToCurrentThread(runnable); } +bool +FakeTVService::IsAllowed(const nsAString& aTunerId, + const nsAString& aSourceType) +{ + // Only allow for the first source of the first tuner. + nsString tunerId; + mTuners[0]->GetId(tunerId); + if (!aTunerId.Equals(tunerId)) { + return false; + } + + uint32_t sourceTypeCount; + char** sourceTypes; + mTuners[0]->GetSupportedSourceTypes(&sourceTypeCount, &sourceTypes); + nsString sourceType; + sourceType.AssignASCII(sourceTypes[0]); + NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(sourceTypeCount, sourceTypes); + if (!aSourceType.Equals(sourceType)) { + return false; + } + + return true; +} + +already_AddRefed<nsITVTunerData> +FakeTVService::MockTuner(const nsAString& aId, + uint32_t aSupportedSourceTypeCount, + const char** aSupportedSourceTypes) +{ + nsCOMPtr<nsITVTunerData> tunerData = new TVTunerData(); + tunerData->SetId(aId); + tunerData->SetSupportedSourceTypes(aSupportedSourceTypeCount, aSupportedSourceTypes); + return tunerData.forget(); +} + +already_AddRefed<nsITVChannelData> +FakeTVService::MockChannel(const nsAString& aNetworkId, + const nsAString& aTransportStreamId, + const nsAString& aServiceId, + const nsAString& aType, + const nsAString& aNumber, + const nsAString& aName, + bool aIsEmergency, + bool aIsFree) +{ + nsCOMPtr<nsITVChannelData> channelData = new TVChannelData(); + channelData->SetNetworkId(aNetworkId); + channelData->SetTransportStreamId(aTransportStreamId); + channelData->SetServiceId(aServiceId); + channelData->SetType(aType); + channelData->SetNumber(aNumber); + channelData->SetName(aName); + channelData->SetIsEmergency(aIsEmergency); + channelData->SetIsFree(aIsFree); + return channelData.forget(); +} + +already_AddRefed<nsITVProgramData> +FakeTVService::MockProgram(const nsAString& aEventId, + const nsAString& aTitle, + uint64_t aStartTime, + uint64_t aDuration, + const nsAString& aDescription, + const nsAString& aRating, + uint32_t aAudioLanguageCount, + const char** aAudioLanguages, + uint32_t aSubtitleLanguageCount, + const char** aSubtitleLanguages) +{ + nsCOMPtr<nsITVProgramData> programData = new TVProgramData(); + programData->SetEventId(aEventId); + programData->SetTitle(aTitle); + programData->SetStartTime(aStartTime); + programData->SetDuration(aDuration); + programData->SetDescription(aDescription); + programData->SetRating(aRating); + programData->SetAudioLanguages(aAudioLanguageCount, aAudioLanguages); + programData->SetSubtitleLanguages(aSubtitleLanguageCount, aSubtitleLanguages); + return programData.forget(); +} + } // namespace dom } // namespace mozilla
--- a/dom/tv/FakeTVService.h +++ b/dom/tv/FakeTVService.h @@ -3,38 +3,82 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_FakeTVService_h #define mozilla_dom_FakeTVService_h #include "nsCOMPtr.h" +#include "nsCycleCollectionParticipant.h" #include "nsITVService.h" +#include "nsTArray.h" #define FAKE_TV_SERVICE_CONTRACTID \ "@mozilla.org/tv/faketvservice;1" #define FAKE_TV_SERVICE_CID \ { 0x60fb3c53, 0x017f, 0x4340, { 0x91, 0x1b, 0xd5, 0x5c, 0x31, 0x28, 0x88, 0xb6 } } +class nsITimer; +class nsITVTunerData; +class nsITVChannelData; +class nsITVProgramData; + namespace mozilla { namespace dom { class FakeTVService MOZ_FINAL : public nsITVService { public: - NS_DECL_ISUPPORTS + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(FakeTVService) NS_DECL_NSITVSERVICE - FakeTVService() {} - - // TODO More members might be added in follow-up patches to help testing. + FakeTVService(); private: - ~FakeTVService() {} + ~FakeTVService(); + + void Init(); + + void Shutdown(); + + bool IsAllowed(const nsAString& aTunerId, + const nsAString& aSourceType); + + already_AddRefed<nsITVTunerData> MockTuner(const nsAString& aId, + uint32_t aSupportedSourceTypeCount, + const char** aSupportedSourceTypes); + + already_AddRefed<nsITVChannelData> MockChannel(const nsAString& aNetworkId, + const nsAString& aTransportStreamId, + const nsAString& aServiceId, + const nsAString& aType, + const nsAString& aNumber, + const nsAString& aName, + bool aIsEmergency, + bool aIsFree); + + already_AddRefed<nsITVProgramData> MockProgram(const nsAString& aEventId, + const nsAString& aTitle, + uint64_t aStartTime, + uint64_t aDuration, + const nsAString& aDescription, + const nsAString& aRating, + uint32_t aAudioLanguageCount, + const char** aAudioLanguages, + uint32_t aSubtitleLanguageCount, + const char** aSubtitleLanguages); nsCOMPtr<nsITVSourceListener> mSourceListener; + + // The real implementation may want to use more efficient data structures. + nsTArray<nsCOMPtr<nsITVTunerData>> mTuners; + nsTArray<nsCOMPtr<nsITVChannelData>> mChannels; + nsTArray<nsCOMPtr<nsITVProgramData>> mPrograms; + nsCOMPtr<nsITimer> mEITBroadcastedTimer; + nsCOMPtr<nsITimer> mScanCompleteTimer; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_FakeTVService_h
--- a/dom/tv/TVListeners.cpp +++ b/dom/tv/TVListeners.cpp @@ -7,49 +7,40 @@ #include "mozilla/dom/TVSource.h" #include "mozilla/dom/TVTuner.h" #include "mozilla/dom/TVUtils.h" #include "TVListeners.h" namespace mozilla { namespace dom { -NS_IMPL_ISUPPORTS(TVSourceListener, nsITVSourceListener) +NS_IMPL_CYCLE_COLLECTION(TVSourceListener, mSources) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(TVSourceListener) +NS_IMPL_CYCLE_COLLECTING_RELEASE(TVSourceListener) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(TVSourceListener) + NS_INTERFACE_MAP_ENTRY(nsITVSourceListener) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END void TVSourceListener::RegisterSource(TVSource* aSource) { - nsString tunerId; - nsRefPtr<TVTuner> tuner = aSource->Tuner(); - tuner->GetId(tunerId); - - nsRefPtrHashtable<nsStringHashKey, TVSource>* tunerSources = nullptr; - if (!mSources.Get(tunerId, &tunerSources)) { - tunerSources = new nsRefPtrHashtable<nsStringHashKey, TVSource>(); - mSources.Put(tunerId, tunerSources); - } - - nsString sourceType = ToTVSourceTypeStr(aSource->Type()); - tunerSources->Put(sourceType, aSource); + mSources.AppendElement(aSource); } void TVSourceListener::UnregisterSource(TVSource* aSource) { - nsString tunerId; - nsRefPtr<TVTuner> tuner = aSource->Tuner(); - tuner->GetId(tunerId); - - nsRefPtrHashtable<nsStringHashKey, TVSource>* tunerSources = nullptr; - if (!mSources.Get(tunerId, &tunerSources)) { - return; + for (uint32_t i = 0; i < mSources.Length(); i++) { + if (mSources[i] == aSource) { + mSources.RemoveElementsAt(i, 1); + } } - - nsString sourceType = ToTVSourceTypeStr(aSource->Type()); - tunerSources->Remove(sourceType); } /* virtual */ NS_IMETHODIMP TVSourceListener::NotifyChannelScanned(const nsAString& aTunerId, const nsAString& aSourceType, nsITVChannelData* aChannelData) { nsRefPtr<TVSource> source = GetSource(aTunerId, aSourceType); @@ -86,20 +77,26 @@ TVSourceListener::NotifyEITBroadcasted(c source->NotifyEITBroadcasted(aChannelData, aProgramDataList, aCount); return NS_OK; } already_AddRefed<TVSource> TVSourceListener::GetSource(const nsAString& aTunerId, const nsAString& aSourceType) { - nsRefPtrHashtable<nsStringHashKey, TVSource>* tunerSources = nullptr; - if (!mSources.Get(aTunerId, &tunerSources)) { - return nullptr; + for (uint32_t i = 0; i < mSources.Length(); i++) { + nsString tunerId; + nsRefPtr<TVTuner> tuner = mSources[i]->Tuner(); + tuner->GetId(tunerId); + + nsString sourceType = ToTVSourceTypeStr(mSources[i]->Type()); + + if (aTunerId.Equals(tunerId) && aSourceType.Equals(sourceType)) { + nsRefPtr<TVSource> source = mSources[i]; + return source.forget(); + } } - nsRefPtr<TVSource> source; - tunerSources->Get(aSourceType, getter_AddRefs(source)); - return source.forget(); + return nullptr; } } // namespace dom } // namespace mozilla
--- a/dom/tv/TVListeners.h +++ b/dom/tv/TVListeners.h @@ -2,42 +2,40 @@ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_dom_TVListeners_h #define mozilla_dom_TVListeners_h -#include "nsClassHashtable.h" +#include "mozilla/dom/TVSource.h" +#include "nsCycleCollectionParticipant.h" #include "nsITVService.h" -#include "nsRefPtrHashtable.h" +#include "nsTArray.h" namespace mozilla { namespace dom { -class TVSource; - class TVSourceListener : public nsITVSourceListener { public: - NS_DECL_ISUPPORTS + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(TVSourceListener) NS_DECL_NSITVSOURCELISTENER void RegisterSource(TVSource* aSource); void UnregisterSource(TVSource* aSource); private: ~TVSourceListener() {} already_AddRefed<TVSource> GetSource(const nsAString& aTunerId, const nsAString& aSourceType); - // The tuner ID acts as the key of the outer table; whereas the source type is - // the key for the inner one. - nsClassHashtable<nsStringHashKey, nsRefPtrHashtable<nsStringHashKey, TVSource>> mSources; + nsTArray<nsRefPtr<TVSource>> mSources; }; } // namespace dom } // namespace mozilla #endif // mozilla_dom_TVListeners_h
--- a/dom/tv/TVTypes.cpp +++ b/dom/tv/TVTypes.cpp @@ -12,16 +12,22 @@ namespace mozilla { namespace dom { /* * Implementation of TVTunerData */ NS_IMPL_ISUPPORTS(TVTunerData, nsITVTunerData) +TVTunerData::TVTunerData() + : mSupportedSourceTypes(nullptr) + , mCount(0) +{ +} + TVTunerData::~TVTunerData() { if (mSupportedSourceTypes) { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mCount, mSupportedSourceTypes); } } /* virtual */ NS_IMETHODIMP @@ -92,16 +98,26 @@ TVTunerData::SetSupportedSourceTypes(uin /* * Implementation of TVChannelData */ NS_IMPL_ISUPPORTS(TVChannelData, nsITVChannelData) +TVChannelData::TVChannelData() + : mIsEmergency(false) + , mIsFree(false) +{ +} + +TVChannelData::~TVChannelData() +{ +} + /* virtual */ NS_IMETHODIMP TVChannelData::GetNetworkId(nsAString& aNetworkId) { aNetworkId = mNetworkId; return NS_OK; } /* virtual */ NS_IMETHODIMP @@ -239,16 +255,24 @@ TVChannelData::SetIsFree(bool aIsFree) /* * Implementation of TVProgramData */ NS_IMPL_ISUPPORTS(TVProgramData, nsITVProgramData) +TVProgramData::TVProgramData() + : mAudioLanguages(nullptr) + , mAudioLanguageCount(0) + , mSubtitleLanguages(nullptr) + , mSubtitleLanguageCount(0) +{ +} + TVProgramData::~TVProgramData() { if (mAudioLanguages) { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mAudioLanguageCount, mAudioLanguages); } if (mSubtitleLanguages) { NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(mSubtitleLanguageCount, mSubtitleLanguages); }
--- a/dom/tv/TVTypes.h +++ b/dom/tv/TVTypes.h @@ -13,32 +13,36 @@ namespace mozilla { namespace dom { class TVTunerData MOZ_FINAL : public nsITVTunerData { public: NS_DECL_ISUPPORTS NS_DECL_NSITVTUNERDATA + TVTunerData(); + private: ~TVTunerData(); nsString mId; char** mSupportedSourceTypes; uint32_t mCount; }; class TVChannelData MOZ_FINAL : public nsITVChannelData { public: NS_DECL_ISUPPORTS NS_DECL_NSITVCHANNELDATA + TVChannelData(); + private: - ~TVChannelData() {} + ~TVChannelData(); nsString mNetworkId; nsString mTransportStreamId; nsString mServiceId; nsString mType; nsString mNumber; nsString mName; bool mIsEmergency; @@ -46,16 +50,18 @@ private: }; class TVProgramData MOZ_FINAL : public nsITVProgramData { public: NS_DECL_ISUPPORTS NS_DECL_NSITVPROGRAMDATA + TVProgramData(); + private: ~TVProgramData(); nsString mEventId; nsString mTitle; uint64_t mStartTime; uint64_t mDuration; nsString mDescription;
--- a/dom/tv/moz.build +++ b/dom/tv/moz.build @@ -1,16 +1,14 @@ # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- # vim: set filetype=python: # 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/. -TEST_DIRS += ['test'] - EXPORTS.mozilla.dom += [ 'FakeTVService.h', 'TVChannel.h', 'TVListeners.h', 'TVManager.h', 'TVProgram.h', 'TVServiceCallbacks.h', 'TVServiceFactory.h', @@ -35,11 +33,15 @@ UNIFIED_SOURCES += [ ] XPIDL_SOURCES += [ 'nsITVService.idl', ] XPIDL_MODULE = 'dom_tv' +MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini'] + +XPCSHELL_TESTS_MANIFESTS += ['test/xpcshell/xpcshell.ini'] + include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul'
rename from dom/tv/test/file_app.sjs rename to dom/tv/test/mochitest/file_app.sjs --- a/dom/tv/test/file_app.sjs +++ b/dom/tv/test/mochitest/file_app.sjs @@ -1,9 +1,9 @@ -var gBasePath = "tests/dom/tv/test/"; +var gBasePath = "tests/dom/tv/test/mochitest/"; function handleRequest(request, response) { var query = getQuery(request); var testToken = ''; if ('testToken' in query) { testToken = query.testToken; }
rename from dom/tv/test/file_app.template.webapp rename to dom/tv/test/mochitest/file_app.template.webapp --- a/dom/tv/test/file_app.template.webapp +++ b/dom/tv/test/mochitest/file_app.template.webapp @@ -1,6 +1,6 @@ { "name": "TV Test App (hosted)", "description": "Hosted TV test app used for mochitest.", - "launch_path": "/tests/dom/tv/test/TESTTOKEN", + "launch_path": "/tests/dom/tv/test/mochitest/TESTTOKEN", "icons": { "128": "default_icon" } }
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_get_channels.html @@ -0,0 +1,60 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test GetChannels for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + + aSources[0].getChannels().then( + function(aChannels) { + ok(aChannels.length > 0, "Got at least 1 channel."); + + for (var i = 0; i < aChannels.length; i++) { + var channel = aChannels[i]; + ok(channel instanceof TVChannel, "Channel " + i + " should be in right type.") + ok('source' in channel, "Channel " + i + " should have a source."); + ok('networkId' in channel, "Channel " + i + " should have a network ID."); + ok('transportStreamId' in channel, "Channel " + i + " should have a transport stream ID."); + ok('serviceId' in channel, "Channel " + i + " should have a service ID."); + ok('type' in channel, "Channel " + i + " should have a type."); + ok('name' in channel, "Channel " + i + " should have a name."); + ok('number' in channel, "Channel " + i + " should have a number."); + } + + finish(); + }, + function(aError) { + ok(false, "Error occurred when getting channels: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_get_channels_during_scanning.html @@ -0,0 +1,58 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test an error case for GetChannels during scanning for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + var source = aSources[0]; + + // TODO Bug 1088818 - Modify the behavior of channel scanning. + source.startScanning({}).then( + function() { + source.getChannels().then( + function() { + ok(false, "Getting channels during scanning should get error."); + finish(); + }, + function(aError) { + is(aError.name, "InvalidStateError", + "InvalidStateError should be expected."); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when starting scanning: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_get_current_program.html @@ -0,0 +1,68 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test GetCurrentProgram for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + + aSources[0].getChannels().then( + function(aChannels) { + ok(aChannels.length > 0, "Got at least 1 channel."); + + aChannels[0].getCurrentProgram().then( + function(aCurrentProgram) { + ok(aCurrentProgram, "Got the current program."); + ok(aCurrentProgram instanceof TVProgram, "The current program should be in the right type.") + ok('channel' in aCurrentProgram, "The current program should have a channel."); + ok('eventId' in aCurrentProgram, "The current program should have an event ID."); + ok('title' in aCurrentProgram, "The current program should have a title."); + ok('startTime' in aCurrentProgram, "The current program should have start time."); + ok('duration' in aCurrentProgram, "The current program should have duration."); + ok(aCurrentProgram.getAudioLanguages().length >= 0, + "The current program may have audio language(s)."); + ok(aCurrentProgram.getSubtitleLanguages().length >= 0, + "The current program may have subtitle language(s)."); + + finish(); + }, + function(aError) { + ok(false, "Error occurred when getting programs: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting channels: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_get_programs.html @@ -0,0 +1,71 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test GetPrograms for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + + aSources[0].getChannels().then( + function(aChannels) { + ok(aChannels.length > 0, "Got at least 1 channel."); + + aChannels[0].getPrograms().then( + function(aPrograms) { + ok(aPrograms.length > 0, "Got at least 1 program."); + + for (var i = 0; i < aPrograms.length; i++) { + var program = aPrograms[i]; + ok(program instanceof TVProgram, "Program " + i + " should be in the right type.") + ok('channel' in program, "Program " + i + " should have a channel."); + ok('eventId' in program, "Program " + i + " should have an event ID."); + ok('title' in program, "Program " + i + " should have a title."); + ok('startTime' in program, "Program " + i + " should have start time."); + ok('duration' in program, "Program " + i + " should have duration."); + ok(program.getAudioLanguages().length >= 0, + "Program " + i + " may have audio language(s)."); + ok(program.getSubtitleLanguages().length >= 0, + "Program " + i + " may have subtitle language(s)."); + } + + finish(); + }, + function(aError) { + ok(false, "Error occurred when getting programs: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting channels: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_get_sources.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test GetSources for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + for (var i = 0; i < aSources.length; i++) { + var source = aSources[i]; + ok(source instanceof TVSource, "Source " + i + " should be in the right type."); + ok('tuner' in source, "Source " + i + " should have a tuner."); + ok('type' in source, "Source " + i + " should have a type."); + ok('isScanning' in source, "Source " + i + " should have isScanning."); + ok(!source.isScanning, + "Source " + i + " should not be scanning by default."); + ok(!source.currentChannel, + "Source " + i + " should have no current channel by default."); + } + + finish(); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_get_tuners.html @@ -0,0 +1,38 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test GetTuners for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + for (var i = 0; i < aTuners.length; i++) { + var tuner = aTuners[i]; + ok(tuner instanceof TVTuner, "Tuner " + i + " should be in the right type."); + ok('id' in tuner, "Tuner " + i + " should have an ID."); + ok(tuner.getSupportedSourceTypes().length > 0, + "Tuner " + i + " should have supported source type(s)."); + ok(!tuner.currentSource, + "Tuner " + i + " should have no current source by default."); + ok(!tuner.stream, "Tuner " + i + " should have no stream by default."); + } + + finish(); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
rename from dom/tv/test/file_tv_non_permitted_app.html rename to dom/tv/test/mochitest/file_tv_non_permitted_app.html --- a/dom/tv/test/file_tv_non_permitted_app.html +++ b/dom/tv/test/mochitest/file_tv_non_permitted_app.html @@ -1,24 +1,17 @@ <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Test the availability of TV Manager API for non-permitted Apps</title> </head> <body> <div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> <script type="application/javascript;version=1.7"> - function ok(a, msg) { - alert((a ? 'OK' : 'KO')+ ' ' + msg) - } - - function finish() { - alert('DONE'); - } - ok(!('tv' in navigator), "navigator.tv should not exist for non-permitted app."); finish(); </script> </body> </html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_permitted_app.html @@ -0,0 +1,16 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test the availability of TV Manager API for permitted Apps</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist for permitted app."); + finish(); + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_scan_channels_completed.html @@ -0,0 +1,68 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test channel scanning complete for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + var isScannedEventFired = false; + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + var source = aSources[0]; + + source.oneitbroadcasted = function(aEvent) { + info("Received EIT broadcasted event."); + + var programs = aEvent.programs; + for (var i = 0; i < programs.length; i++) { + ok(programs[i], "Program " + i + " should be set.") + } + }; + + source.onscanningstatechanged = function(aEvent) { + if (aEvent.state === 'scanned') { + isScannedEventFired = true; + info("Received channel scanned event."); + ok(aEvent.channel, "Scanned channel should be set."); + } else if (aEvent.state === 'completed') { + ok(isScannedEventFired, "Received channel scanning completed event after channel scanned event."); + finish(); + } + }; + + // TODO Bug 1088818 - Modify the behavior of channel scanning. + source.startScanning({}).then( + function() {}, + function(aError) { + ok(false, "Error occurred when starting scanning: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_scan_channels_stopped.html @@ -0,0 +1,66 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test StartScanning and StopScanning for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + var isClearedEventFired = false; + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + var source = aSources[0]; + + source.onscanningstatechanged = function(aEvent) { + if (aEvent.state === 'cleared') { + isClearedEventFired = true; + info("Received channel cache cleared event."); + } else if (aEvent.state === 'stopped') { + ok(isClearedEventFired, "Received channel scanning stopped event after cleared event."); + finish(); + } + }; + + // TODO Bug 1088818 - Modify the behavior of channel scanning. + source.startScanning({ isRescanned: true }).then( + function() { + source.stopScanning().then( + function() {}, + function(aError) { + ok(false, "Error occurred when stopping scanning: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when starting scanning: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_set_current_channel.html @@ -0,0 +1,70 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test SetCurrentChannel for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + var tuner = aTuners[0]; + var selectedSourceType = tuner.getSupportedSourceTypes()[0]; + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + var source = aSources[0]; + + source.getChannels().then( + function(aChannels) { + ok(aChannels.length > 0, "Got at least 1 channel."); + var selectedChannelNumber = aChannels[0].number; + + source.oncurrentchannelchanged = function(aEvent) { + ok(aEvent instanceof TVCurrentChannelChangedEvent, + "The event is in the right type"); + ok(aEvent.channel instanceof TVChannel, + "The channel is in the right type."); + is(aEvent.channel, source.currentChannel, + "The current channel is set."); + is(source.currentChannel.number, selectedChannelNumber, + "The current channel number is correct."); + finish(); + }; + + source.setCurrentChannel(selectedChannelNumber).then( + function() {}, + function(aError) { + ok(false, "Error occurred when setting current channel: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting channels: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_set_current_channel_during_scanning.html @@ -0,0 +1,58 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test an error case for SetCurrentChannel during scanning for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners){ + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + var source = aSources[0]; + + // TODO Bug 1088818 - Modify the behavior of channel scanning. + source.startScanning({}).then( + function() { + source.setCurrentChannel("1").then( + function() { + ok(false, "Setting current channel during scanning should get error."); + finish(); + }, + function(aError) { + is(aError.name, "InvalidStateError", + "InvalidStateError should be expected."); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when starting scanning: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_set_current_source.html @@ -0,0 +1,48 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test SetCurrentSource for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + var tuner = aTuners[0]; + var selectedSourceType = tuner.getSupportedSourceTypes()[0]; + + tuner.oncurrentsourcechanged = function(aEvent) { + ok(aEvent instanceof TVCurrentSourceChangedEvent, + "The event is in the right type"); + ok(aEvent.source instanceof TVSource, + "The source is in the right type."); + is(aEvent.source, tuner.currentSource, + "The current source is set."); + is(tuner.currentSource.type, selectedSourceType, + "The current source type is correct."); + finish(); + }; + + tuner.setCurrentSource(selectedSourceType).then( + function() {}, + function(aError) { + ok(false, "Error occurred when setting current source: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_set_invalid_current_channel.html @@ -0,0 +1,49 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test an error case for SetCurrentChannel for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + var tuner = aTuners[0]; + var selectedSourceType = tuner.getSupportedSourceTypes()[0]; + + aTuners[0].getSources().then( + function(aSources) { + ok(aSources.length > 0, "Got at least 1 source."); + + aSources[0].setCurrentChannel("NonExistentChannelNumber").then( + function() { + ok(false, "Setting an invalid current channel should get error."); + finish(); + }, + function(aError) { + is(aError.name, "AbortError", "AbortError should be expected."); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting sources: " + aError); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/file_tv_set_invalid_current_source.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test an error case for SetCurrentSource for TV API</title> +</head> +<body> +<div id="content"></div> + <script type="application/javascript" src="./test_helpers.js"></script> + <script type="application/javascript;version=1.7"> + + ok('tv' in navigator, "navigator.tv should exist."); + + navigator.tv.getTuners().then( + function(aTuners) { + ok(aTuners.length > 0, "Got at least 1 tuner."); + + aTuners[0].setCurrentSource("InvalidSourceType").then( + function() { + ok(false, "Setting an invalid current source should get error."); + finish(); + }, + function(aError) { + is(aError.name, "TypeError", "TypeError should be expected."); + finish(); + } + ); + }, + function(aError) { + ok(false, "Error occurred when getting tuners: " + aError); + finish(); + } + ); + </script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/head.js @@ -0,0 +1,97 @@ +"use strict"; + +var gAppsService = SpecialPowers.Cc["@mozilla.org/AppsService;1"] + .getService(SpecialPowers.Ci.nsIAppsService); + + +var gApp; + +function cbError(e) { + ok(false, "Error callback invoked: " + this.error.name); + SimpleTest.finish(); +} + +function installApp(aTestToken, aTemplate) { + var hostedManifestURL = window.location.origin + + '/tests/dom/tv/test/mochitest/file_app.sjs?testToken=' + + aTestToken + '&template=' + aTemplate; + var request = navigator.mozApps.install(hostedManifestURL); + request.onerror = cbError; + request.onsuccess = function() { + gApp = request.result; + + var appId = gAppsService.getAppLocalIdByManifestURL(gApp.manifestURL); + SpecialPowers.addPermission("tv", true, { url: gApp.origin, + appId: appId, + isInBrowserElement: false }); + + runTest(); + } +} + +function uninstallApp() { + var request = navigator.mozApps.mgmt.uninstall(gApp); + request.onerror = cbError; + request.onsuccess = function() { + // All done. + info("All done"); + runTest(); + } +} + +function testApp() { + var ifr = document.createElement('iframe'); + ifr.setAttribute('mozbrowser', 'true'); + ifr.setAttribute('mozapp', gApp.manifestURL); + ifr.setAttribute('src', gApp.manifest.launch_path); + var domParent = document.getElementById('content'); + + // Set us up to listen for messages from the app. + var listener = function(e) { + var message = e.detail.message; + if (/^OK/.exec(message)) { + ok(true, "Message from app: " + message); + } else if (/KO/.exec(message)) { + ok(false, "Message from app: " + message); + } else if (/^INFO/.exec(message)) { + info("Message from app: " + message); + } else if (/DONE/.exec(message)) { + ok(true, "Messaging from app complete"); + ifr.removeEventListener('mozbrowsershowmodalprompt', listener); + domParent.removeChild(ifr); + runTest(); + } + } + + // This event is triggered when the app calls "alert". + ifr.addEventListener('mozbrowsershowmodalprompt', listener, false); + domParent.appendChild(ifr); +} + +function runTest() { + if (!tests.length) { + SimpleTest.finish(); + return; + } + + var test = tests.shift(); + test(); +} + +function setupPrefsAndPermissions() { + SpecialPowers.pushPrefEnv({"set": [["dom.tv.enabled", true], + ["dom.testing.tv_enabled_for_hosted_apps", true]]}, function() { + SpecialPowers.pushPermissions( + [{ "type": "browser", "allow": true, "context": document }, + { "type": "embed-apps", "allow": true, "context": document }, + { "type": "webapps-manage", "allow": true, "context": document }], + function() { + SpecialPowers.setAllAppsLaunchable(true); + SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true); + // No confirmation needed when an app is installed and uninstalled. + SpecialPowers.autoConfirmAppInstall(() => { + SpecialPowers.autoConfirmAppUninstall(runTest); + }); + }); + }); +}
rename from dom/tv/test/mochitest.ini rename to dom/tv/test/mochitest/mochitest.ini --- a/dom/tv/test/mochitest.ini +++ b/dom/tv/test/mochitest/mochitest.ini @@ -1,7 +1,37 @@ [DEFAULT] support-files = file_app.sjs file_app.template.webapp file_tv_non_permitted_app.html + file_tv_permitted_app.html + file_tv_get_tuners.html + file_tv_get_sources.html + file_tv_get_channels.html + file_tv_get_channels_during_scanning.html + file_tv_get_programs.html + file_tv_get_current_program.html + file_tv_set_current_source.html + file_tv_set_invalid_current_source.html + file_tv_set_current_channel.html + file_tv_set_current_channel_during_scanning.html + file_tv_set_invalid_current_channel.html + file_tv_scan_channels_stopped.html + file_tv_scan_channels_completed.html + head.js + test_helpers.js [test_tv_non_permitted_app.html] +[test_tv_permitted_app.html] +[test_tv_get_tuners.html] +[test_tv_get_sources.html] +[test_tv_get_channels.html] +[test_tv_get_channels_during_scanning.html] +[test_tv_get_programs.html] +[test_tv_get_current_program.html] +[test_tv_set_current_source.html] +[test_tv_set_invalid_current_source.html] +[test_tv_set_current_channel.html] +[test_tv_set_current_channel_during_scanning.html] +[test_tv_set_invalid_current_channel.html] +[test_tv_scan_channels_stopped.html] +[test_tv_scan_channels_completed.html]
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_helpers.js @@ -0,0 +1,17 @@ +"use strict"; + +function is(a, b, msg) { + alert((a === b ? 'OK' : 'KO') + ' ' + msg); +} + +function ok(a, msg) { + alert((a ? 'OK' : 'KO')+ ' ' + msg); +} + +function info(msg) { + alert('INFO ' + msg); +} + +function finish() { + alert('DONE'); +}
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_get_channels.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test GetChannels for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_get_channels.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_get_channels_during_scanning.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test an error case for GetChannels during scanning for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_get_channels_during_scanning.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_get_current_program.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test GetCurrentProgram for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_get_current_program.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_get_programs.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test GetPrograms for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_get_programs.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_get_sources.html @@ -0,0 +1,37 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test GetSources for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +"use strict"; + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_get_sources.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_get_tuners.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test GetTuners for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_get_tuners.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
rename from dom/tv/test/test_tv_non_permitted_app.html rename to dom/tv/test/mochitest/test_tv_non_permitted_app.html --- a/dom/tv/test/test_tv_non_permitted_app.html +++ b/dom/tv/test/mochitest/test_tv_non_permitted_app.html @@ -4,109 +4,46 @@ <title>Test Non-Permitted Application for TV API</title> <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> </head> <body> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"> +<script type="application/javascript" src="./head.js"></script> <script type="application/javascript"> -"use strict"; - -var gHostedManifestURL = 'http://test/tests/dom/tv/test/file_app.sjs?testToken=file_tv_non_permitted_app.html&template=file_app.template.webapp'; -var gApp; - -function cbError(e) { - ok(false, "Error callback invoked: " + this.error.name); - SimpleTest.finish(); -} - -function installApp() { - var request = navigator.mozApps.install(gHostedManifestURL); - request.onerror = cbError; - request.onsuccess = function() { - gApp = request.result; - runTest(); - } -} - -function uninstallApp() { - var request = navigator.mozApps.mgmt.uninstall(gApp); - request.onerror = cbError; - request.onsuccess = function() { - // All done. - info("All done"); - runTest(); - } -} +var tests = [ + function() { + SpecialPowers.pushPrefEnv({"set": [["dom.tv.enabled", true]]}, function() { + SpecialPowers.pushPermissions( + [{ "type": "browser", "allow": true, "context": document }, + { "type": "embed-apps", "allow": true, "context": document }, + { "type": "webapps-manage", "allow": true, "context": document }], + function() { + SpecialPowers.setAllAppsLaunchable(true); + SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true); + // No confirmation needed when an app is installed and uninstalled. + SpecialPowers.autoConfirmAppInstall(() => { + SpecialPowers.autoConfirmAppUninstall(runTest); + }); + }); + }); + }, -function testApp() { - var ifr = document.createElement('iframe'); - ifr.setAttribute('mozbrowser', 'true'); - ifr.setAttribute('mozapp', gApp.manifestURL); - ifr.setAttribute('src', gApp.manifest.launch_path); - var domParent = document.getElementById('content'); - - // Set us up to listen for messages from the app. - var listener = function(e) { - var message = e.detail.message; - if (/^OK/.exec(message)) { - ok(true, "Message from app: " + message); - } else if (/KO/.exec(message)) { - ok(false, "Message from app: " + message); - } else if (/DONE/.exec(message)) { - ok(true, "Messaging from app complete"); - ifr.removeEventListener('mozbrowsershowmodalprompt', listener); - domParent.removeChild(ifr); - runTest(); - } - } - - // This event is triggered when the app calls "alert". - ifr.addEventListener('mozbrowsershowmodalprompt', listener, false); - domParent.appendChild(ifr); -} - -var tests = [ // Installing the app - installApp, + installApp.bind(this, "file_tv_non_permitted_app.html", "file_app.template.webapp"), // Run tests in app testApp, // Uninstall the app uninstallApp ]; -function runTest() { - if (!tests.length) { - SimpleTest.finish(); - return; - } - - var test = tests.shift(); - test(); -} - SimpleTest.waitForExplicitFinish(); - -SpecialPowers.pushPrefEnv({"set": [["dom.tv.enabled", true]]}, function() { - SpecialPowers.pushPermissions( - [{ "type": "tv", "allow": true, "context": document }, - { "type": "browser", "allow": true, "context": document }, - { "type": "embed-apps", "allow": true, "context": document }, - { "type": "webapps-manage", "allow": true, "context": document }], - function(){ - SpecialPowers.setAllAppsLaunchable(true); - SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true); - // No confirmation needed when an app is installed - SpecialPowers.autoConfirmAppInstall(() => { - SpecialPowers.autoConfirmAppUninstall(runTest); - }); - }); -}); +runTest(); </script> </pre> </body> </html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_permitted_app.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test Permitted Application for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_permitted_app.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_scan_channels_completed.html @@ -0,0 +1,36 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test channel scanning complete for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_scan_channels_completed.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.expectAssertions(0, 2); +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_scan_channels_stopped.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test StartScanning and StopScanning for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_scan_channels_stopped.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_set_current_channel.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test SetCurrentChannel for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_set_current_channel.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_set_current_channel_during_scanning.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test an error case for SetCurrentChannel during scanning for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_set_current_channel_during_scanning.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_set_current_source.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test SetCurrentSource for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_set_current_source.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_set_invalid_current_channel.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test an error case for SetCurrentChannel for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_set_invalid_current_channel.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/tv/test/mochitest/test_tv_set_invalid_current_source.html @@ -0,0 +1,35 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Test an error case for SetCurrentSource for TV API</title> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> +</head> +<body> +<p id="display"></p> +<div id="content" style="display: none"></div> +<pre id="test"> +<script type="application/javascript" src="./head.js"></script> +<script type="application/javascript"> + +var tests = [ + // Setup preferences and permissions + setupPrefsAndPermissions, + + // Installing the app + installApp.bind(this, "file_tv_set_invalid_current_source.html", "file_app.template.webapp"), + + // Run tests in app + testApp, + + // Uninstall the app + uninstallApp +]; + +SimpleTest.waitForExplicitFinish(); +runTest(); + +</script> +</pre> +</body> +</html>
deleted file mode 100644 --- a/dom/tv/test/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# 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/. - -MOCHITEST_MANIFESTS += ['mochitest.ini']
new file mode 100644 --- /dev/null +++ b/dom/tv/test/xpcshell/test_tv_channel_data.js @@ -0,0 +1,169 @@ +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +function run_test() { + run_next_test(); +} + +add_test(function test_valid_network_id() { + var networkId = "networkId"; + + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + data.networkId = networkId; + + equal(data.networkId, networkId); + + run_next_test(); +}); + +add_test(function test_empty_network_id() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + Assert.throws(function() { + data.networkId = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_valid_transport_stream_id() { + var transportStreamId = "transportStreamId"; + + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + data.transportStreamId = transportStreamId; + + equal(data.transportStreamId, transportStreamId); + + run_next_test(); +}); + +add_test(function test_empty_transport_stream_id() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + Assert.throws(function() { + data.transportStreamId = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_valid_service_id() { + var serviceId = "serviceId"; + + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + data.serviceId = serviceId; + + equal(data.serviceId, serviceId); + + run_next_test(); +}); + +add_test(function test_empty_service_id() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + Assert.throws(function() { + data.serviceId = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_valid_type() { + var type = "tv"; + + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + data.type = type; + + equal(data.type, type); + + run_next_test(); +}); + +add_test(function test_empty_type() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + Assert.throws(function() { + data.type = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_invalid_type() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + Assert.throws(function() { + data.type = "invalid"; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_valid_number() { + var number = "number"; + + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + data.number = number; + + equal(data.number, number); + + run_next_test(); +}); + +add_test(function test_empty_number() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + Assert.throws(function() { + data.number = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_valid_name() { + var name = "name"; + + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + data.name = name; + + equal(data.name, name); + + run_next_test(); +}); + +add_test(function test_empty_name() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + Assert.throws(function() { + data.name = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_is_emergency() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + data.isEmergency = true; + + ok(data.isEmergency); + + run_next_test(); +}); + +add_test(function test_is_free() { + var data = Cc["@mozilla.org/tv/tvchanneldata;1"]. + createInstance(Ci.nsITVChannelData); + data.isFree = true; + + ok(data.isFree); + + run_next_test(); +});
new file mode 100644 --- /dev/null +++ b/dom/tv/test/xpcshell/test_tv_program_data.js @@ -0,0 +1,197 @@ +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +function run_test() { + run_next_test(); +} + +add_test(function test_valid_event_id() { + var eventId = "eventId"; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.eventId = eventId; + + equal(data.eventId, eventId); + + run_next_test(); +}); + +add_test(function test_empty_event_id() { + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + Assert.throws(function() { + data.eventId = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_valid_title() { + var title = "title"; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.title = title; + + equal(data.title, title); + + run_next_test(); +}); + +add_test(function test_empty_title() { + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + Assert.throws(function() { + data.title = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_start_time() { + var startTime = 1; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.startTime = startTime; + + equal(data.startTime, startTime); + + run_next_test(); +}); + +add_test(function test_duration() { + var duration = 1; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.duration = duration; + + equal(data.duration, duration); + + run_next_test(); +}); + +add_test(function test_valid_description() { + var description = "description"; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.description = description; + + equal(data.description, description); + + run_next_test(); +}); + +add_test(function test_empty_description() { + var description = ""; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.description = description; + + equal(data.description, description); + + run_next_test(); +}); + +add_test(function test_valid_rating() { + var rating = "rating"; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.rating = rating; + + equal(data.rating, rating); + + run_next_test(); +}); + +add_test(function test_empty_rating() { + var rating = ""; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.rating = rating; + + equal(data.rating, rating); + + run_next_test(); +}); + +add_test(function test_valid_audio_languages() { + var languages = ["eng", "jpn"]; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.setAudioLanguages(languages.length, languages); + + var audioLanguages = data.getAudioLanguages(); + equal(audioLanguages.length, languages.length); + for (var i = 0; i < audioLanguages.length; i++) { + equal(audioLanguages[i], languages[i]); + } + + run_next_test(); +}); + +add_test(function test_empty_audio_languages() { + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.setAudioLanguages(0, []); + + var audioLanguages = data.getAudioLanguages(); + equal(audioLanguages.length, 0); + + run_next_test(); +}); + +add_test(function test_mismatched_audio_languages() { + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + Assert.throws(function() { + data.setAudioLanguages(1, []); + }, /NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY/i); + + run_next_test(); +}); + +add_test(function test_valid_subtitle_languages() { + var languages = ["eng", "jpn"]; + + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.setSubtitleLanguages(languages.length, languages); + + var subtitleLanguages = data.getSubtitleLanguages(); + equal(subtitleLanguages.length, languages.length); + for (var i = 0; i < subtitleLanguages.length; i++) { + equal(subtitleLanguages[i], languages[i]); + } + + run_next_test(); +}); + +add_test(function test_empty_subtitle_languages() { + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + data.setSubtitleLanguages(0, []); + + var subtitleLanguages = data.getSubtitleLanguages(); + equal(subtitleLanguages.length, 0); + + run_next_test(); +}); + +add_test(function test_mismatched_subtitle_languages() { + var data = Cc["@mozilla.org/tv/tvprogramdata;1"]. + createInstance(Ci.nsITVProgramData); + Assert.throws(function() { + data.setSubtitleLanguages(1, []); + }, /NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY/i); + + run_next_test(); +});
new file mode 100644 --- /dev/null +++ b/dom/tv/test/xpcshell/test_tv_tuner_data.js @@ -0,0 +1,65 @@ +"use strict"; + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +function run_test() { + run_next_test(); +} + +add_test(function test_valid_id() { + var id = "id"; + + var data = Cc["@mozilla.org/tv/tvtunerdata;1"]. + createInstance(Ci.nsITVTunerData); + data.id = id; + + equal(data.id, id); + + run_next_test(); +}); + +add_test(function test_empty_id() { + var data = Cc["@mozilla.org/tv/tvtunerdata;1"]. + createInstance(Ci.nsITVTunerData); + Assert.throws(function() { + data.id = ""; + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_valid_supported_source_types() { + var sourceTypes = ["dvb-t", "dvb-s"]; + + var data = Cc["@mozilla.org/tv/tvtunerdata;1"]. + createInstance(Ci.nsITVTunerData); + data.setSupportedSourceTypes(sourceTypes.length, sourceTypes); + + var types = data.getSupportedSourceTypes(); + equal(types.length, sourceTypes.length); + for (var i = 0; i < types.length; i++) { + equal(types[i], sourceTypes[i]); + } + + run_next_test(); +}); + +add_test(function test_empty_supported_source_types() { + var data = Cc["@mozilla.org/tv/tvtunerdata;1"]. + createInstance(Ci.nsITVTunerData); + Assert.throws(function() { + data.setSupportedSourceTypes(0, []); + }, /NS_ERROR_ILLEGAL_VALUE/i); + + run_next_test(); +}); + +add_test(function test_mismatched_supported_source_types() { + var data = Cc["@mozilla.org/tv/tvtunerdata;1"]. + createInstance(Ci.nsITVTunerData); + Assert.throws(function() { + data.setSupportedSourceTypes(1, []); + }, /NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY/i); + + run_next_test(); +});
new file mode 100644 --- /dev/null +++ b/dom/tv/test/xpcshell/xpcshell.ini @@ -0,0 +1,7 @@ +[DEFAULT] +head = +tail = + +[test_tv_tuner_data.js] +[test_tv_channel_data.js] +[test_tv_program_data.js]
--- a/dom/webidl/IccCardLockError.webidl +++ b/dom/webidl/IccCardLockError.webidl @@ -1,11 +1,10 @@ /* 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/. */ -[Constructor(DOMString lockType, DOMString errorName, short retryCount), +[Constructor(DOMString errorName, short retryCount), Pref="dom.icc.enabled"] interface IccCardLockError : DOMError { - readonly attribute DOMString lockType; readonly attribute short retryCount; };
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -213,16 +213,40 @@ typedef mozilla::gfx::Matrix4x4 Matrix4x * "apz.fling_accel_base_mult" * "apz.fling_accel_supplemental_mult" * When applying an acceleration on a fling, the new computed velocity is * (new_fling_velocity * base_mult) + (old_velocity * supplemental_mult). * The base_mult and supplemental_mult multiplier values are controlled by * these prefs. Note that "old_velocity" here is the initial velocity of the * previous fling _after_ acceleration was applied to it (if applicable). * + * "apz.fling_curve_function_x1" + * "apz.fling_curve_function_y1" + * "apz.fling_curve_function_x2" + * "apz.fling_curve_function_y2" + * "apz.fling_curve_threshold_inches_per_ms" + * These five parameters define a Bezier curve function and threshold used to + * increase the actual velocity relative to the user's finger velocity. When the + * finger velocity is below the threshold (or if the threshold is not positive), + * the velocity is used as-is. If the finger velocity exceeds the threshold + * velocity, then the function defined by the curve is applied on the part of + * the velocity that exceeds the threshold. Note that the upper bound of the + * velocity is still specified by the apz.max_velocity_inches_per_ms pref, and + * the function will smoothly curve the velocity from the threshold to the + * max. In general the function parameters chosen should define an ease-out + * curve in order to increase the velocity in this range, or an ease-in curve to + * decrease the velocity. A straight-line curve is equivalent to disabling the + * curve entirely by setting the threshold to -1. The max velocity pref must + * also be set in order for the curving to take effect, as it defines the upper + * bound of the velocity curve. + * The points (x1, y1) and (x2, y2) used as the two intermediate control points + * in the cubic bezier curve; the first and last points are (0,0) and (1,1). + * Some example values for these prefs can be found at + * http://mxr.mozilla.org/mozilla-central/source/layout/style/nsStyleStruct.cpp?rev=21282be9ad95#2462 + * * "apz.fling_friction" * Amount of friction applied during flings. * * "apz.fling_repaint_interval" * Maximum amount of time flinging before sending a viewport change. This will * asynchronously repaint the page. * Units: milliseconds * @@ -346,17 +370,22 @@ typedef mozilla::gfx::Matrix4x4 Matrix4x * "apz.zoom_animation_duration_ms" * This controls how long the zoom-to-rect animation takes. * Units: ms */ /** * Computed time function used for sampling frames of a zoom to animation. */ -StaticAutoPtr<ComputedTimingFunction> gComputedTimingFunction; +StaticAutoPtr<ComputedTimingFunction> gZoomAnimationFunction; + +/** + * Computed time function used for curving up velocity when it gets high. + */ +StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction; /** * Maximum zoom amount, always used, even if a page asks for higher. */ static const CSSToScreenScale MAX_ZOOM(8.0f); /** * Minimum zoom amount, always used, even if a page asks for lower. @@ -633,17 +662,17 @@ public: if (animPosition >= 1.0) { aFrameMetrics.SetZoom(mEndZoom); aFrameMetrics.SetScrollOffset(mEndOffset); return false; } // Sample the zoom at the current time point. The sampled zoom // will affect the final computed resolution. - float sampledPosition = gComputedTimingFunction->GetValue(animPosition); + float sampledPosition = gZoomAnimationFunction->GetValue(animPosition); // We scale the scrollOffset linearly with sampledPosition, so the zoom // needs to scale inversely to match. aFrameMetrics.SetZoom(CSSToScreenScale(1 / (sampledPosition / mEndZoom.scale + (1 - sampledPosition) / mStartZoom.scale))); aFrameMetrics.SetScrollOffset(CSSPoint::FromUnknownPoint(gfx::Point( @@ -854,20 +883,27 @@ AsyncPanZoomController::InitializeGlobal { MOZ_ASSERT(NS_IsMainThread()); static bool sInitialized = false; if (sInitialized) return; sInitialized = true; - gComputedTimingFunction = new ComputedTimingFunction(); - gComputedTimingFunction->Init( + gZoomAnimationFunction = new ComputedTimingFunction(); + gZoomAnimationFunction->Init( nsTimingFunction(NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE)); - ClearOnShutdown(&gComputedTimingFunction); + ClearOnShutdown(&gZoomAnimationFunction); + gVelocityCurveFunction = new ComputedTimingFunction(); + gVelocityCurveFunction->Init( + nsTimingFunction(gfxPrefs::APZCurveFunctionX1(), + gfxPrefs::APZCurveFunctionY2(), + gfxPrefs::APZCurveFunctionX2(), + gfxPrefs::APZCurveFunctionY2())); + ClearOnShutdown(&gVelocityCurveFunction); } AsyncPanZoomController::AsyncPanZoomController(uint64_t aLayersId, APZCTreeManager* aTreeManager, const nsRefPtr<InputQueue>& aInputQueue, GeckoContentController* aGeckoContentController, GestureBehavior aGestures) : mLayersId(aLayersId),
--- a/gfx/layers/apz/src/Axis.cpp +++ b/gfx/layers/apz/src/Axis.cpp @@ -3,42 +3,55 @@ /* 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 "Axis.h" #include <math.h> // for fabsf, pow, powf #include <algorithm> // for max #include "AsyncPanZoomController.h" // for AsyncPanZoomController +#include "mozilla/dom/AnimationPlayer.h" // for ComputedTimingFunction #include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager #include "FrameMetrics.h" // for FrameMetrics #include "mozilla/Attributes.h" // for MOZ_FINAL #include "mozilla/Preferences.h" // for Preferences #include "mozilla/gfx/Rect.h" // for RoundedIn #include "mozilla/mozalloc.h" // for operator new #include "mozilla/FloatingPoint.h" // for FuzzyEqualsAdditive +#include "mozilla/StaticPtr.h" // for StaticAutoPtr #include "nsMathUtils.h" // for NS_lround #include "nsPrintfCString.h" // for nsPrintfCString #include "nsThreadUtils.h" // for NS_DispatchToMainThread, etc #include "nscore.h" // for NS_IMETHOD #include "gfxPrefs.h" // for the preferences +#define AXIS_LOG(...) +// #define AXIS_LOG(...) printf_stderr("AXIS: " __VA_ARGS__) + namespace mozilla { namespace layers { +extern StaticAutoPtr<ComputedTimingFunction> gVelocityCurveFunction; + Axis::Axis(AsyncPanZoomController* aAsyncPanZoomController) : mPos(0), mPosTimeMs(0), mVelocity(0.0f), mAxisLocked(false), mAsyncPanZoomController(aAsyncPanZoomController), mOverscroll(0) { } +float Axis::ToLocalVelocity(float aVelocityInchesPerMs) { + ScreenPoint aVelocityPoint = MakePoint(aVelocityInchesPerMs * APZCTreeManager::GetDPI()); + mAsyncPanZoomController->ToLocalScreenCoordinates(&aVelocityPoint, mAsyncPanZoomController->PanStart()); + return aVelocityPoint.Length(); +} + void Axis::UpdateWithTouchAtDevicePoint(ScreenCoord aPos, uint32_t aTimestampMs) { // mVelocityQueue is controller-thread only AsyncPanZoomController::AssertOnControllerThread(); if (aTimestampMs == mPosTimeMs) { // This could be a duplicate event, or it could be a legitimate event // on some platforms that generate events really fast. As a compromise // update mPos so we don't run into problems like bug 1042734, even though @@ -47,19 +60,31 @@ void Axis::UpdateWithTouchAtDevicePoint( return; } float newVelocity = mAxisLocked ? 0.0f : (float)(mPos - aPos) / (float)(aTimestampMs - mPosTimeMs); if (gfxPrefs::APZMaxVelocity() > 0.0f) { bool velocityIsNegative = (newVelocity < 0); newVelocity = fabs(newVelocity); - ScreenPoint maxVelocity = MakePoint(gfxPrefs::APZMaxVelocity() * APZCTreeManager::GetDPI()); - mAsyncPanZoomController->ToLocalScreenCoordinates(&maxVelocity, mAsyncPanZoomController->PanStart()); - newVelocity = std::min(newVelocity, maxVelocity.Length()); + float maxVelocity = ToLocalVelocity(gfxPrefs::APZMaxVelocity()); + newVelocity = std::min(newVelocity, maxVelocity); + + if (gfxPrefs::APZCurveThreshold() > 0.0f && gfxPrefs::APZCurveThreshold() < gfxPrefs::APZMaxVelocity()) { + float curveThreshold = ToLocalVelocity(gfxPrefs::APZCurveThreshold()); + if (newVelocity > curveThreshold) { + // here, 0 < curveThreshold < newVelocity <= maxVelocity, so we apply the curve + float scale = maxVelocity - curveThreshold; + float funcInput = (newVelocity - curveThreshold) / scale; + float funcOutput = gVelocityCurveFunction->GetValue(funcInput); + float curvedVelocity = (funcOutput * scale) + curveThreshold; + AXIS_LOG("Curving up velocity from %f to %f\n", newVelocity, curvedVelocity); + newVelocity = curvedVelocity; + } + } if (velocityIsNegative) { newVelocity = -newVelocity; } } mVelocity = newVelocity; mPos = aPos;
--- a/gfx/layers/apz/src/Axis.h +++ b/gfx/layers/apz/src/Axis.h @@ -227,16 +227,19 @@ protected: // accessed on the controller/UI thread. nsTArray<std::pair<uint32_t, float> > mVelocityQueue; const FrameMetrics& GetFrameMetrics() const; // Adjust a requested overscroll amount for resistance, yielding a smaller // actual overscroll amount. ScreenCoord ApplyResistance(ScreenCoord aOverscroll) const; + + // Convert a velocity from global inches/ms into local ScreenCoords per ms + float ToLocalVelocity(float aVelocityInchesPerMs); }; class AxisX : public Axis { public: explicit AxisX(AsyncPanZoomController* mAsyncPanZoomController); virtual ScreenCoord GetPointOffset(const ScreenPoint& aPoint) const MOZ_OVERRIDE; virtual ScreenCoord GetRectLength(const ScreenRect& aRect) const MOZ_OVERRIDE; virtual ScreenCoord GetRectOffset(const ScreenRect& aRect) const MOZ_OVERRIDE;
--- a/gfx/layers/ipc/CompositorParent.cpp +++ b/gfx/layers/ipc/CompositorParent.cpp @@ -60,16 +60,20 @@ #include "mozilla/Hal.h" #include "mozilla/HalTypes.h" #include "mozilla/StaticPtr.h" #ifdef MOZ_ENABLE_PROFILER_SPS #include "ProfilerMarkers.h" #endif #include "mozilla/VsyncDispatcher.h" +#ifdef MOZ_WIDGET_GONK +#include "GeckoTouchDispatcher.h" +#endif + namespace mozilla { namespace layers { using namespace base; using namespace mozilla::ipc; using namespace mozilla::gfx; using namespace std; @@ -268,16 +272,18 @@ CompositorVsyncObserver::Composite(TimeS if (mNeedsComposite && mCompositorParent) { mNeedsComposite = false; mCompositorParent->CompositeCallback(aVsyncTimestamp); } else { // We're getting vsync notifications but we don't need to composite so // unregister the vsync. UnobserveVsync(); } + + DispatchTouchEvents(aVsyncTimestamp); } bool CompositorVsyncObserver::NeedsComposite() { MOZ_ASSERT(CompositorParent::IsInCompositorThread()); return mNeedsComposite; } @@ -297,16 +303,26 @@ CompositorVsyncObserver::ObserveVsync() void CompositorVsyncObserver::UnobserveVsync() { MOZ_ASSERT(CompositorParent::IsInCompositorThread() || NS_IsMainThread()); VsyncDispatcher::GetInstance()->RemoveCompositorVsyncObserver(this); mIsObservingVsync = false; } +void +CompositorVsyncObserver::DispatchTouchEvents(TimeStamp aVsyncTimestamp) +{ +#ifdef MOZ_WIDGET_GONK + if (gfxPrefs::TouchResampling()) { + GeckoTouchDispatcher::NotifyVsync(aVsyncTimestamp); + } +#endif +} + void CompositorParent::StartUp() { MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); sCompositorThreadHolder = new CompositorThreadHolder(); }
--- a/gfx/layers/ipc/CompositorParent.h +++ b/gfx/layers/ipc/CompositorParent.h @@ -108,16 +108,17 @@ public: private: virtual ~CompositorVsyncObserver(); void Composite(TimeStamp aVsyncTimestamp); void NotifyCompositeTaskExecuted(); void ObserveVsync(); void UnobserveVsync(); + void DispatchTouchEvents(TimeStamp aVsyncTimestamp); bool mNeedsComposite; bool mIsObservingVsync; nsRefPtr<CompositorParent> mCompositorParent; mozilla::Monitor mCurrentCompositeTaskMonitor; CancelableTask* mCurrentCompositeTask; };
--- a/gfx/thebes/gfxPrefs.h +++ b/gfx/thebes/gfxPrefs.h @@ -141,16 +141,21 @@ private: DECL_GFX_PREF(Live, "apz.content_response_timeout", APZContentResponseTimeout, int32_t, 300); DECL_GFX_PREF(Live, "apz.cross_slide.enabled", APZCrossSlideEnabled, bool, false); DECL_GFX_PREF(Live, "apz.danger_zone_x", APZDangerZoneX, int32_t, 50); DECL_GFX_PREF(Live, "apz.danger_zone_y", APZDangerZoneY, int32_t, 100); DECL_GFX_PREF(Live, "apz.enlarge_displayport_when_clipped", APZEnlargeDisplayPortWhenClipped, bool, false); DECL_GFX_PREF(Live, "apz.fling_accel_interval_ms", APZFlingAccelInterval, int32_t, 500); DECL_GFX_PREF(Live, "apz.fling_accel_base_mult", APZFlingAccelBaseMultiplier, float, 1.0f); DECL_GFX_PREF(Live, "apz.fling_accel_supplemental_mult", APZFlingAccelSupplementalMultiplier, float, 1.0f); + DECL_GFX_PREF(Once, "apz.fling_curve_function_x1", APZCurveFunctionX1, float, 0.0f); + DECL_GFX_PREF(Once, "apz.fling_curve_function_y1", APZCurveFunctionY1, float, 0.0f); + DECL_GFX_PREF(Once, "apz.fling_curve_function_x2", APZCurveFunctionX2, float, 1.0f); + DECL_GFX_PREF(Once, "apz.fling_curve_function_y2", APZCurveFunctionY2, float, 1.0f); + DECL_GFX_PREF(Live, "apz.fling_curve_threshold_inches_per_ms", APZCurveThreshold, float, -1.0f); DECL_GFX_PREF(Once, "apz.fling_friction", APZFlingFriction, float, 0.002f); DECL_GFX_PREF(Live, "apz.fling_repaint_interval", APZFlingRepaintInterval, int32_t, 75); DECL_GFX_PREF(Once, "apz.fling_stop_on_tap_threshold", APZFlingStopOnTapThreshold, float, 0.05f); DECL_GFX_PREF(Once, "apz.fling_stopped_threshold", APZFlingStoppedThreshold, float, 0.01f); DECL_GFX_PREF(Once, "apz.max_velocity_inches_per_ms", APZMaxVelocity, float, -1.0f); DECL_GFX_PREF(Once, "apz.max_velocity_queue_size", APZMaxVelocityQueueSize, uint32_t, 5); DECL_GFX_PREF(Live, "apz.min_skate_speed", APZMinSkateSpeed, float, 1.0f); DECL_GFX_PREF(Live, "apz.num_paint_duration_samples", APZNumPaintDurationSamples, int32_t, 3);
--- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -383,16 +383,19 @@ size. --> <!ENTITY button_set "Set"> <!ENTITY button_clear "Clear"> <!ENTITY home_top_sites_title "Top Sites"> <!-- Localization note (home_top_sites_add): This string is used as placeholder text underneath empty thumbnails in the Top Sites page on about:home. --> <!ENTITY home_top_sites_add "Add a site"> +<!-- Localization note (home_title): This string should be kept in sync + with the page title defined in aboutHome.dtd --> +<!ENTITY home_title "&brandShortName; Home"> <!ENTITY home_history_title "History"> <!ENTITY home_clear_history_button "Clear browsing history"> <!ENTITY home_clear_history_confirm "Are you sure you want to clear your history?"> <!ENTITY home_bookmarks_empty "Bookmarks you save show up here."> <!ENTITY home_closed_tabs_title "Recently closed tabs"> <!ENTITY home_last_tabs_title "Tabs from last time"> <!ENTITY home_last_tabs_empty "Your recent tabs show up here."> <!ENTITY home_open_all "Open all">
new file mode 100644 --- /dev/null +++ b/mobile/android/base/newtablet/res/color-large-v11/new_tablet_tab_item_title.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <item android:state_checked="true" + android:color="@color/text_color_primary_inverse"/> + + <item android:state_pressed="true" + android:color="@color/text_color_primary_inverse"/> + + <item android:color="@color/new_tablet_tab_grid_text_unselected"/> + +</selector>
new file mode 100644 index 0000000000000000000000000000000000000000..ca09ae09adbd7242fd2489cdc31205b9f2bdfe42 GIT binary patch literal 353 zc$@)Y0iOPeP)<h;3K|Lk000e1NJLTq000gE000gM1^@s6A4o0H00001b5ch_0Itp) z=>Px$8%ab#R45g7lEI3DFc5}KKq=Oo1)+U_rMEss@7-q*AIO6TU!gZ2qt~9xA_~%i zLUgIhcJsGP36lJWgqh5jnM{V|d434P@H9=6Y?@{t$MKJ2P@1NjD2mRW=ZU(mkE|$) zU*Gpvh?P?IRaJd0VL(b3Aw+<<zV9D=97hQQ3W8v*ZoOn#wtagXX9>ZN>KK9$42Xg$ z^E}T_JrmAxR+i<C!LY$kB`Qyck|eplKpPA{i829#?*qaxWrlwV!N;+X@Fs|CednD2 z>Gmh1se5`LHH^OM1)3lP0yK3SFtb5uIm)wr6~`FaT8^7BNtB%`P$PQgm_2%nse2~a zbzQ+Ru$aBJZSN?L{)sNbPH@+Cw_z9_iuwKr#WwOu!#h6=00000NkvXXu0mjfmeiB+
new file mode 100644 index 0000000000000000000000000000000000000000..e24adb4995993aa353b02b52322471f1aec57c98 GIT binary patch literal 272 zc$@(c0q_2aP)<h;3K|Lk000e1NJLTq000R9000RH1^@s6;E@Ip00001b5ch_0Itp) z=>Px#%1J~)R2Ug`kUa{6KoEuF5{L*|i|8RdK$;-QIV|)9X_5n^$q{TUy+b4rQl!lp z{6TCjM1w{Az=1T`W|(<z-+r@NmSr!~H2u1+4{;nnR?A6}Wa~K2t?RnC!eAK2#`C-! z0T0!6-8*y3vV29tFbtEf>uZEGO^;OiaU7>v-)p}&5ti3h7>c3@Ku`>$D0;SSdlCb+ zX_~Vz{!Id*s;V6Unm`Hz3ASxt=*6g5Qw%VKVR$XeGLU6vJy-lg-}fJZga;Ok%+bFO W^oJsPr}$m~0000<MNUMnLSTaVl4@=M
new file mode 100644 --- /dev/null +++ b/mobile/android/base/newtablet/res/drawable-large-v11/new_tablet_tab_item_close_button.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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/. --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + + <!-- pressed state --> + <item android:state_pressed="true" + android:drawable="@drawable/new_tablet_tab_close_active"/> + + <item android:state_checked="true" + android:drawable="@drawable/new_tablet_tab_close_active"/> + + <!-- normal mode --> + <item android:drawable="@drawable/new_tablet_tab_close"/> + +</selector>
--- a/mobile/android/base/newtablet/res/drawable-large-v11/new_tablet_tab_strip_item_bg.xml +++ b/mobile/android/base/newtablet/res/drawable-large-v11/new_tablet_tab_strip_item_bg.xml @@ -26,27 +26,27 @@ <shape> <solid android:color="@color/highlight_dark_focused" /> </shape> </item> <item android:state_pressed="true" android:state_checked="true"> <shape> - <solid android:color="@color/highlight_nav" /> + <solid android:color="@color/new_tablet_highlight" /> </shape> </item> <item android:state_checked="true"> <shape> <solid android:color="@color/background_normal" /> </shape> </item> <item android:state_pressed="true"> <shape> - <solid android:color="@color/highlight_dark" /> + <solid android:color="@color/new_tablet_highlight_dark" /> </shape> </item> <item android:drawable="@android:color/transparent"/> </selector>
new file mode 100644 index 0000000000000000000000000000000000000000..cb997070af278fbd6cfd1b207227bac8d46f59c8 GIT binary patch literal 417 zc$@*D0bc%zP)<h;3K|Lk000e1NJLTq000sI000sQ1^@s6R?d!B00001b5ch_0Itp) z=>Px$TS-JgR5%fhl+9{`KoG~f+Xqk(RD6d*p_I_(8Yt~q5Bh$hK0pp7&{Jti$)PQM z2SxA$k3vfK9~jwec2oD@%+ANpnROi&MbTv#hFi<BuG_ZVBuVmkF=M4^x^^7rVHk$* zuIm=8D2koyx;K<tRn>bO$M>|?$vn?rJ<nT`udeG)j!MV?>HGd&mSu0UP1aQie70?0 zakL``LN~#55X3i4^TME@0whD1m)xcaB4R$oQ7jH1B%gyZ#(w29p_dT^`w4`N2?n3K zWC(mmAQ<MrREQSzA4~^94#z`XI1|+-?e~&CsVA+OzRr{(6j9a5r9A@8fe=uIO|6+A zI1?lhfTVh94;7t*;Ibjv^fjq6hQBxnf+u<tNmN1*vYB9ISw3@&0tzIlgTRNWpleew zRvhz$0FWjK#pqyt-~Vt7CCrm?9QUHcjoJ<YWC<ABL5|4%5}?~Z(yih{^hqE<00000 LNkvXXu0mjf$;Ph-
new file mode 100644 index 0000000000000000000000000000000000000000..8e8f299f092c23dba9bd21551f7a127fa6da9210 GIT binary patch literal 606 zc$@)V0-^nhP)<h;3K|Lk000e1NJLTq000{R000{Z1^@s6jnwp200001b5ch_0Itp) z=>Px%7)eAyR7ee_mfuPOQ4q%4Qy{o);GYN)@nQ*j0Uw}<h@gw;0lX0L6}%E6=*A}y z(MPDeA}@M@dV**#6j8B2mL)+!=zP*F>$>aCt_O77IcMhQob&BrlpQ(h^}3qR=id{F z#L09zwZ`M|O}Sit!(5cnYPC+&>GV@P9zU2&CZCpN6-uR&r2wSsx*<VFlz29qExO(A zRi#qtkdJGd&E{DymwS!HVtW)Lf#33@i~ovj5EjUVyVC#MXf!S;fMdNth?9jJYMS;T zuytOE!UFw3lslPB9t)fiIoy^D3<4qVuN(qmz!|wg^c)1_fadf0Vl*1v3aAcZhyvt- z`u+Yj#HLUM5CcSkO33H7PL+lMN!h<3mkq-M7dRXa?=qQ8P5v=k-iUV&Y#k~h5aw23 zaBzTFw`q8Ruzn2&=Qcn;kS{DMa1&@FEG#exgnR;Degkra82sj)e)%3fIK|+cqu-uq zMw1+Q(^}_iK|Z(jg@pl8(jcHGEDDGNT!U=`3IeVOgad-=dcEF#l)Kc1aY49(ip63r z%H_S>#xNkKyg4_GQ#1;ilWaEI345v1`EY@Q!QfJ$3yKN?5HCJwOH--Tqd>bw|I%$a zR}dGds_MQ#U+0G4nG2%Wpb91DOQ3;7Uq?YvKosi-G)?ozFpR=djZ!4Ct<yfxZlMc8 sbAmuh64tic?Q@(Fwhk2mRIOIcKYT~ozl0)7e*gdg07*qoM6N<$g7G*B(*OVf
--- a/mobile/android/base/newtablet/res/layout-large-v11/tab_strip.xml +++ b/mobile/android/base/newtablet/res/layout-large-v11/tab_strip.xml @@ -5,18 +5,19 @@ <merge xmlns:android="http://schemas.android.com/apk/res/android"> <org.mozilla.gecko.tabs.TabStripView android:id="@+id/tab_strip" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" - android:paddingTop="8dp" - android:paddingLeft="2dp"/> + android:requiresFadingEdge="horizontal" + android:fadingEdgeLength="10dp" + android:paddingTop="8dp"/> <ImageButton android:id="@+id/add_tab" style="@style/UrlBar.ImageButton" android:layout_width="@dimen/new_tablet_tab_strip_height" android:src="@drawable/tab_new_level" android:contentDescription="@string/new_tab" android:background="@drawable/action_bar_button_inverse"/>
--- a/mobile/android/base/newtablet/res/layout-large-v11/tab_strip_item.xml +++ b/mobile/android/base/newtablet/res/layout-large-v11/tab_strip_item.xml @@ -5,10 +5,10 @@ <!-- The paddings are asymmetric here to compensate the padding around the the close button within the TabStripItemView --> <org.mozilla.gecko.tabs.TabStripItemView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="@dimen/new_tablet_tab_strip_item_width" android:layout_height="match_parent" android:background="@drawable/new_tablet_tab_strip_item_bg" - android:paddingLeft="25dp" - android:paddingRight="15dp"/> + android:paddingLeft="28dp" + android:paddingRight="12dp"/>
--- a/mobile/android/base/newtablet/res/layout-large-v11/tab_strip_item_view.xml +++ b/mobile/android/base/newtablet/res/layout-large-v11/tab_strip_item_view.xml @@ -5,17 +5,17 @@ <merge xmlns:android="http://schemas.android.com/apk/res/android" xmlns:gecko="http://schemas.android.com/apk/res-auto"> <ImageView android:id="@+id/favicon" android:layout_width="@dimen/new_tablet_tab_strip_favicon_size" android:layout_height="match_parent" - android:layout_marginRight="9dp" + android:layout_marginRight="8dp" android:scaleType="centerInside" android:duplicateParentState="true"/> <org.mozilla.gecko.widget.FadedTextView android:id="@+id/title" android:layout_width="0dip" android:layout_height="match_parent" android:layout_weight="1.0"
--- a/mobile/android/base/resources/layout/new_tablet_tabs_item_cell.xml +++ b/mobile/android/base/resources/layout/new_tablet_tabs_item_cell.xml @@ -4,53 +4,53 @@ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> <org.mozilla.gecko.tabs.TabsLayoutItemView xmlns:android="http://schemas.android.com/apk/res/android" style="@style/TabsItem" android:focusable="true" android:id="@+id/info" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingTop="6dip" - android:paddingBottom="6dip" - android:paddingLeft="1dip" - android:paddingRight="1dip" android:gravity="center" - android:orientation="vertical"> + android:orientation="vertical" + android:paddingBottom="@dimen/new_tablet_tab_panel_grid_padding"> - <LinearLayout android:layout_width="@dimen/new_tablet_tab_thumbnail_width" + <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" - android:padding="3dip"> + android:duplicateParentState="true" + android:paddingLeft="@dimen/new_tablet_tab_highlight_stroke_width" + android:paddingRight="@dimen/new_tablet_tab_highlight_stroke_width" + android:paddingBottom="@dimen/new_tablet_tab_highlight_stroke_width"> <TextView android:id="@+id/title" android:layout_width="0dip" android:layout_height="wrap_content" android:layout_weight="1.0" - android:paddingTop="4dip" style="@style/TabLayoutItemTextAppearance" - android:textSize="12sp" - android:textColor="#FFFFFFFF" + android:textSize="14sp" + android:textColor="@color/new_tablet_tab_item_title" android:singleLine="true" android:duplicateParentState="true"/> <ImageButton android:id="@+id/close" style="@style/TabsItemClose" android:layout_width="wrap_content" android:layout_height="match_parent" - android:background="@drawable/action_bar_button_inverse" android:scaleType="center" + android:background="@android:color/transparent" android:contentDescription="@string/close_tab" - android:src="@drawable/new_tablet_tab_close"/> + android:src="@drawable/new_tablet_tab_item_close_button" + android:duplicateParentState="true"/> </LinearLayout> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:padding="3dp" + android:padding="@dimen/new_tablet_tab_highlight_stroke_width" android:background="@drawable/tab_thumbnail" android:duplicateParentState="true"> <org.mozilla.gecko.widget.ThumbnailView android:id="@+id/thumbnail" android:layout_width="@dimen/new_tablet_tab_thumbnail_width" android:layout_height="@dimen/new_tablet_tab_thumbnail_height" android:src="@drawable/tab_thumbnail_default"/>
--- a/mobile/android/base/resources/values/colors.xml +++ b/mobile/android/base/resources/values/colors.xml @@ -13,16 +13,17 @@ <color name="highlight_dark">#33FFFFFF</color> <color name="highlight_dark_focused">#1AFFFFFF</color> <!-- (bug 1077195) Focused state values are temporary. --> <color name="new_tablet_highlight">#D7D7DC</color> <color name="new_tablet_highlight_focused">#C0C9D0</color> <color name="new_tablet_highlight_pb">#222222</color> <color name="new_tablet_highlight_focused_pb">#363B40</color> + <color name="new_tablet_highlight_dark">#45494E</color> <!-- highlight on shaped button: 20% white over background_tabs --> <color name="highlight_shaped">#FF696D71</color> <!-- highlight-focused on shaped button: 10% white over background_tabs --> <color name="highlight_shaped_focused">#FF565B60</color> <!-- highlight on nav button: 20% black over background_normal --> @@ -146,9 +147,13 @@ <!-- Canvas delegate paint color --> <color name="canvas_delegate_paint">#FFFF0000</color> <!-- Top sites thumbnail colors --> <color name="top_site_default">#FFECF0F3</color> <color name="top_site_border">#FFCFD9E1</color> + <!-- Tab grid text highlight colour --> + <color name="new_tablet_tab_grid_text_unselected">#FFAFB1B3</color> + + </resources>
--- a/mobile/android/base/resources/values/dimens.xml +++ b/mobile/android/base/resources/values/dimens.xml @@ -18,18 +18,18 @@ <dimen name="browser_toolbar_shadow_size">2dp</dimen> <!-- If you update one of these values, update the others. --> <dimen name="new_tablet_nav_button_width">42dp</dimen> <dimen name="new_tablet_nav_button_width_half">21dp</dimen> <dimen name="new_tablet_nav_button_width_plus_half">63dp</dimen> <dimen name="new_tablet_tab_strip_height">48dp</dimen> - <dimen name="new_tablet_tab_strip_item_width">250dp</dimen> - <dimen name="new_tablet_tab_strip_item_margin">-30dp</dimen> + <dimen name="new_tablet_tab_strip_item_width">208dp</dimen> + <dimen name="new_tablet_tab_strip_item_margin">-28dp</dimen> <dimen name="new_tablet_tab_strip_favicon_size">16dp</dimen> <dimen name="new_tablet_site_security_height">60dp</dimen> <dimen name="new_tablet_site_security_width">34dp</dimen> <!-- We primarily use padding (instead of margins) to increase the hit area. --> <dimen name="new_tablet_site_security_padding_vertical">21dp</dimen> <dimen name="new_tablet_site_security_padding_horizontal">8dp</dimen> <dimen name="new_tablet_site_security_right_margin">1dp</dimen> <dimen name="new_tablet_browser_toolbar_height">60dp</dimen> @@ -123,19 +123,23 @@ <dimen name="text_selection_handle_height">58dp</dimen> <dimen name="text_selection_handle_shadow">11dp</dimen> <dimen name="validation_message_height">50dp</dimen> <dimen name="validation_message_margin_top">6dp</dimen> <dimen name="url_bar_offset_left">32dp</dimen> <dimen name="history_tab_indicator_height">50dp</dimen> - <dimen name="new_tablet_tab_thumbnail_height">180dp</dimen> - <dimen name="new_tablet_tab_thumbnail_width">180dp</dimen> - <dimen name="new_tablet_tab_panel_grid_padding">24dp</dimen> + <dimen name="new_tablet_tab_thumbnail_width">168dp</dimen> + <dimen name="new_tablet_tab_thumbnail_height">140dp</dimen> + <dimen name="new_tablet_tab_panel_column_width">178dp</dimen> + <dimen name="new_tablet_tab_panel_grid_padding">19dp</dimen> + <dimen name="new_tablet_tab_panel_grid_padding_top">24dp</dimen> + + <dimen name="new_tablet_tab_highlight_stroke_width">5dp</dimen> <!-- PageActionButtons dimensions --> <dimen name="page_action_button_width">32dp</dimen> <!-- Banner --> <dimen name="home_banner_height">72dp</dimen> <!-- Icon Grid -->
--- a/mobile/android/base/strings.xml.in +++ b/mobile/android/base/strings.xml.in @@ -338,16 +338,17 @@ <string name="button_ok">&button_ok;</string> <string name="button_cancel">&button_cancel;</string> <string name="button_clear_data">&button_clear_data;</string> <string name="button_set">&button_set;</string> <string name="button_clear">&button_clear;</string> <string name="button_yes">&button_yes;</string> <string name="button_no">&button_no;</string> + <string name="home_title">&home_title;</string> <string name="home_top_sites_title">&home_top_sites_title;</string> <string name="home_top_sites_add">&home_top_sites_add;</string> <string name="home_history_title">&home_history_title;</string> <string name="home_clear_history_button">&home_clear_history_button;</string> <string name="home_clear_history_confirm">&home_clear_history_confirm;</string> <string name="home_bookmarks_empty">&home_bookmarks_empty;</string> <string name="home_closed_tabs_title">&home_closed_tabs_title;</string> <string name="home_last_tabs_title">&home_last_tabs_title;</string>
--- a/mobile/android/base/tabs/TabStripItemView.java +++ b/mobile/android/base/tabs/TabStripItemView.java @@ -1,30 +1,32 @@ /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; 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.tabs; +import org.mozilla.gecko.AboutPages; import org.mozilla.gecko.R; import org.mozilla.gecko.Tab; import org.mozilla.gecko.Tabs; import org.mozilla.gecko.widget.ThemedImageButton; import org.mozilla.gecko.widget.ThemedLinearLayout; import org.mozilla.gecko.widget.ThemedTextView; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffXfermode; import android.graphics.Region; +import android.text.TextUtils; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.Checkable; import android.widget.ImageView; public class TabStripItemView extends ThemedLinearLayout @@ -194,21 +196,35 @@ public class TabStripItemView extends Th } void updateFromTab(Tab tab) { if (tab == null) { return; } id = tab.getId(); + + updateTitle(tab); updateFavicon(tab.getFavicon()); - titleView.setText(tab.getDisplayTitle()); setPrivateMode(tab.isPrivate()); } + private void updateTitle(Tab tab) { + final String title; + + // Avoid flickering the about:home URL on every load given how often + // this page is used in the UI. + if (AboutPages.isAboutHome(tab.getURL())) { + titleView.setText(R.string.home_title); + } else { + titleView.setText(tab.getDisplayTitle()); + } + + } + private void updateFavicon(final Bitmap favicon) { if (favicon == null) { lastFavicon = null; faviconView.setImageResource(R.drawable.new_tablet_default_favicon); return; } if (favicon == lastFavicon) { return;
--- a/mobile/android/base/tabs/TabsGridLayout.java +++ b/mobile/android/base/tabs/TabsGridLayout.java @@ -63,21 +63,22 @@ class TabsGridLayout extends GridView }); setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); setStretchMode(GridView.STRETCH_SPACING); setGravity(Gravity.CENTER); setNumColumns(GridView.AUTO_FIT); final Resources resources = getResources(); - final int columnWidth = resources.getDimensionPixelSize(R.dimen.new_tablet_tab_thumbnail_width); + final int columnWidth = resources.getDimensionPixelSize(R.dimen.new_tablet_tab_panel_column_width); setColumnWidth(columnWidth); final int padding = resources.getDimensionPixelSize(R.dimen.new_tablet_tab_panel_grid_padding); - setPadding(padding, 0, padding, 0); + final int paddingTop = resources.getDimensionPixelSize(R.dimen.new_tablet_tab_panel_grid_padding_top); + setPadding(padding, paddingTop, padding, padding); } private class TabsGridLayoutAdapter extends TabsLayoutAdapter { final private Button.OnClickListener mCloseClickListener; final private View.OnClickListener mSelectClickListener; public TabsGridLayoutAdapter (Context context) {
--- a/mobile/android/base/tabs/TabsLayoutItemView.java +++ b/mobile/android/base/tabs/TabsLayoutItemView.java @@ -10,16 +10,17 @@ import org.mozilla.gecko.widget.TabThumb import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.view.View; import android.widget.Checkable; import android.widget.ImageButton; import android.widget.ImageView; +import android.widget.ImageView.ScaleType; import android.widget.LinearLayout; import android.widget.TextView; public class TabsLayoutItemView extends LinearLayout implements Checkable { private static final String LOGTAG = "Gecko" + TabsLayoutItemView.class.getSimpleName(); private static final int[] STATE_CHECKED = { android.R.attr.state_checked }; private boolean mChecked; @@ -90,17 +91,17 @@ public class TabsLayoutItemView extends if (tab == null) { return; } mTabId = tab.getId(); Drawable thumbnailImage = tab.getThumbnail(); if (thumbnailImage != null) { - mThumbnail.setImageDrawable(thumbnailImage); + setThumbnail(thumbnailImage); } else { mThumbnail.setImageResource(R.drawable.tab_thumbnail_default); } if (mThumbnailWrapper != null) { mThumbnailWrapper.setRecording(tab.isRecording()); } mTitle.setText(tab.getDisplayTitle()); mCloseButton.setTag(this);
--- a/mobile/android/base/widget/TwoWayView.java +++ b/mobile/android/base/widget/TwoWayView.java @@ -1108,16 +1108,120 @@ public class TwoWayView extends AdapterV return mFirstPosition + i; } } } return INVALID_POSITION; } @Override + protected float getTopFadingEdgeStrength() { + if (!mIsVertical) { + return 0f; + } + + final float fadingEdge = super.getTopFadingEdgeStrength(); + + final int childCount = getChildCount(); + if (childCount == 0) { + return fadingEdge; + } else { + if (mFirstPosition > 0) { + return 1.0f; + } + + final int top = getChildAt(0).getTop(); + final int paddingTop = getPaddingTop(); + + final float length = (float) getVerticalFadingEdgeLength(); + + return (top < paddingTop ? (float) -(top - paddingTop) / length : fadingEdge); + } + } + + @Override + protected float getBottomFadingEdgeStrength() { + if (!mIsVertical) { + return 0f; + } + + final float fadingEdge = super.getBottomFadingEdgeStrength(); + + final int childCount = getChildCount(); + if (childCount == 0) { + return fadingEdge; + } else { + if (mFirstPosition + childCount - 1 < mItemCount - 1) { + return 1.0f; + } + + final int bottom = getChildAt(childCount - 1).getBottom(); + final int paddingBottom = getPaddingBottom(); + + final int height = getHeight(); + final float length = (float) getVerticalFadingEdgeLength(); + + return (bottom > height - paddingBottom ? + (float) (bottom - height + paddingBottom) / length : fadingEdge); + } + } + + @Override + protected float getLeftFadingEdgeStrength() { + if (mIsVertical) { + return 0f; + } + + final float fadingEdge = super.getLeftFadingEdgeStrength(); + + final int childCount = getChildCount(); + if (childCount == 0) { + return fadingEdge; + } else { + if (mFirstPosition > 0) { + return 1.0f; + } + + final int left = getChildAt(0).getLeft(); + final int paddingLeft = getPaddingLeft(); + + final float length = (float) getHorizontalFadingEdgeLength(); + + return (left < paddingLeft ? (float) -(left - paddingLeft) / length : fadingEdge); + } + } + + @Override + protected float getRightFadingEdgeStrength() { + if (mIsVertical) { + return 0f; + } + + final float fadingEdge = super.getRightFadingEdgeStrength(); + + final int childCount = getChildCount(); + if (childCount == 0) { + return fadingEdge; + } else { + if (mFirstPosition + childCount - 1 < mItemCount - 1) { + return 1.0f; + } + + final int right = getChildAt(childCount - 1).getRight(); + final int paddingRight = getPaddingRight(); + + final int width = getWidth(); + final float length = (float) getHorizontalFadingEdgeLength(); + + return (right > width - paddingRight ? + (float) (right - width + paddingRight) / length : fadingEdge); + } + } + + @Override protected int computeVerticalScrollExtent() { final int count = getChildCount(); if (count == 0) { return 0; } int extent = count * 100; @@ -1809,17 +1913,17 @@ public class TwoWayView extends AdapterV if (nextPage < 0) { return false; } final int position = lookForSelectablePosition(nextPage, forward); if (position >= 0) { mLayoutMode = LAYOUT_SPECIFIC; - mSpecificStart = (mIsVertical ? getPaddingTop() : getPaddingLeft()); + mSpecificStart = getStartEdge() + getFadingEdgeLength(); if (forward && position > mItemCount - getChildCount()) { mLayoutMode = LAYOUT_FORCE_BOTTOM; } if (!forward && position < getChildCount()) { mLayoutMode = LAYOUT_FORCE_TOP; } @@ -2068,28 +2172,32 @@ public class TwoWayView extends AdapterV final View newFocus; final int searchPoint; if (selectedView != null && selectedView.hasFocus()) { View oldFocus = selectedView.findFocus(); newFocus = FocusFinder.getInstance().findNextFocus(this, oldFocus, direction); } else { if (direction == View.FOCUS_DOWN || direction == View.FOCUS_RIGHT) { - final int start = getStartEdge(); + boolean fadingEdgeShowing = (mFirstPosition > 0); + final int start = getStartEdge() + + (fadingEdgeShowing ? getArrowScrollPreviewLength() : 0); final int selectedStart; if (selectedView != null) { selectedStart = getChildStartEdge(selectedView); } else { selectedStart = start; } searchPoint = Math.max(selectedStart, start); } else { - final int end = getEndEdge(); + final boolean fadingEdgeShowing = + (mFirstPosition + getChildCount() - 1) < mItemCount; + final int end = getEndEdge() - (fadingEdgeShowing ? getArrowScrollPreviewLength() : 0); final int selectedEnd; if (selectedView != null) { selectedEnd = getChildEndEdge(selectedView); } else { selectedEnd = end; } @@ -2152,22 +2260,17 @@ public class TwoWayView extends AdapterV public int getMaxScrollAmount() { return (int) (MAX_SCROLL_FACTOR * getSize()); } /** * @return The amount to preview next items when arrow scrolling. */ private int getArrowScrollPreviewLength() { - // FIXME: TwoWayView has no fading edge support just yet but using it - // makes it convenient for defining the next item's previous length. - int fadingEdgeLength = - (mIsVertical ? getVerticalFadingEdgeLength() : getHorizontalFadingEdgeLength()); - - return mItemMargin + Math.max(MIN_SCROLL_PREVIEW_PIXELS, fadingEdgeLength); + return mItemMargin + Math.max(MIN_SCROLL_PREVIEW_PIXELS, getFadingEdgeLength()); } /** * @param newFocus The view that would have focus. * @return the position that contains newFocus */ private int positionOfNewFocus(View newFocus) { final int numChildren = getChildCount(); @@ -2953,16 +3056,40 @@ public class TwoWayView extends AdapterV private int getChildSize(View child) { return (mIsVertical ? child.getHeight() : child.getWidth()); } private int getChildMeasuredSize(View child) { return (mIsVertical ? child.getMeasuredHeight() : child.getMeasuredWidth()); } + private int getFadingEdgeLength() { + return (mIsVertical ? getVerticalFadingEdgeLength() : getHorizontalFadingEdgeLength()); + } + + private int getMinSelectionPixel(int start, int fadingEdgeLength, int selectedPosition) { + // First pixel we can draw the selection into. + int selectionPixelStart = start; + if (selectedPosition > 0) { + selectionPixelStart += fadingEdgeLength; + } + + return selectionPixelStart; + } + + private int getMaxSelectionPixel(int end, int fadingEdgeLength, + int selectedPosition) { + int selectionPixelEnd = end; + if (selectedPosition != mItemCount - 1) { + selectionPixelEnd -= fadingEdgeLength; + } + + return selectionPixelEnd; + } + private boolean contentFits() { final int childCount = getChildCount(); if (childCount == 0) { return true; } if (childCount != mItemCount) { return false; @@ -4186,21 +4313,25 @@ public class TwoWayView extends AdapterV } else { child.offsetLeftAndRight(offset); } } } private View moveSelection(View oldSelected, View newSelected, int delta, int start, int end) { + final int fadingEdgeLength = getFadingEdgeLength(); final int selectedPosition = mSelectedPosition; final int oldSelectedStart = getChildStartEdge(oldSelected); final int oldSelectedEnd = getChildEndEdge(oldSelected); + final int minStart = getMinSelectionPixel(start, fadingEdgeLength, selectedPosition); + final int maxEnd = getMaxSelectionPixel(end, fadingEdgeLength, selectedPosition); + View selected = null; if (delta > 0) { /* * Case 1: Scrolling down. */ /* @@ -4228,20 +4359,20 @@ public class TwoWayView extends AdapterV selected = makeAndAddView(selectedPosition, oldSelectedEnd + itemMargin, true, true); final int selectedStart = getChildStartEdge(selected); final int selectedEnd = getChildEndEdge(selected); // Some of the newly selected item extends below the bottom of the list if (selectedEnd > end) { // Find space available above the selection into which we can scroll upwards - final int spaceBefore = selectedStart - start; + final int spaceBefore = selectedStart - minStart; // Find space required to bring the bottom of the selected item fully into view - final int spaceAfter = selectedEnd - end; + final int spaceAfter = selectedEnd - maxEnd; // Don't scroll more than half the size of the list final int halfSpace = (end - start) / 2; int offset = Math.min(spaceBefore, spaceAfter); offset = Math.min(offset, halfSpace); if (mIsVertical) { oldSelected.offsetTopAndBottom(-offset); @@ -4286,22 +4417,22 @@ public class TwoWayView extends AdapterV // it above the oldSelected (B) selected = makeAndAddView(selectedPosition, oldSelectedStart, false, true); } final int selectedStart = getChildStartEdge(selected); final int selectedEnd = getChildEndEdge(selected); // Some of the newly selected item extends above the top of the list - if (selectedStart < start) { + if (selectedStart < minStart) { // Find space required to bring the top of the selected item fully into view - final int spaceBefore = start - selectedStart; + final int spaceBefore = minStart - selectedStart; // Find space available below the selection into which we can scroll downwards - final int spaceAfter = end - selectedEnd; + final int spaceAfter = maxEnd - selectedEnd; // Don't scroll more than half the height of the list final int halfSpace = (end - start) / 2; int offset = Math.min(spaceBefore, spaceAfter); offset = Math.min(offset, halfSpace); if (mIsVertical) { selected.offsetTopAndBottom(offset); @@ -4510,59 +4641,80 @@ public class TwoWayView extends AdapterV final int childCount = getChildCount(); if (childCount <= 0) { return false; } int selectedStart = 0; int selectedPosition; - final int start = getStartEdge(); - final int end = getEndEdge(); + int start = getStartEdge(); + int end = getEndEdge(); final int firstPosition = mFirstPosition; final int toPosition = mResurrectToPosition; boolean down = true; if (toPosition >= firstPosition && toPosition < firstPosition + childCount) { selectedPosition = toPosition; final View selected = getChildAt(selectedPosition - mFirstPosition); selectedStart = getChildStartEdge(selected); + + final int selectedEnd = getChildEndEdge(selected); + + // We are scrolled, don't get in the fade + if (selectedStart < start) { + selectedStart = start + getFadingEdgeLength(); + } else if (selectedEnd > end) { + selectedStart = end - getChildMeasuredSize(selected) - getFadingEdgeLength(); + } } else if (toPosition < firstPosition) { // Default to selecting whatever is first selectedPosition = firstPosition; for (int i = 0; i < childCount; i++) { final View child = getChildAt(i); final int childStart = getChildStartEdge(child); if (i == 0) { // Remember the position of the first item selectedStart = childStart; + + // See if we are scrolled at all + if (firstPosition > 0 || childStart < start) { + // If we are scrolled, don't select anything that is + // in the fade region + start += getFadingEdgeLength(); + } } if (childStart >= start) { // Found a view whose top is fully visible selectedPosition = firstPosition + i; selectedStart = childStart; break; } } } else { + final int itemCount = mItemCount; selectedPosition = firstPosition + childCount - 1; down = false; for (int i = childCount - 1; i >= 0; i--) { final View child = getChildAt(i); final int childStart = getChildStartEdge(child); final int childEnd = getChildEndEdge(child); if (i == childCount - 1) { selectedStart = childStart; + + if (firstPosition + childCount < itemCount || childEnd > end) { + end -= getFadingEdgeLength(); + } } if (childEnd <= end) { selectedPosition = firstPosition + i; selectedStart = childStart; break; } } @@ -5088,45 +5240,49 @@ public class TwoWayView extends AdapterV adjustViewsStartOrEnd(); final int offsetAfter = getChildEndEdge(selected) + mItemMargin; fillAfter(position + 1, offsetAfter); } private View fillFromSelection(int selectedTop, int start, int end) { + int fadingEdgeLength = getFadingEdgeLength(); final int selectedPosition = mSelectedPosition; + final int minStart = getMinSelectionPixel(start, fadingEdgeLength, selectedPosition); + final int maxEnd = getMaxSelectionPixel(end, fadingEdgeLength, selectedPosition); + View selected = makeAndAddView(selectedPosition, selectedTop, true, true); final int selectedStart = getChildStartEdge(selected); final int selectedEnd = getChildEndEdge(selected); // Some of the newly selected item extends below the bottom of the list - if (selectedEnd > end) { + if (selectedEnd > maxEnd) { // Find space available above the selection into which we can scroll // upwards - final int spaceAbove = selectedStart - start; + final int spaceAbove = selectedStart - minStart; // Find space required to bring the bottom of the selected item // fully into view - final int spaceBelow = selectedEnd - end; + final int spaceBelow = selectedEnd - maxEnd; final int offset = Math.min(spaceAbove, spaceBelow); // Now offset the selected item to get it into view selected.offsetTopAndBottom(-offset); - } else if (selectedStart < start) { + } else if (selectedStart < minStart) { // Find space required to bring the top of the selected item fully // into view - final int spaceAbove = start - selectedStart; + final int spaceAbove = minStart - selectedStart; // Find space available below the selection into which we can scroll // downwards - final int spaceBelow = end - selectedEnd; + final int spaceBelow = maxEnd - selectedEnd; final int offset = Math.min(spaceAbove, spaceBelow); // Offset the selected item to get it into view selected.offsetTopAndBottom(offset); } // Fill in views above and below
--- a/mobile/android/chrome/content/WebcompatReporter.js +++ b/mobile/android/chrome/content/WebcompatReporter.js @@ -34,17 +34,18 @@ var WebcompatReporter = { this.menuItemEnabled = true; } else if (this.menuItemEnabled && !this.isReportableUrl(currentURI)) { NativeWindow.menu.update(this.menuItem, {enabled: false}); this.menuItemEnabled = false; } } else if (topic === "DesktopMode:Change") { let args = JSON.parse(data); let tab = BrowserApp.getTabForId(args.tabId); - if (args.desktopMode && tab !== null) { + let currentURI = tab.browser.currentURI.spec; + if (args.desktopMode && this.isReportableUrl(currentURI)) { this.reportDesktopModePrompt(); } } }, addMenuItem: function() { this.menuItem = NativeWindow.menu.add({ name: this.strings.GetStringFromName("webcompat.menu.name"), @@ -52,20 +53,20 @@ var WebcompatReporter = { let currentURI = BrowserApp.selectedTab.browser.currentURI.spec; this.reportIssue(currentURI); }, enabled: false, }); }, isReportableUrl: function(url) { - return url !== null && !(url.startsWith("about") || - url.startsWith("chrome") || - url.startsWith("file") || - url.startsWith("resource")); + return url && !(url.startsWith("about") || + url.startsWith("chrome") || + url.startsWith("file") || + url.startsWith("resource")); }, reportDesktopModePrompt: function() { let currentURI = BrowserApp.selectedTab.browser.currentURI.spec; let message = this.strings.GetStringFromName("webcompat.reportDesktopMode.message"); let options = { button: { label: this.strings.GetStringFromName("webcompat.reportDesktopModeYes.label"),
--- a/mobile/android/locales/en-US/chrome/aboutHome.dtd +++ b/mobile/android/locales/en-US/chrome/aboutHome.dtd @@ -1,5 +1,7 @@ <!-- 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/. --> +<!-- This string should be kept in sync with the home_title string + in android_strings.dtd --> <!ENTITY abouthome.title "&brandShortName; Home">
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -464,16 +464,21 @@ pref("apz.axis_lock.direct_pan_angle", " pref("apz.content_response_timeout", 300); pref("apz.cross_slide.enabled", false); pref("apz.danger_zone_x", 50); pref("apz.danger_zone_y", 100); pref("apz.enlarge_displayport_when_clipped", false); pref("apz.fling_accel_base_mult", "1.0"); pref("apz.fling_accel_interval_ms", 500); pref("apz.fling_accel_supplemental_mult", "1.0"); +pref("apz.fling_curve_function_x1", "0.0"); +pref("apz.fling_curve_function_y1", "0.0"); +pref("apz.fling_curve_function_x2", "1.0"); +pref("apz.fling_curve_function_y2", "1.0"); +pref("apz.fling_curve_threshold_inches_per_ms", "-1.0"); pref("apz.fling_friction", "0.002"); pref("apz.fling_stop_on_tap_threshold", "0.05"); pref("apz.fling_stopped_threshold", "0.01"); pref("apz.max_velocity_inches_per_ms", "-1.0"); pref("apz.max_velocity_queue_size", 5); pref("apz.min_skate_speed", "1.0"); pref("apz.num_paint_duration_samples", 3); pref("apz.overscroll.enabled", false);
--- a/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc +++ b/toolkit/crashreporter/google-breakpad/src/common/linux/dump_symbols.cc @@ -719,81 +719,76 @@ bool LoadSymbols(const string& obj_file, // Failed, but maybe there's a .gnu_debuglink section? if (read_gnu_debug_link) { const Shdr* gnu_debuglink_section = FindElfSectionByName<ElfClass>(".gnu_debuglink", SHT_PROGBITS, sections, names, names_end, elf_header->e_shnum); if (gnu_debuglink_section) { if (!info->debug_dirs().empty()) { + found_debug_info_section = true; + const char* debuglink_contents = GetOffset<ElfClass, char>(elf_header, gnu_debuglink_section->sh_offset); string debuglink_file = ReadDebugLink<ElfClass>(debuglink_contents, gnu_debuglink_section->sh_size, obj_file, info->debug_dirs()); info->set_debuglink_file(debuglink_file); } else { fprintf(stderr, ".gnu_debuglink section found in '%s', " "but no debug path specified.\n", obj_file.c_str()); } } else { fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n", obj_file.c_str()); } - } else { - if (symbol_data != ONLY_CFI) { - // The caller doesn't want to consult .gnu_debuglink. - // See if there are export symbols available. - const Shdr* dynsym_section = - FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM, - sections, names, names_end, - elf_header->e_shnum); - const Shdr* dynstr_section = - FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB, - sections, names, names_end, - elf_header->e_shnum); - if (dynsym_section && dynstr_section) { - info->LoadedSection(".dynsym"); - - const uint8_t* dynsyms = - GetOffset<ElfClass, uint8_t>(elf_header, - dynsym_section->sh_offset); - const uint8_t* dynstrs = - GetOffset<ElfClass, uint8_t>(elf_header, - dynstr_section->sh_offset); - bool result = - ELFSymbolsToModule(dynsyms, - dynsym_section->sh_size, - dynstrs, - dynstr_section->sh_size, - big_endian, - ElfClass::kAddrSize, - module); - found_usable_info = found_usable_info || result; - } - } - - // Return true if some usable information was found, since - // the caller doesn't want to use .gnu_debuglink. - BPLOG(INFO) << "LoadSymbols: " - << (found_usable_info ? "SUCCESS " : "FAILURE ") - << obj_file; - return found_usable_info; } - - // No debug info was found, let the user try again with .gnu_debuglink - // if present. - BPLOG(INFO) << "LoadSymbols: FAILURE " << obj_file; - return false; } - BPLOG(INFO) << "LoadSymbols: SUCCESS " << obj_file; - return true; + if (symbol_data != ONLY_CFI) { + const Shdr* dynsym_section = + FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM, + sections, names, names_end, + elf_header->e_shnum); + const Shdr* dynstr_section = + FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB, + sections, names, names_end, + elf_header->e_shnum); + if (dynsym_section && dynstr_section) { + info->LoadedSection(".dynsym"); + + const uint8_t* dynsyms = + GetOffset<ElfClass, uint8_t>(elf_header, + dynsym_section->sh_offset); + const uint8_t* dynstrs = + GetOffset<ElfClass, uint8_t>(elf_header, + dynstr_section->sh_offset); + bool result = + ELFSymbolsToModule(dynsyms, + dynsym_section->sh_size, + dynstrs, + dynstr_section->sh_size, + big_endian, + ElfClass::kAddrSize, + module); + found_usable_info = found_usable_info || result; + } + } + + if (read_gnu_debug_link) { + return found_debug_info_section; + } + + // Return true if some usable information was found + BPLOG(INFO) << "LoadSymbols: " + << (found_usable_info ? "SUCCESS " : "FAILURE ") + << obj_file; + return found_usable_info; } // Return the breakpad symbol file identifier for the architecture of // ELF_HEADER. template<typename ElfClass> const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) { typedef typename ElfClass::Half Half; Half arch = elf_header->e_machine;
--- a/toolkit/crashreporter/google-breakpad/src/common/module.cc +++ b/toolkit/crashreporter/google-breakpad/src/common/module.cc @@ -100,20 +100,31 @@ void Module::AddStackFrameEntry(StackFra if (!ret.second) { // Free the duplicate that was not inserted because this Module // now owns it. delete stack_frame_entry; } } void Module::AddExtern(Extern *ext) { - std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext); - if (!ret.second) { - // Free the duplicate that was not inserted because this Module - // now owns it. + Function func; + func.name = ext->name; + func.address = ext->address; + + // Since parsing debug section and public info are not necessarily + // mutually exclusive, check if the symbol has already been read + // as a function to avoid duplicates. + if (functions_.find(&func) == functions_.end()) { + std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext); + if (!ret.second) { + // Free the duplicate that was not inserted because this Module + // now owns it. + delete ext; + } + } else { delete ext; } } void Module::GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i) { vec->insert(i, functions_.begin(), functions_.end()); }
--- a/toolkit/devtools/server/protocol.js +++ b/toolkit/devtools/server/protocol.js @@ -149,24 +149,37 @@ types.addType = function(name, typeObjec name: name, primitive: !(typeObject.read || typeObject.write), read: identityWrite, write: identityWrite }, typeObject); registeredTypes.set(name, type); - if (!options.thawed) { - Object.freeze(type); - } - return type; }; /** + * Remove a type previously registered with the system. + * Primarily useful for types registered by addons. + */ +types.removeType = function(name) { + // This type may still be referenced by other types, make sure + // those references don't work. + let type = registeredTypes.get(name); + + type.name = "DEFUNCT:" + name; + type.category = "defunct"; + type.primitive = false; + type.read = type.write = function() { throw new Error("Using defunct type: " + name); }; + + registeredTypes.delete(name); +} + +/** * Add an array type to the type system. * * getType() will call this function if provided an "array:<type>" * typestring. * * @param type subtype * The subtype to be held by the array. */ @@ -294,20 +307,16 @@ types.addActorType = function(name) { } if (!(formAttr in type.actorSpec)) { throw new Error("No type defined for " + formAttr); } return type.actorSpec[formAttr]; } - }, { - // We usually freeze types, but actor types are updated when clients are - // created, so don't freeze yet. - thawed: true }); return type; } types.addNullableType = function(subtype) { subtype = types.getType(subtype); return types.addType("nullable:" + subtype.name, { category: "nullable", @@ -365,16 +374,24 @@ types.addActorDetail = function(name, ac types.addLifetime = function(name, prop) { if (registeredLifetimes.has(name)) { throw Error("Lifetime '" + name + "' already registered."); } registeredLifetimes.set(name, prop); } /** + * Remove a previously-registered lifetime. Useful for lifetimes registered + * in addons. + */ +types.removeLifetime = function(name) { + registeredLifetimes.delete(name); +} + +/** * Register a lifetime type. This creates an actor type tied to the given * lifetime. * * This is called by getType() when passed a '<lifetimeType>:<actorType>' * typestring. * * @param string lifetime * A lifetime string previously regisered with addLifetime()
new file mode 100644 --- /dev/null +++ b/toolkit/devtools/server/tests/unit/test_protocol_unregister.js @@ -0,0 +1,44 @@ +const {types} = devtools.require("devtools/server/protocol"); + + +function run_test() +{ + types.addType("test", { + read: (v) => { return "successful read: " + v }, + write: (v) => { return "successful write: " + v } + }); + + // Verify the type registered correctly. + + let type = types.getType("test"); + let arrayType = types.getType("array:test"); + do_check_eq(type.read("foo"), "successful read: foo"); + do_check_eq(arrayType.read(["foo"])[0], "successful read: foo"); + + types.removeType("test"); + + do_check_eq(type.name, "DEFUNCT:test"); + try { + types.getType("test"); + do_check_true(false, "getType should fail"); + } catch(ex) { + do_check_eq(ex.toString(), "Error: Unknown type: test"); + } + + try { + type.read("foo"); + do_check_true(false, "type.read should have thrown an exception."); + } catch(ex) { + do_check_eq(ex.toString(), "Error: Using defunct type: test"); + } + + try { + arrayType.read(["foo"]); + do_check_true(false, "array:test.read should have thrown an exception."); + } catch(ex) { + do_check_eq(ex.toString(), "Error: Using defunct type: test"); + } + +} + +
--- a/toolkit/devtools/server/tests/unit/xpcshell.ini +++ b/toolkit/devtools/server/tests/unit/xpcshell.ini @@ -57,20 +57,21 @@ support-files = [test_nativewrappers.js] [test_nodelistactor.js] [test_eval-01.js] [test_eval-02.js] [test_eval-03.js] [test_eval-04.js] [test_eval-05.js] [test_protocol_async.js] -[test_protocol_simple.js] -[test_protocol_longstring.js] [test_protocol_children.js] [test_protocol_formtype.js] +[test_protocol_longstring.js] +[test_protocol_simple.js] +[test_protocol_unregister.js] [test_breakpoint-01.js] [test_register_actor.js] skip-if = toolkit == "gonk" reason = bug 820380 [test_breakpoint-02.js] skip-if = toolkit == "gonk" reason = bug 820380 [test_breakpoint-03.js]
--- a/toolkit/modules/GMPInstallManager.jsm +++ b/toolkit/modules/GMPInstallManager.jsm @@ -50,16 +50,26 @@ XPCOMUtils.defineLazyGetter(this, "gCert let temp = { }; Cu.import("resource://gre/modules/CertUtils.jsm", temp); return temp; }); XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel", "resource://gre/modules/UpdateChannel.jsm"); +/** + * Number of milliseconds after which we need to cancel `checkForAddons`. + * + * Bug 1087674 suggests that the XHR we use in `checkForAddons` may + * never terminate in presence of network nuisances (e.g. strange + * antivirus behavior). This timeout is a defensive measure to ensure + * that we fail cleanly in such case. + */ +const CHECK_FOR_ADDONS_TIMEOUT_DELAY_MS = 20000; + function getScopedLogger(prefix) { // `PARENT_LOGGER_ID.` being passed here effectively links this logger // to the parentLogger. return Log.repository.getLogger(PARENT_LOGGER_ID + "." + prefix); } /** * Manages preferences for GMP addons @@ -364,18 +374,21 @@ GMPInstallManager.prototype = { // The Cache-Control header is only interpreted by proxies and the // final destination. It does not help if a resource is already // cached locally. this._request.setRequestHeader("Cache-Control", "no-cache"); // HTTP/1.0 servers might not implement Cache-Control and // might only implement Pragma: no-cache this._request.setRequestHeader("Pragma", "no-cache"); - this._request.addEventListener("error", this.onErrorXML.bind(this) ,false); - this._request.addEventListener("load", this.onLoadXML.bind(this), false); + this._request.timeout = CHECK_FOR_ADDONS_TIMEOUT_DELAY_MS; + this._request.addEventListener("error", event => this.onFailXML("onErrorXML", event), false); + this._request.addEventListener("abort", event => this.onFailXML("onAbortXML", event), false); + this._request.addEventListener("timeout", event => this.onFailXML("onTimeoutXML", event), false); + this._request.addEventListener("load", event => this.onLoadXML(event), false); log.info("sending request to: " + url); this._request.send(null); return this._deferred.promise; }, /** * Installs the specified addon and calls a callback when done. @@ -501,60 +514,73 @@ GMPInstallManager.prototype = { overrideLeaveDownloadedZip: false, /** * The XMLHttpRequest succeeded and the document was loaded. * @param event The nsIDOMEvent for the load */ onLoadXML: function(event) { let log = getScopedLogger("onLoadXML"); - log.info("request completed downloading document"); + try { + log.info("request completed downloading document"); + let certs = null; + if (!Services.prefs.prefHasUserValue(GMPPrefs.KEY_URL_OVERRIDE) && + GMPPrefs.get(GMPPrefs.KEY_CERT_CHECKATTRS, undefined, true)) { + certs = gCertUtils.readCertPrefs(GMPPrefs.CERTS_BRANCH); + } + + let allowNonBuiltIn = !GMPPrefs.get(GMPPrefs.KEY_CERT_REQUIREBUILTIN, + undefined, true); + log.info("allowNonBuiltIn: " + allowNonBuiltIn); - let certs = null; - if (!Services.prefs.prefHasUserValue(GMPPrefs.KEY_URL_OVERRIDE) && - GMPPrefs.get(GMPPrefs.KEY_CERT_CHECKATTRS, undefined, true)) { - certs = gCertUtils.readCertPrefs(GMPPrefs.CERTS_BRANCH); + gCertUtils.checkCert(this._request.channel, allowNonBuiltIn, certs); + + this.parseResponseXML(); + } catch (ex) { + log.error("could not load xml: " + ex); + this._deferred.reject({ + target: event.target, + status: this._getChannelStatus(event.target), + message: "" + ex, + }); + delete this._deferred; } - - let allowNonBuiltIn = !GMPPrefs.get(GMPPrefs.KEY_CERT_REQUIREBUILTIN, - undefined, true); - log.info("allowNonBuiltIn: " + allowNonBuiltIn); - gCertUtils.checkCert(this._request.channel, allowNonBuiltIn, certs); - - this.parseResponseXML(); }, /** * Returns the status code for the XMLHttpRequest */ _getChannelStatus: function(request) { let log = getScopedLogger("_getChannelStatus"); - let status = 0; + let status = null; try { status = request.status; log.info("request.status is: " + request.status); } catch (e) { } - if (status == 0) { + if (status == null) { status = request.channel.QueryInterface(Ci.nsIRequest).status; } return status; }, /** - * There was an error of some kind during the XMLHttpRequest + * There was an error of some kind during the XMLHttpRequest. This + * error may have been caused by external factors (e.g. network + * issues) or internally (by a timeout). + * * @param event The nsIDOMEvent for the error - */ - onErrorXML: function(event) { - let log = getScopedLogger("onErrorXML"); + */ + onFailXML: function(failure, event) { + let log = getScopedLogger(failure); let request = event.target; let status = this._getChannelStatus(request); - let message = "request.status: " + status; + let message = "request.status: " + status + "(" + event.type + ")"; log.warn(message); this._deferred.reject({ target: request, status: status, message: message }); delete this._deferred; },
--- a/toolkit/modules/tests/xpcshell/test_GMPInstallManager.js +++ b/toolkit/modules/tests/xpcshell/test_GMPInstallManager.js @@ -139,16 +139,85 @@ add_test(function test_checkForAddons_40 }, function(err) { do_check_true(!!err); do_check_eq(err.status, 404); installManager.uninit(); run_next_test(); }); }); +/** + * Tests that a xhr abort() works as expected + */ +add_test(function test_checkForAddons_abort() { + let xhr = overrideXHR(200, "", { dropRequest: true} ); + let installManager = new GMPInstallManager(); + let promise = installManager.checkForAddons(); + xhr.abort(); + promise.then(function() { + do_throw("abort() should reject"); + }, function(err) { + do_check_eq(err.status, 0); + installManager.uninit(); + run_next_test(); + }); +}); + +/** + * Tests that a defensive timeout works as expected + */ +add_test(function test_checkForAddons_timeout() { + overrideXHR(200, "", { dropRequest: true, timeout: true }); + let installManager = new GMPInstallManager(); + let promise = installManager.checkForAddons(); + promise.then(function() { + do_throw("Defensive timeout should reject"); + }, function(err) { + do_check_eq(err.status, 0); + installManager.uninit(); + run_next_test(); + }); +}); + +/** + * Tests that we throw correctly in case of ssl certification error. + */ +add_test(function test_checkForAddons_bad_ssl() { + // + // Add random stuff that cause CertUtil to require https. + // + let PREF_KEY_URL_OVERRIDE_BACKUP = + Preferences.get(GMPPrefs.KEY_URL_OVERRIDE, undefined); + Preferences.reset(GMPPrefs.KEY_URL_OVERRIDE); + + let CERTS_BRANCH_DOT_ONE = GMPPrefs.CERTS_BRANCH + ".1"; + let PREF_CERTS_BRANCH_DOT_ONE_BACKUP = + Preferences.get(CERTS_BRANCH_DOT_ONE, undefined); + Services.prefs.setCharPref(CERTS_BRANCH_DOT_ONE, "funky value"); + + + overrideXHR(200, ""); + let installManager = new GMPInstallManager(); + let promise = installManager.checkForAddons(); + promise.then(function() { + do_throw("Defensive timeout should reject"); + }, function(err) { + do_check_true(err.message.contains("SSL is required and URI scheme is not https.")); + installManager.uninit(); + if (PREF_KEY_URL_OVERRIDE_BACKUP) { + Preferences.set(GMPPrefs.KEY_URL_OVERRIDE, + PREF_KEY_URL_OVERRIDE_BACKUP); + } + if (PREF_CERTS_BRANCH_DOT_ONE_BACKUP) { + Preferences.set(CERTS_BRANCH_DOT_ONE, + PREF_CERTS_BRANCH_DOT_ONE_BACKUP); + } + run_next_test(); + }); +}); /** * Tests that gettinga a funky non XML response works as expected */ add_test(function test_checkForAddons_notXML() { overrideXHR(200, "3.141592653589793...."); let installManager = new GMPInstallManager(); let promise = installManager.checkForAddons(); @@ -595,65 +664,110 @@ function makeHandler(aVal) { if (typeof aVal == "function") return { handleEvent: aVal }; return aVal; } /** * Constructs a mock xhr which is used for testing different aspects * of responses. */ -function xhr(inputStatus, inputResponse) { +function xhr(inputStatus, inputResponse, options) { this.inputStatus = inputStatus; this.inputResponse = inputResponse; + this.status = 0; + this.responseXML = null; + this._aborted = false; + this._onabort = null; + this._onprogress = null; + this._onerror = null; + this._onload = null; + this._onloadend = null; + this._ontimeout = null; + this._url = null; + this._method = null; + this._timeout = 0; + this._notified = false; + this._options = options || {}; } xhr.prototype = { overrideMimeType: function(aMimetype) { }, setRequestHeader: function(aHeader, aValue) { }, status: null, channel: { set notificationCallbacks(aVal) { } }, - _url: null, - _method: null, open: function(aMethod, aUrl) { this.channel.originalURI = Services.io.newURI(aUrl, null, null); this._method = aMethod; this._url = aUrl; }, abort: function() { + this._dropRequest = true; + this._notify(["abort", "loadend"]); }, responseXML: null, responseText: null, send: function(aBody) { - let self = this; do_execute_soon(function() { - self.status = self.inputStatus; - self.responseText = self.inputResponse; try { - let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. - createInstance(Ci.nsIDOMParser); - self.responseXML = parser.parseFromString(self.inputResponse, - "application/xml"); - } catch (e) { - self.responseXML = null; + if (this._options.dropRequest) { + if (this._timeout > 0 && this._options.timeout) { + this._notify(["timeout", "loadend"]); + } + return; + } + this.status = this.inputStatus; + this.responseText = this.inputResponse; + try { + let parser = Cc["@mozilla.org/xmlextras/domparser;1"]. + createInstance(Ci.nsIDOMParser); + this.responseXML = parser.parseFromString(this.inputResponse, + "application/xml"); + } catch (e) { + this.responseXML = null; + } + if (this.inputStatus === 200) { + this._notify(["load", "loadend"]); + } else { + this._notify(["error", "loadend"]); + } + } catch (ex) { + do_throw(ex); } - let e = { target: self }; - if (self.inputStatus === 200) { - self.onload(e); - } else { - self.onerror(e); - } - }); + }.bind(this)); }, - _onprogress: null, + set onabort(aValue) { this._onabort = makeHandler(aValue); }, + get onabort() { return this._onabort; }, set onprogress(aValue) { this._onprogress = makeHandler(aValue); }, get onprogress() { return this._onprogress; }, - _onerror: null, set onerror(aValue) { this._onerror = makeHandler(aValue); }, get onerror() { return this._onerror; }, - _onload: null, set onload(aValue) { this._onload = makeHandler(aValue); }, get onload() { return this._onload; }, + set onloadend(aValue) { this._onloadend = makeHandler(aValue); }, + get onloadend() { return this._onloadend; }, + set ontimeout(aValue) { this._ontimeout = makeHandler(aValue); }, + get ontimeout() { return this._ontimeout; }, + set timeout(aValue) { this._timeout = aValue; }, + _notify: function(events) { + if (this._notified) { + return; + } + this._notified = true; + for (let item of events) { + let k = "on" + item; + if (this[k]) { + do_print("Notifying " + item); + let e = { + target: this, + type: item, + }; + this[k](e); + } else { + do_print("Notifying " + item + ", but there are no listeners"); + } + } + }, addEventListener: function(aEvent, aValue, aCapturing) { eval("this._on" + aEvent + " = aValue"); }, flags: Ci.nsIClassInfo.SINGLETON, implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT, getHelperForLanguage: function(aLanguage) null, getInterfaces: function(aCount) { let interfaces = [Ci.nsISupports]; @@ -678,26 +792,27 @@ xhr.prototype = { }; /** * Helper used to overrideXHR requests (no matter to what URL) with the * specified status and response. * @param status The status you want to get back when an XHR request is made * @param response The response you want to get back when an XHR request is made */ -function overrideXHR(status, response) { +function overrideXHR(status, response, options) { let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); if (overrideXHR.myxhr) { registrar.unregisterFactory(overrideXHR.myxhr.classID, overrideXHR.myxhr); } - overrideXHR.myxhr = new xhr(status, response); + overrideXHR.myxhr = new xhr(status, response, options); registrar.registerFactory(overrideXHR.myxhr.classID, overrideXHR.myxhr.classDescription, overrideXHR.myxhr.contractID, overrideXHR.myxhr); + return overrideXHR.myxhr; } /** * Compares binary data of 2 arrays and returns true if they are the same * * @param arr1 The first array to compare * @param arr2 The second array to compare */
--- a/toolkit/mozapps/extensions/AddonManager.jsm +++ b/toolkit/mozapps/extensions/AddonManager.jsm @@ -2413,21 +2413,21 @@ this.AddonManagerPrivate = { }, backgroundUpdateCheck: function AMP_backgroundUpdateCheck() { return AddonManagerInternal.backgroundUpdateCheck(); }, backgroundUpdateTimerHandler() { // Don't call through to the real update check if no checks are enabled. - let checkHotfix = this.hotfixID && + let checkHotfix = AddonManagerInternal.hotfixID && Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED) && Services.prefs.getBoolPref(PREF_APP_UPDATE_AUTO); - if (!this.updateEnabled && !checkHotfix) { + if (!AddonManagerInternal.updateEnabled && !checkHotfix) { logger.info("Skipping background update check"); return; } // Don't return the promise here, since the caller doesn't care. AddonManagerInternal.backgroundUpdateCheck(); }, addStartupChange: function AMP_addStartupChange(aType, aID) {
--- a/toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_backgroundupdate.js @@ -39,17 +39,18 @@ function run_test_1() { do_check_eq(aAddons.length, 0); Services.obs.addObserver(function() { Services.obs.removeObserver(arguments.callee, "addons-background-update-complete"); do_execute_soon(run_test_2); }, "addons-background-update-complete", false); - AddonManagerPrivate.backgroundUpdateCheck(); + // Trigger the background update timer handler + gInternalManager.notify(null); }); } // Verify that with two add-ons installed both of which claim to have updates // available we get the notification after both updates attempted to start function run_test_2() { writeInstallRDFForExtension({ id: "addon1@tests.mozilla.org", @@ -115,10 +116,11 @@ function run_test_2() { completeCount++; if (completeCount == 3) { do_check_true(sawCompleteNotification); end_test(); } } }); - AddonManagerPrivate.backgroundUpdateCheck(); + // Trigger the background update timer handler + gInternalManager.notify(null); }