Merge m-c to inbound, a=merge
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
@ -135,7 +135,7 @@
|
|||||||
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
|
<project groups="invensense" name="platform/hardware/invensense" path="hardware/invensense" revision="e6d9ab28b4f4e7684f6c07874ee819c9ea0002a2"/>
|
||||||
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
|
<project name="platform/hardware/ril" path="hardware/ril" revision="865ce3b4a2ba0b3a31421ca671f4d6c5595f8690"/>
|
||||||
<project name="kernel/common" path="kernel" revision="b698c5aa4e9393dfd70d0ea7a0bf93b333b54750"/>
|
<project name="kernel/common" path="kernel" revision="b698c5aa4e9393dfd70d0ea7a0bf93b333b54750"/>
|
||||||
<project name="platform/system/core" path="system/core" revision="4776448ebcd3f07d58b91503c478da9b54cb58a0"/>
|
<project name="platform/system/core" path="system/core" revision="1b888e1ae54c358246f13e4fb915ce43cde00691"/>
|
||||||
<project name="u-boot" path="u-boot" revision="f1502910977ac88f43da7bf9277c3523ad4b0b2f"/>
|
<project name="u-boot" path="u-boot" revision="f1502910977ac88f43da7bf9277c3523ad4b0b2f"/>
|
||||||
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="7d6e1269be7186b2073fa568958b357826692c4b"/>
|
<project name="vendor/sprd/gps" path="vendor/sprd/gps" revision="7d6e1269be7186b2073fa568958b357826692c4b"/>
|
||||||
<project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="295ff253b74353751a99aafd687196a28c84a58e"/>
|
<project name="vendor/sprd/open-source" path="vendor/sprd/open-source" revision="295ff253b74353751a99aafd687196a28c84a58e"/>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
</project>
|
</project>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="4ace9aaee0e048dfda11bb787646c59982a3dc80"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"git": {
|
"git": {
|
||||||
"git_revision": "8999f0ba6326d815c8366e3c1155b7e4e9763b40",
|
"git_revision": "f75a7e01912cee313fed92ff2089586f507b2ba5",
|
||||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||||
"branch": ""
|
"branch": ""
|
||||||
},
|
},
|
||||||
"revision": "983b7ecb17c67b9fb511f400bb5b28b9069eea00",
|
"revision": "f51f8770b9665f44e57e9e09faee2b967a80abf1",
|
||||||
"repo_path": "integration/gaia-central"
|
"repo_path": "integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
<project name="platform_build" path="build" remote="b2g" revision="8d83715f08b7849f16a0dfc88f78d5c3a89c0a54">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
<project name="moztt" path="external/moztt" remote="b2g" revision="31a7849fe9a8b743d6f5e5facc212f0ef9d57499"/>
|
||||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
|
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="0c28789b9957913be975eb002a22323f93585d4c"/>
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
<project name="platform_build" path="build" remote="b2g" revision="c9d4fe680662ee44a4bdea42ae00366f5df399cf">
|
||||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||||
</project>
|
</project>
|
||||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="8999f0ba6326d815c8366e3c1155b7e4e9763b40"/>
|
<project name="gaia" path="gaia" remote="mozillaorg" revision="f75a7e01912cee313fed92ff2089586f507b2ba5"/>
|
||||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||||
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
<project name="fake-qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="939b377d55a2f081d94029a30a75d05e5a20daf3"/>
|
||||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="7938df689aa87769fad3f2cf9097fb4ecb106a43"/>
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
"dot-location": [2, "property"],
|
"dot-location": [2, "property"],
|
||||||
"eol-last": 2,
|
"eol-last": 2,
|
||||||
"eqeqeq": [2, "smart"],
|
"eqeqeq": [2, "smart"],
|
||||||
|
"jsx-quotes": [2, "prefer-double"],
|
||||||
"key-spacing": [2, {"beforeColon": false, "afterColon": true }],
|
"key-spacing": [2, {"beforeColon": false, "afterColon": true }],
|
||||||
"linebreak-style": [2, "unix"],
|
"linebreak-style": [2, "unix"],
|
||||||
"new-cap": 0, // TODO: set to 2
|
"new-cap": 0, // TODO: set to 2
|
||||||
@ -106,7 +107,6 @@
|
|||||||
"yoda": [2, "never"],
|
"yoda": [2, "never"],
|
||||||
// eslint-plugin-react rules. These are documented at
|
// eslint-plugin-react rules. These are documented at
|
||||||
// <https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules>
|
// <https://github.com/yannickcr/eslint-plugin-react#list-of-supported-rules>
|
||||||
"react/jsx-quotes": [2, "double", "avoid-escape"],
|
|
||||||
"react/jsx-no-undef": 2,
|
"react/jsx-no-undef": 2,
|
||||||
"react/jsx-sort-props": 2,
|
"react/jsx-sort-props": 2,
|
||||||
"react/jsx-sort-prop-types": 2,
|
"react/jsx-sort-prop-types": 2,
|
||||||
|
@ -469,51 +469,6 @@ html, .fx-embedded, #main,
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.room-conversation-wrapper header {
|
|
||||||
background: #000;
|
|
||||||
height: 50px;
|
|
||||||
text-align: left;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[dir="rtl"] .room-conversation-wrapper header {
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-conversation-wrapper header h1 {
|
|
||||||
font-size: 1.5em;
|
|
||||||
color: #fff;
|
|
||||||
line-height: 50px;
|
|
||||||
text-indent: 40px;
|
|
||||||
background-image: url("../img/firefox-logo.png");
|
|
||||||
background-size: 30px;
|
|
||||||
background-position: 0 center;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[dir="rtl"] .room-conversation-wrapper header h1 {
|
|
||||||
background-position: 100% center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-conversation-wrapper header a {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
html[dir="rtl"] .room-conversation-wrapper header a {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-conversation-wrapper header .icon-help {
|
|
||||||
display: inline-block;
|
|
||||||
background-size: contain;
|
|
||||||
margin-top: 15px;
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
background: transparent url("../img/svg/glyph-help-16x16.svg") no-repeat;
|
|
||||||
}
|
|
||||||
|
|
||||||
.room-invitation-overlay {
|
.room-invitation-overlay {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: rgba(255, 255, 255, 0.85);
|
background: rgba(255, 255, 255, 0.85);
|
||||||
@ -676,12 +631,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.standalone-room-wrapper > .media-layout {
|
|
||||||
/* 50px is the header, 10px is the bottom margin. */
|
|
||||||
height: calc(100% - 50px - 10px);
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-layout > .media-wrapper {
|
.media-layout > .media-wrapper {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column wrap;
|
flex-flow: column wrap;
|
||||||
@ -797,11 +746,6 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width:640px) {
|
@media screen and (max-width:640px) {
|
||||||
.standalone-room-wrapper > .media-layout {
|
|
||||||
/* 50px is height of header, 10px is bottom margin. */
|
|
||||||
height: calc(100% - 50px - 10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-layout > .media-wrapper {
|
.media-layout > .media-wrapper {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -832,8 +776,8 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.media-wrapper > .focus-stream > .local ~ .conversation-toolbar {
|
.media-wrapper > .focus-stream > .local ~ .conversation-toolbar {
|
||||||
/* 22px are the margins, 120px is for the local video area. */
|
/* 120px is for the local video area. */
|
||||||
max-width: calc(100% - 22px - 120px);
|
max-width: calc(100% - 120px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-wrapper > .focus-stream > .local {
|
.media-wrapper > .focus-stream > .local {
|
||||||
@ -938,7 +882,7 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.media-wrapper > .focus-stream > .local ~ .conversation-toolbar {
|
.media-wrapper > .focus-stream > .local ~ .conversation-toolbar {
|
||||||
max-width: calc(75% - 22px);
|
max-width: 75%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-wrapper > .focus-stream > .local {
|
.media-wrapper > .focus-stream > .local {
|
||||||
@ -981,7 +925,7 @@ body[platform="win"] .share-service-dropdown.overflow > .dropdown-menu-item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.media-wrapper:not(.showing-remote-streams) > .focus-stream > .local ~ .conversation-toolbar {
|
.media-wrapper:not(.showing-remote-streams) > .focus-stream > .local ~ .conversation-toolbar {
|
||||||
max-width: calc(100% - 22px);
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-wrapper > .focus-stream {
|
.media-wrapper > .focus-stream {
|
||||||
@ -1247,8 +1191,7 @@ html[dir="rtl"] .text-chat-entry.received .text-chat-arrow {
|
|||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
.standalone .room-conversation-wrapper .video-layout-wrapper {
|
.standalone .room-conversation-wrapper .video-layout-wrapper {
|
||||||
/* 50px: header's height; 10px: bottom margin */
|
height: 100%;
|
||||||
height: calc(100% - 50px - 10px);
|
|
||||||
}
|
}
|
||||||
.standalone .room-conversation .video_wrapper.remote_wrapper {
|
.standalone .room-conversation .video_wrapper.remote_wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -1123,14 +1123,15 @@ loop.shared.views = (function(_, mozL10n) {
|
|||||||
srcMediaElement: this.props.remoteSrcMediaElement}),
|
srcMediaElement: this.props.remoteSrcMediaElement}),
|
||||||
this.state.localMediaAboslutelyPositioned ?
|
this.state.localMediaAboslutelyPositioned ?
|
||||||
this.renderLocalVideo() : null,
|
this.renderLocalVideo() : null,
|
||||||
this.props.children
|
this.props.displayScreenShare ? null : this.props.children
|
||||||
),
|
),
|
||||||
React.createElement("div", {className: screenShareStreamClasses},
|
React.createElement("div", {className: screenShareStreamClasses},
|
||||||
React.createElement(MediaView, {displayAvatar: false,
|
React.createElement(MediaView, {displayAvatar: false,
|
||||||
isLoading: this.props.isScreenShareLoading,
|
isLoading: this.props.isScreenShareLoading,
|
||||||
mediaType: "screen-share",
|
mediaType: "screen-share",
|
||||||
posterUrl: this.props.screenSharePosterUrl,
|
posterUrl: this.props.screenSharePosterUrl,
|
||||||
srcMediaElement: this.props.screenShareMediaElement})
|
srcMediaElement: this.props.screenShareMediaElement}),
|
||||||
|
this.props.displayScreenShare ? this.props.children : null
|
||||||
),
|
),
|
||||||
React.createElement(loop.shared.views.chat.TextChatView, {
|
React.createElement(loop.shared.views.chat.TextChatView, {
|
||||||
dispatcher: this.props.dispatcher,
|
dispatcher: this.props.dispatcher,
|
||||||
|
@ -1123,7 +1123,7 @@ loop.shared.views = (function(_, mozL10n) {
|
|||||||
srcMediaElement={this.props.remoteSrcMediaElement} />
|
srcMediaElement={this.props.remoteSrcMediaElement} />
|
||||||
{ this.state.localMediaAboslutelyPositioned ?
|
{ this.state.localMediaAboslutelyPositioned ?
|
||||||
this.renderLocalVideo() : null }
|
this.renderLocalVideo() : null }
|
||||||
{ this.props.children }
|
{ this.props.displayScreenShare ? null : this.props.children }
|
||||||
</div>
|
</div>
|
||||||
<div className={screenShareStreamClasses}>
|
<div className={screenShareStreamClasses}>
|
||||||
<MediaView displayAvatar={false}
|
<MediaView displayAvatar={false}
|
||||||
@ -1131,6 +1131,7 @@ loop.shared.views = (function(_, mozL10n) {
|
|||||||
mediaType="screen-share"
|
mediaType="screen-share"
|
||||||
posterUrl={this.props.screenSharePosterUrl}
|
posterUrl={this.props.screenSharePosterUrl}
|
||||||
srcMediaElement={this.props.screenShareMediaElement} />
|
srcMediaElement={this.props.screenShareMediaElement} />
|
||||||
|
{ this.props.displayScreenShare ? this.props.children : null }
|
||||||
</div>
|
</div>
|
||||||
<loop.shared.views.chat.TextChatView
|
<loop.shared.views.chat.TextChatView
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
|
@ -46,47 +46,82 @@ body,
|
|||||||
height: 30px;
|
height: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.room-conversation-wrapper > .beta-logo {
|
/* Standalone Overlay wrapper */
|
||||||
position: fixed;
|
.standalone-overlay-wrapper {
|
||||||
top: 0;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 50px;
|
top: 0;
|
||||||
height: 50px;
|
bottom: 0;
|
||||||
background: transparent url(../shared/img/beta-ribbon.svg) no-repeat;
|
right: 0;
|
||||||
background-size: 50px;
|
margin: 1.2rem;
|
||||||
z-index: 1000;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mozilla Logo */
|
.standalone-overlay-wrapper > .hello-logo {
|
||||||
|
width: 128px;
|
||||||
|
height: 21px;
|
||||||
|
background-image: url("../shared/img/hello_logo.svg");
|
||||||
|
background-size: contain;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.focus-stream > .standalone-moz-logo {
|
html[dir="rtl"] .standalone-overlay-wrapper > .hello-logo {
|
||||||
|
right: 0;
|
||||||
|
left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.standalone-overlay-wrapper > .general-support-url {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
html[dir="rtl"] .standalone-overlay-wrapper > .general-support-url {
|
||||||
|
left: 0;
|
||||||
|
right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.standalone-overlay-wrapper .icon-help {
|
||||||
|
background-size: contain;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
background: transparent url("../shared/img/svg/glyph-help-16x16.svg") no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
.standalone-overlay-wrapper > .standalone-moz-logo {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
height: 13px;
|
height: 13px;
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
background-image: url("../img/mozilla-logo.svg#logo-white");
|
background-image: url("../img/mozilla-logo.svg#logo-white");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 1.2rem;
|
bottom: 0;
|
||||||
right: 1.2rem;
|
right: 0;
|
||||||
left: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
html[dir="rtl"] .focus-stream > .standalone-moz-logo {
|
html[dir="rtl"] .standalone-overlay-wrapper > .standalone-moz-logo {
|
||||||
left: 1.2rem;
|
left: 0;
|
||||||
right: auto;
|
right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width:640px) {
|
|
||||||
.focus-stream > .standalone-moz-logo {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-large {
|
.btn-large {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
padding: .3em .5rem;
|
padding: .3em .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width:640px) {
|
||||||
|
.standalone-overlay-wrapper > .standalone-moz-logo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.standalone-overlay-wrapper > .hello-logo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsupported/expired views
|
* Unsupported/expired views
|
||||||
*/
|
*/
|
||||||
|
@ -390,32 +390,6 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var StandaloneRoomHeader = React.createClass({displayName: "StandaloneRoomHeader",
|
|
||||||
propTypes: {
|
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
recordClick: function() {
|
|
||||||
this.props.dispatcher.dispatch(new sharedActions.RecordClick({
|
|
||||||
linkInfo: "Support link click"
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
return (
|
|
||||||
React.createElement("header", null,
|
|
||||||
React.createElement("h1", null, mozL10n.get("clientShortname2")),
|
|
||||||
React.createElement("a", {href: loop.config.generalSupportUrl,
|
|
||||||
onClick: this.recordClick,
|
|
||||||
rel: "noreferrer",
|
|
||||||
target: "_blank"},
|
|
||||||
React.createElement("i", {className: "icon icon-help"})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var StandaloneRoomView = React.createClass({displayName: "StandaloneRoomView",
|
var StandaloneRoomView = React.createClass({displayName: "StandaloneRoomView",
|
||||||
mixins: [
|
mixins: [
|
||||||
Backbone.Events,
|
Backbone.Events,
|
||||||
@ -628,8 +602,6 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
React.createElement("div", {className: "room-conversation-wrapper standalone-room-wrapper"},
|
React.createElement("div", {className: "room-conversation-wrapper standalone-room-wrapper"},
|
||||||
React.createElement("div", {className: "beta-logo"}),
|
|
||||||
React.createElement(StandaloneRoomHeader, {dispatcher: this.props.dispatcher}),
|
|
||||||
React.createElement(sharedViews.MediaLayoutView, {
|
React.createElement(sharedViews.MediaLayoutView, {
|
||||||
dispatcher: this.props.dispatcher,
|
dispatcher: this.props.dispatcher,
|
||||||
displayScreenShare: displayScreenShare,
|
displayScreenShare: displayScreenShare,
|
||||||
@ -647,6 +619,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
screenSharePosterUrl: this.props.screenSharePosterUrl,
|
screenSharePosterUrl: this.props.screenSharePosterUrl,
|
||||||
showContextRoomName: true,
|
showContextRoomName: true,
|
||||||
useDesktopPaths: false},
|
useDesktopPaths: false},
|
||||||
|
React.createElement(StandaloneOverlayWrapper, {dispatcher: this.props.dispatcher}),
|
||||||
React.createElement(StandaloneRoomInfoArea, {activeRoomStore: this.props.activeRoomStore,
|
React.createElement(StandaloneRoomInfoArea, {activeRoomStore: this.props.activeRoomStore,
|
||||||
dispatcher: this.props.dispatcher,
|
dispatcher: this.props.dispatcher,
|
||||||
failureReason: this.state.failureReason,
|
failureReason: this.state.failureReason,
|
||||||
@ -662,22 +635,49 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
publishStream: this.publishStream,
|
publishStream: this.publishStream,
|
||||||
show: true,
|
show: true,
|
||||||
video: {enabled: !this.state.videoMuted,
|
video: {enabled: !this.state.videoMuted,
|
||||||
visible: this._roomIsActive()}}),
|
visible: this._roomIsActive()}})
|
||||||
React.createElement(StandaloneMozLogo, {dispatcher: this.props.dispatcher})
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var StandaloneMozLogo = React.createClass({displayName: "StandaloneMozLogo",
|
var StandaloneOverlayWrapper = React.createClass({displayName: "StandaloneOverlayWrapper",
|
||||||
propTypes: {
|
propTypes: {
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
React.createElement("div", {className: "standalone-moz-logo"})
|
React.createElement("div", {className: "standalone-overlay-wrapper"},
|
||||||
|
React.createElement("div", {className: "hello-logo"}),
|
||||||
|
React.createElement(GeneralSupportURL, {dispatcher: this.props.dispatcher}),
|
||||||
|
React.createElement("div", {className: "standalone-moz-logo"})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var GeneralSupportURL = React.createClass({displayName: "GeneralSupportURL",
|
||||||
|
propTypes: {
|
||||||
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
generalSupportUrlClick: function() {
|
||||||
|
this.props.dispatcher.dispatch(new sharedActions.RecordClick({
|
||||||
|
linkInfo: "Support link click"
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
React.createElement("a", {className: "general-support-url",
|
||||||
|
href: loop.config.generalSupportUrl,
|
||||||
|
onClick: this.generalSupportUrlClick,
|
||||||
|
rel: "noreferrer",
|
||||||
|
target: "_blank"},
|
||||||
|
React.createElement("div", {className: "icon icon-help"})
|
||||||
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -722,8 +722,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
StandaloneHandleUserAgentView: StandaloneHandleUserAgentView,
|
StandaloneHandleUserAgentView: StandaloneHandleUserAgentView,
|
||||||
StandaloneRoomControllerView: StandaloneRoomControllerView,
|
StandaloneRoomControllerView: StandaloneRoomControllerView,
|
||||||
StandaloneRoomFailureView: StandaloneRoomFailureView,
|
StandaloneRoomFailureView: StandaloneRoomFailureView,
|
||||||
StandaloneRoomHeader: StandaloneRoomHeader,
|
|
||||||
StandaloneRoomInfoArea: StandaloneRoomInfoArea,
|
StandaloneRoomInfoArea: StandaloneRoomInfoArea,
|
||||||
|
StandaloneOverlayWrapper: StandaloneOverlayWrapper,
|
||||||
StandaloneRoomView: StandaloneRoomView,
|
StandaloneRoomView: StandaloneRoomView,
|
||||||
ToSView: ToSView
|
ToSView: ToSView
|
||||||
};
|
};
|
||||||
|
@ -390,32 +390,6 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var StandaloneRoomHeader = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
|
||||||
},
|
|
||||||
|
|
||||||
recordClick: function() {
|
|
||||||
this.props.dispatcher.dispatch(new sharedActions.RecordClick({
|
|
||||||
linkInfo: "Support link click"
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function() {
|
|
||||||
return (
|
|
||||||
<header>
|
|
||||||
<h1>{mozL10n.get("clientShortname2")}</h1>
|
|
||||||
<a href={loop.config.generalSupportUrl}
|
|
||||||
onClick={this.recordClick}
|
|
||||||
rel="noreferrer"
|
|
||||||
target="_blank">
|
|
||||||
<i className="icon icon-help"></i>
|
|
||||||
</a>
|
|
||||||
</header>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var StandaloneRoomView = React.createClass({
|
var StandaloneRoomView = React.createClass({
|
||||||
mixins: [
|
mixins: [
|
||||||
Backbone.Events,
|
Backbone.Events,
|
||||||
@ -628,8 +602,6 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="room-conversation-wrapper standalone-room-wrapper">
|
<div className="room-conversation-wrapper standalone-room-wrapper">
|
||||||
<div className="beta-logo" />
|
|
||||||
<StandaloneRoomHeader dispatcher={this.props.dispatcher} />
|
|
||||||
<sharedViews.MediaLayoutView
|
<sharedViews.MediaLayoutView
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
displayScreenShare={displayScreenShare}
|
displayScreenShare={displayScreenShare}
|
||||||
@ -647,6 +619,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
screenSharePosterUrl={this.props.screenSharePosterUrl}
|
screenSharePosterUrl={this.props.screenSharePosterUrl}
|
||||||
showContextRoomName={true}
|
showContextRoomName={true}
|
||||||
useDesktopPaths={false}>
|
useDesktopPaths={false}>
|
||||||
|
<StandaloneOverlayWrapper dispatcher={this.props.dispatcher} />
|
||||||
<StandaloneRoomInfoArea activeRoomStore={this.props.activeRoomStore}
|
<StandaloneRoomInfoArea activeRoomStore={this.props.activeRoomStore}
|
||||||
dispatcher={this.props.dispatcher}
|
dispatcher={this.props.dispatcher}
|
||||||
failureReason={this.state.failureReason}
|
failureReason={this.state.failureReason}
|
||||||
@ -663,21 +636,48 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
show={true}
|
show={true}
|
||||||
video={{enabled: !this.state.videoMuted,
|
video={{enabled: !this.state.videoMuted,
|
||||||
visible: this._roomIsActive()}} />
|
visible: this._roomIsActive()}} />
|
||||||
<StandaloneMozLogo dispatcher={this.props.dispatcher}/>
|
|
||||||
</sharedViews.MediaLayoutView>
|
</sharedViews.MediaLayoutView>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var StandaloneMozLogo = React.createClass({
|
var StandaloneOverlayWrapper = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div className="standalone-moz-logo" />
|
<div className="standalone-overlay-wrapper">
|
||||||
|
<div className="hello-logo"></div>
|
||||||
|
<GeneralSupportURL dispatcher={this.props.dispatcher} />
|
||||||
|
<div className="standalone-moz-logo" />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var GeneralSupportURL = React.createClass({
|
||||||
|
propTypes: {
|
||||||
|
dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired
|
||||||
|
},
|
||||||
|
|
||||||
|
generalSupportUrlClick: function() {
|
||||||
|
this.props.dispatcher.dispatch(new sharedActions.RecordClick({
|
||||||
|
linkInfo: "Support link click"
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<a className="general-support-url"
|
||||||
|
href={loop.config.generalSupportUrl}
|
||||||
|
onClick={this.generalSupportUrlClick}
|
||||||
|
rel="noreferrer"
|
||||||
|
target="_blank">
|
||||||
|
<div className="icon icon-help"></div>
|
||||||
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -722,8 +722,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
|
|||||||
StandaloneHandleUserAgentView: StandaloneHandleUserAgentView,
|
StandaloneHandleUserAgentView: StandaloneHandleUserAgentView,
|
||||||
StandaloneRoomControllerView: StandaloneRoomControllerView,
|
StandaloneRoomControllerView: StandaloneRoomControllerView,
|
||||||
StandaloneRoomFailureView: StandaloneRoomFailureView,
|
StandaloneRoomFailureView: StandaloneRoomFailureView,
|
||||||
StandaloneRoomHeader: StandaloneRoomHeader,
|
|
||||||
StandaloneRoomInfoArea: StandaloneRoomInfoArea,
|
StandaloneRoomInfoArea: StandaloneRoomInfoArea,
|
||||||
|
StandaloneOverlayWrapper: StandaloneOverlayWrapper,
|
||||||
StandaloneRoomView: StandaloneRoomView,
|
StandaloneRoomView: StandaloneRoomView,
|
||||||
ToSView: ToSView
|
ToSView: ToSView
|
||||||
};
|
};
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
"dependencies": {},
|
"dependencies": {},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"compression": "1.5.x",
|
"compression": "1.5.x",
|
||||||
"eslint": "1.2.x",
|
"eslint": "1.6.x",
|
||||||
"eslint-plugin-mozilla": "../../../../testing/eslint-plugin-mozilla",
|
"eslint-plugin-mozilla": "../../../../testing/eslint-plugin-mozilla",
|
||||||
"eslint-plugin-react": "3.2.x",
|
"eslint-plugin-react": "3.5.x",
|
||||||
"exports-loader": "0.6.x",
|
"exports-loader": "0.6.x",
|
||||||
"express": "4.x",
|
"express": "4.x",
|
||||||
"imports-loader": "0.6.x",
|
"imports-loader": "0.6.x",
|
||||||
|
@ -40,6 +40,7 @@ describe("loop.standaloneRoomViews", function() {
|
|||||||
close: sandbox.stub(),
|
close: sandbox.stub(),
|
||||||
addEventListener: function() {},
|
addEventListener: function() {},
|
||||||
document: { addEventListener: function(){} },
|
document: { addEventListener: function(){} },
|
||||||
|
removeEventListener: function() {},
|
||||||
setTimeout: function(callback) { callback(); }
|
setTimeout: function(callback) { callback(); }
|
||||||
};
|
};
|
||||||
loop.shared.mixins.setRootObject(fakeWindow);
|
loop.shared.mixins.setRootObject(fakeWindow);
|
||||||
@ -211,7 +212,7 @@ describe("loop.standaloneRoomViews", function() {
|
|||||||
function mountTestComponent() {
|
function mountTestComponent() {
|
||||||
return TestUtils.renderIntoDocument(
|
return TestUtils.renderIntoDocument(
|
||||||
React.createElement(
|
React.createElement(
|
||||||
loop.standaloneRoomViews.StandaloneRoomHeader, {
|
loop.standaloneRoomViews.StandaloneOverlayWrapper, {
|
||||||
dispatcher: dispatcher
|
dispatcher: dispatcher
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,6 @@
|
|||||||
#nav-bar[brighttext] {
|
#nav-bar[brighttext] {
|
||||||
--toolbarbutton-hover-background: rgba(255,255,255,.25);
|
--toolbarbutton-hover-background: rgba(255,255,255,.25);
|
||||||
--toolbarbutton-hover-bordercolor: rgba(255,255,255,.5);
|
--toolbarbutton-hover-bordercolor: rgba(255,255,255,.5);
|
||||||
--toolbarbutton-hover-boxshadow: none;
|
|
||||||
|
|
||||||
--toolbarbutton-active-background: rgba(255,255,255,.4);
|
--toolbarbutton-active-background: rgba(255,255,255,.4);
|
||||||
--toolbarbutton-active-bordercolor: rgba(255,255,255,.7);
|
--toolbarbutton-active-bordercolor: rgba(255,255,255,.7);
|
||||||
@ -61,6 +60,17 @@
|
|||||||
--toolbarbutton-checkedhover-backgroundcolor: rgba(255,255,255,.3);
|
--toolbarbutton-checkedhover-backgroundcolor: rgba(255,255,255,.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#nav-bar:-moz-lwtheme {
|
||||||
|
--toolbarbutton-hover-background: rgba(255,255,255,.25);
|
||||||
|
--toolbarbutton-hover-bordercolor: rgba(0,0,0,.2);
|
||||||
|
|
||||||
|
--toolbarbutton-active-background: rgba(70%,70%,70%,.25);
|
||||||
|
--toolbarbutton-active-bordercolor: rgba(0,0,0,.3);
|
||||||
|
--toolbarbutton-active-boxshadow: 0 0 2px rgba(0,0,0,.6) inset;
|
||||||
|
|
||||||
|
--toolbarbutton-checkedhover-backgroundcolor: rgba(85%,85%,85%,.25);
|
||||||
|
}
|
||||||
|
|
||||||
#menubar-items {
|
#menubar-items {
|
||||||
-moz-box-orient: vertical; /* for flex hack */
|
-moz-box-orient: vertical; /* for flex hack */
|
||||||
}
|
}
|
||||||
@ -1136,10 +1146,6 @@ toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarb
|
|||||||
}
|
}
|
||||||
|
|
||||||
#nav-bar:-moz-lwtheme {
|
#nav-bar:-moz-lwtheme {
|
||||||
--urlbar-border-color: rgba(0,0,0,.32);
|
|
||||||
}
|
|
||||||
|
|
||||||
#nav-bar:-moz-lwtheme-brighttext {
|
|
||||||
--urlbar-border-color: var(--toolbarbutton-hover-bordercolor);
|
--urlbar-border-color: var(--toolbarbutton-hover-bordercolor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1171,11 +1177,6 @@ toolbar .toolbarbutton-1:-moz-any(@primaryToolbarButtons@) > :-moz-any(.toolbarb
|
|||||||
border-color: var(--urlbar-border-color);
|
border-color: var(--urlbar-border-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
#urlbar:-moz-lwtheme-brighttext,
|
|
||||||
.searchbar-textbox:-moz-lwtheme-brighttext {
|
|
||||||
background-clip: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
#urlbar:hover,
|
#urlbar:hover,
|
||||||
.searchbar-textbox:hover {
|
.searchbar-textbox:hover {
|
||||||
border-color: var(--urlbar-border-color-hover);
|
border-color: var(--urlbar-border-color-hover);
|
||||||
|
@ -384,13 +384,6 @@ exports.dumpv = function(msg) {
|
|||||||
// loader, so define it on dumpn instead.
|
// loader, so define it on dumpn instead.
|
||||||
exports.dumpv.wantVerbose = false;
|
exports.dumpv.wantVerbose = false;
|
||||||
|
|
||||||
exports.dbg_assert = function dbg_assert(cond, e) {
|
|
||||||
if (!cond) {
|
|
||||||
return e;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility function for updating an object with the properties of
|
* Utility function for updating an object with the properties of
|
||||||
* other objects.
|
* other objects.
|
||||||
@ -447,6 +440,50 @@ exports.defineLazyGetter = function defineLazyGetter(aObject, aName, aLambda) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// DEPRECATED: use DevToolsUtils.assert(condition, message) instead!
|
||||||
|
exports.dbg_assert = function dbg_assert(cond, e) {
|
||||||
|
if (!cond) {
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DevToolsUtils.assert(condition, message)
|
||||||
|
*
|
||||||
|
* @param Boolean condition
|
||||||
|
* @param String message
|
||||||
|
*
|
||||||
|
* Assertions are enabled when any of the following are true:
|
||||||
|
* - This is a DEBUG_JS_MODULES build
|
||||||
|
* - This is a DEBUG build
|
||||||
|
* - DevToolsUtils.testing is set to true
|
||||||
|
*
|
||||||
|
* If assertions are enabled, then `condition` is checked and if false-y, the
|
||||||
|
* assertion failure is logged and then an error is thrown.
|
||||||
|
*
|
||||||
|
* If assertions are not enabled, then this function is a no-op.
|
||||||
|
*
|
||||||
|
* This is an improvement over `dbg_assert`, which doesn't actually cause any
|
||||||
|
* fatal behavior, and is therefore much easier to accidentally ignore.
|
||||||
|
*/
|
||||||
|
exports.defineLazyGetter(exports, "assert", () => {
|
||||||
|
function noop(condition, msg) { }
|
||||||
|
|
||||||
|
function assert(condition, message) {
|
||||||
|
if (!condition) {
|
||||||
|
const err = new Error("Assertion failure: " + message);
|
||||||
|
exports.reportException("DevToolsUtils.assert", err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const scope = {};
|
||||||
|
Cu.import("resource://gre/modules/AppConstants.jsm", scope);
|
||||||
|
const { DEBUG, DEBUG_JS_MODULES } = scope.AppConstants;
|
||||||
|
|
||||||
|
return (DEBUG || DEBUG_JS_MODULES || exports.testing) ? assert : noop;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a getter on a specified object for a module. The module will not
|
* Defines a getter on a specified object for a module. The module will not
|
||||||
* be imported until first use.
|
* be imported until first use.
|
||||||
|
324
devtools/shared/heapsnapshot/CensusUtils.js
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/*** Visitor ****************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Visitor visits each node and edge of a census report tree as the census
|
||||||
|
* report is being traversed by `walk`.
|
||||||
|
*/
|
||||||
|
function Visitor() { };
|
||||||
|
exports.Visitor = Visitor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `enter` method is called when a new sub-report is entered in traversal.
|
||||||
|
*
|
||||||
|
* @param {Object} breakdown
|
||||||
|
* The breakdown for the sub-report that is being entered by traversal.
|
||||||
|
*
|
||||||
|
* @param {any} edge
|
||||||
|
* The edge leading to this sub-report. The edge is null if (but not iff!
|
||||||
|
* eg, null allocation stack edges) we are entering the root report.
|
||||||
|
*/
|
||||||
|
Visitor.prototype.enter = function (breakdown, edge) { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `exit` method is called when traversal of a sub-report has finished.
|
||||||
|
*
|
||||||
|
* @param {Object} breakdown
|
||||||
|
* The breakdown for the sub-report whose traversal has finished.
|
||||||
|
*/
|
||||||
|
Visitor.prototype.exit = function (breakdown) { };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The `count` method is called when leaf nodes (reports whose breakdown is
|
||||||
|
* by: "count") in the report tree are encountered.
|
||||||
|
*
|
||||||
|
* @param {Object} breakdown
|
||||||
|
* The count breakdown for this report.
|
||||||
|
*
|
||||||
|
* @param {Object} report
|
||||||
|
* The report generated by a breakdown by "count".
|
||||||
|
*
|
||||||
|
* @param {any|null} edge
|
||||||
|
* The edge leading to this count report. The edge is null if we are
|
||||||
|
* entering the root report.
|
||||||
|
*/
|
||||||
|
Visitor.prototype.count = function (breakdown, report, edge) { }
|
||||||
|
|
||||||
|
/*** getReportEdges *********************************************************/
|
||||||
|
|
||||||
|
const EDGES = Object.create(null);
|
||||||
|
|
||||||
|
EDGES.count = function (breakdown, report) {
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
EDGES.internalType = function (breakdown, report) {
|
||||||
|
return Object.keys(report).map(key => ({
|
||||||
|
edge: key,
|
||||||
|
referent: report[key],
|
||||||
|
breakdown: breakdown.then
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
EDGES.objectClass = function (breakdown, report) {
|
||||||
|
return Object.keys(report).map(key => ({
|
||||||
|
edge: key,
|
||||||
|
referent: report[key],
|
||||||
|
breakdown: key === "other" ? breakdown.other : breakdown.then
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
EDGES.coarseType = function (breakdown, report) {
|
||||||
|
return [
|
||||||
|
{ edge: "objects", referent: report.objects, breakdown: breakdown.objects },
|
||||||
|
{ edge: "scripts", referent: report.scripts, breakdown: breakdown.scripts },
|
||||||
|
{ edge: "strings", referent: report.strings, breakdown: breakdown.strings },
|
||||||
|
{ edge: "other", referent: report.other, breakdown: breakdown.other },
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
EDGES.allocationStack = function (breakdown, report) {
|
||||||
|
const edges = [];
|
||||||
|
report.forEach((value, key) => {
|
||||||
|
edges.push({
|
||||||
|
edge: key,
|
||||||
|
referent: value,
|
||||||
|
breakdown: key === "noStack" ? breakdown.noStack : breakdown.then
|
||||||
|
})
|
||||||
|
});
|
||||||
|
return edges;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the set of outgoing edges from `report` as specified by the given
|
||||||
|
* breakdown.
|
||||||
|
*
|
||||||
|
* @param {Object} breakdown
|
||||||
|
* The census breakdown.
|
||||||
|
*
|
||||||
|
* @param {Object} report
|
||||||
|
* The census report.
|
||||||
|
*/
|
||||||
|
function getReportEdges(breakdown, report) {
|
||||||
|
return EDGES[breakdown.by](breakdown, report);
|
||||||
|
}
|
||||||
|
exports.getReportEdges = getReportEdges;
|
||||||
|
|
||||||
|
/*** walk *******************************************************************/
|
||||||
|
|
||||||
|
function recursiveWalk(breakdown, edge, report, visitor) {
|
||||||
|
if (breakdown.by === "count") {
|
||||||
|
visitor.enter(breakdown, edge);
|
||||||
|
visitor.count(breakdown, report, edge);
|
||||||
|
visitor.exit(breakdown, edge);
|
||||||
|
} else {
|
||||||
|
visitor.enter(breakdown, edge);
|
||||||
|
for (let { edge, referent, breakdown } of getReportEdges(breakdown, report)) {
|
||||||
|
recursiveWalk(breakdown, edge, referent, visitor);
|
||||||
|
}
|
||||||
|
visitor.exit(breakdown, edge);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Walk the given `report` that was generated by taking a census with the
|
||||||
|
* specified `breakdown`.
|
||||||
|
*
|
||||||
|
* @param {Object} breakdown
|
||||||
|
* The census breakdown.
|
||||||
|
*
|
||||||
|
* @param {Object} report
|
||||||
|
* The census report.
|
||||||
|
*
|
||||||
|
* @param {Visitor} visitor
|
||||||
|
* The Visitor instance to call into while traversing.
|
||||||
|
*/
|
||||||
|
function walk(breakdown, report, visitor) {
|
||||||
|
recursiveWalk(breakdown, null, report, visitor);
|
||||||
|
};
|
||||||
|
exports.walk = walk;
|
||||||
|
|
||||||
|
/*** diff *******************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if the object is a Map, false otherwise. Works with Map objects
|
||||||
|
* from other globals, unlike `instanceof`.
|
||||||
|
*
|
||||||
|
* @returns {Boolean}
|
||||||
|
*/
|
||||||
|
function isMap(obj) {
|
||||||
|
return Object.prototype.toString.call(obj) === "[object Map]";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Visitor for computing the difference between the census report being
|
||||||
|
* traversed and the given other census.
|
||||||
|
*
|
||||||
|
* @param {Object} otherCensus
|
||||||
|
* The other census report.
|
||||||
|
*/
|
||||||
|
function DiffVisitor(otherCensus) {
|
||||||
|
// The other census we are comparing against.
|
||||||
|
this._otherCensus = otherCensus;
|
||||||
|
|
||||||
|
// Stack maintaining the current corresponding sub-report for the other
|
||||||
|
// census we are comparing against.
|
||||||
|
this._otherCensusStack = [];
|
||||||
|
|
||||||
|
// Stack maintaining the set of edges visited at each sub-report.
|
||||||
|
this._edgesVisited = [new Set()];
|
||||||
|
|
||||||
|
// The final delta census. Valid only after traversal.
|
||||||
|
this._results = null;
|
||||||
|
|
||||||
|
// Stack maintaining the results corresponding to each sub-report we are
|
||||||
|
// currently traversing.
|
||||||
|
this._resultsStack = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
DiffVisitor.prototype = Object.create(Visitor.prototype);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a report and an outgoing edge, get the edge's referent.
|
||||||
|
*/
|
||||||
|
DiffVisitor.prototype._get = function (report, edge) {
|
||||||
|
if (!report) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return isMap(report) ? report.get(edge) : report[edge];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a report, an outgoing edge, and a value, set the edge's referent to
|
||||||
|
* the given value.
|
||||||
|
*/
|
||||||
|
DiffVisitor.prototype._set = function (report, edge, val) {
|
||||||
|
if (isMap(report)) {
|
||||||
|
report.set(edge, val);
|
||||||
|
} else {
|
||||||
|
report[edge] = val;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @overrides Visitor.prototype.enter
|
||||||
|
*/
|
||||||
|
DiffVisitor.prototype.enter = function (breakdown, edge) {
|
||||||
|
const isFirstTimeEntering = this._results === null;
|
||||||
|
|
||||||
|
const newResults = breakdown.by === "allocationStack" ? new Map() : {};
|
||||||
|
let newOther;
|
||||||
|
|
||||||
|
if (!this._results) {
|
||||||
|
// This is the first time we have entered a sub-report.
|
||||||
|
this._results = newResults;
|
||||||
|
newOther = this._otherCensus;
|
||||||
|
} else {
|
||||||
|
const topResults = this._resultsStack[this._resultsStack.length - 1];
|
||||||
|
this._set(topResults, edge, newResults);
|
||||||
|
|
||||||
|
const topOther = this._otherCensusStack[this._otherCensusStack.length - 1];
|
||||||
|
newOther = this._get(topOther, edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._resultsStack.push(newResults);
|
||||||
|
this._otherCensusStack.push(newOther);
|
||||||
|
|
||||||
|
const visited = this._edgesVisited[this._edgesVisited.length - 1];
|
||||||
|
visited.add(edge);
|
||||||
|
this._edgesVisited.push(new Set());
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @overrides Visitor.prototype.exit
|
||||||
|
*/
|
||||||
|
DiffVisitor.prototype.exit = function (breakdown) {
|
||||||
|
// Find all the edges in the other census report that were not traversed and
|
||||||
|
// add them to the results directly.
|
||||||
|
const other = this._otherCensusStack[this._otherCensusStack.length - 1];
|
||||||
|
if (other) {
|
||||||
|
const visited = this._edgesVisited[this._edgesVisited.length - 1];
|
||||||
|
const unvisited = getReportEdges(breakdown, other)
|
||||||
|
.map(e => e.edge)
|
||||||
|
.filter(e => !visited.has(e));
|
||||||
|
const results = this._resultsStack[this._resultsStack.length - 1];
|
||||||
|
for (let edge of unvisited) {
|
||||||
|
this._set(results, edge, this._get(other, edge));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._otherCensusStack.pop();
|
||||||
|
this._resultsStack.pop();
|
||||||
|
this._edgesVisited.pop();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @overrides Visitor.prototype.count
|
||||||
|
*/
|
||||||
|
DiffVisitor.prototype.count = function (breakdown, report, edge) {
|
||||||
|
const other = this._otherCensusStack[this._otherCensusStack.length - 1];
|
||||||
|
const results = this._resultsStack[this._resultsStack.length - 1];
|
||||||
|
|
||||||
|
if (other) {
|
||||||
|
if (breakdown.count) {
|
||||||
|
results.count = other.count - report.count;
|
||||||
|
}
|
||||||
|
if (breakdown.bytes) {
|
||||||
|
results.bytes = other.bytes - report.bytes;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (breakdown.count) {
|
||||||
|
results.count = -report.count;
|
||||||
|
}
|
||||||
|
if (breakdown.bytes) {
|
||||||
|
results.bytes = -report.bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the resulting report of the difference between the traversed census
|
||||||
|
* report and the other census report.
|
||||||
|
*
|
||||||
|
* @returns {Object}
|
||||||
|
* The delta census report.
|
||||||
|
*/
|
||||||
|
DiffVisitor.prototype.results = function () {
|
||||||
|
if (!this._results) {
|
||||||
|
throw new Error("Attempt to get results before computing diff!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._resultsStack.length) {
|
||||||
|
throw new Error("Attempt to get results while still computing diff!");
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._results;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Take the difference between two censuses. The resulting delta report
|
||||||
|
* contains the number/size of things that are in the `endCensus` that are not
|
||||||
|
* in the `startCensus`.
|
||||||
|
*
|
||||||
|
* @param {Object} breakdown
|
||||||
|
* The breakdown used to generate both census reports.
|
||||||
|
*
|
||||||
|
* @param {Object} startCensus
|
||||||
|
* The first census report.
|
||||||
|
*
|
||||||
|
* @param {Object} endCensus
|
||||||
|
* The second census report.
|
||||||
|
*
|
||||||
|
* @returns {Object}
|
||||||
|
* A delta report mirroring the structure of the two census reports
|
||||||
|
* (as specified by the given breakdown).
|
||||||
|
*/
|
||||||
|
function diff(breakdown, startCensus, endCensus) {
|
||||||
|
const visitor = new DiffVisitor(endCensus);
|
||||||
|
walk(breakdown, startCensus, visitor);
|
||||||
|
return visitor.results();
|
||||||
|
};
|
||||||
|
exports.diff = diff
|
@ -76,7 +76,7 @@ HeapAnalysesClient.prototype.readHeapSnapshot = function (snapshotFilePath) {
|
|||||||
* if `asTreeNode` is true.
|
* if `asTreeNode` is true.
|
||||||
*/
|
*/
|
||||||
HeapAnalysesClient.prototype.takeCensus = function (snapshotFilePath,
|
HeapAnalysesClient.prototype.takeCensus = function (snapshotFilePath,
|
||||||
censusOptions={},
|
censusOptions,
|
||||||
requestOptions={}) {
|
requestOptions={}) {
|
||||||
return this._worker.performTask("takeCensus", {
|
return this._worker.performTask("takeCensus", {
|
||||||
snapshotFilePath,
|
snapshotFilePath,
|
||||||
@ -84,3 +84,42 @@ HeapAnalysesClient.prototype.takeCensus = function (snapshotFilePath,
|
|||||||
requestOptions,
|
requestOptions,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request that the worker take a census on the heap snapshots with the given
|
||||||
|
* paths and then return the difference between them. Both heap snapshots must
|
||||||
|
* have already been read into memory by the worker (see `readHeapSnapshot`).
|
||||||
|
*
|
||||||
|
* @param {String} firstSnapshotFilePath
|
||||||
|
* The first snapshot file path.
|
||||||
|
*
|
||||||
|
* @param {String} secondSnapshotFilePath
|
||||||
|
* The second snapshot file path.
|
||||||
|
*
|
||||||
|
* @param {Object} censusOptions
|
||||||
|
* A structured-cloneable object specifying the requested census's
|
||||||
|
* breakdown. See the "takeCensus" section of
|
||||||
|
* `js/src/doc/Debugger/Debugger.Memory.md` for detailed documentation.
|
||||||
|
*
|
||||||
|
* @param {Object} requestOptions
|
||||||
|
* An object specifying options for this request.
|
||||||
|
* - {Boolean} asTreeNode
|
||||||
|
* Whether the resulting delta report should be converted to a census
|
||||||
|
* tree node before returned. Defaults to false.
|
||||||
|
*
|
||||||
|
* @returns Promise<delta report|CensusTreeNode>
|
||||||
|
* The delta report generated by diffing the two census reports, or a
|
||||||
|
* CensusTreeNode generated from the delta report if
|
||||||
|
* `requestOptions.asTreeNode` was true.
|
||||||
|
*/
|
||||||
|
HeapAnalysesClient.prototype.takeCensusDiff = function (firstSnapshotFilePath,
|
||||||
|
secondSnapshotFilePath,
|
||||||
|
censusOptions,
|
||||||
|
requestOptions = {}) {
|
||||||
|
return this._worker.performTask("takeCensusDiff", {
|
||||||
|
firstSnapshotFilePath,
|
||||||
|
secondSnapshotFilePath,
|
||||||
|
censusOptions,
|
||||||
|
requestOptions
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
importScripts("resource://gre/modules/workers/require.js");
|
importScripts("resource://gre/modules/workers/require.js");
|
||||||
importScripts("resource://gre/modules/devtools/shared/worker/helper.js");
|
importScripts("resource://gre/modules/devtools/shared/worker/helper.js");
|
||||||
const { CensusTreeNode } = require("resource://gre/modules/devtools/shared/heapsnapshot/census-tree-node.js");
|
const { CensusTreeNode } = require("resource://gre/modules/devtools/shared/heapsnapshot/census-tree-node.js");
|
||||||
|
const CensusUtils = require("resource://gre/modules/devtools/shared/heapsnapshot/CensusUtils.js");
|
||||||
|
|
||||||
// The set of HeapSnapshot instances this worker has read into memory. Keyed by
|
// The set of HeapSnapshot instances this worker has read into memory. Keyed by
|
||||||
// snapshot file path.
|
// snapshot file path.
|
||||||
@ -36,5 +37,35 @@ workerHelper.createTask(self, "takeCensus", ({ snapshotFilePath, censusOptions,
|
|||||||
}
|
}
|
||||||
|
|
||||||
let report = snapshots[snapshotFilePath].takeCensus(censusOptions);
|
let report = snapshots[snapshotFilePath].takeCensus(censusOptions);
|
||||||
return requestOptions.asTreeNode ? new CensusTreeNode(censusOptions.breakdown, report) : report;
|
return requestOptions.asTreeNode
|
||||||
|
? new CensusTreeNode(censusOptions.breakdown, report)
|
||||||
|
: report;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see HeapAnalysesClient.prototype.takeCensusDiff
|
||||||
|
*/
|
||||||
|
workerHelper.createTask(self, "takeCensusDiff", request => {
|
||||||
|
const {
|
||||||
|
firstSnapshotFilePath,
|
||||||
|
secondSnapshotFilePath,
|
||||||
|
censusOptions,
|
||||||
|
requestOptions
|
||||||
|
} = request;
|
||||||
|
|
||||||
|
if (!snapshots[firstSnapshotFilePath]) {
|
||||||
|
throw new Error(`No known heap snapshot for '${firstSnapshotFilePath}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!snapshots[secondSnapshotFilePath]) {
|
||||||
|
throw new Error(`No known heap snapshot for '${secondSnapshotFilePath}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const first = snapshots[firstSnapshotFilePath].takeCensus(censusOptions);
|
||||||
|
const second = snapshots[secondSnapshotFilePath].takeCensus(censusOptions);
|
||||||
|
const delta = CensusUtils.diff(censusOptions.breakdown, first, second);
|
||||||
|
|
||||||
|
return requestOptions.asTreeNode
|
||||||
|
? new CensusTreeNode(censusOptions.breakdown, delta)
|
||||||
|
: delta;
|
||||||
});
|
});
|
||||||
|
@ -202,6 +202,12 @@ HeapSnapshot::saveNode(const protobuf::Node& node)
|
|||||||
return false;
|
return false;
|
||||||
NodeId id = node.id();
|
NodeId id = node.id();
|
||||||
|
|
||||||
|
// NodeIds are derived from pointers (at most 48 bits) and we rely on them
|
||||||
|
// fitting into JS numbers (IEEE 754 doubles, can precisely store 53 bit
|
||||||
|
// integers) despite storing them on disk as 64 bit integers.
|
||||||
|
if (NS_WARN_IF(!JS::Value::isNumberRepresentable(id)))
|
||||||
|
return false;
|
||||||
|
|
||||||
// Should only deserialize each node once.
|
// Should only deserialize each node once.
|
||||||
if (NS_WARN_IF(nodes.has(id)))
|
if (NS_WARN_IF(nodes.has(id)))
|
||||||
return false;
|
return false;
|
||||||
|
@ -45,6 +45,7 @@ FINAL_LIBRARY = 'xul'
|
|||||||
|
|
||||||
DevToolsModules(
|
DevToolsModules(
|
||||||
'census-tree-node.js',
|
'census-tree-node.js',
|
||||||
|
'CensusUtils.js',
|
||||||
'HeapAnalysesClient.js',
|
'HeapAnalysesClient.js',
|
||||||
'HeapAnalysesWorker.js',
|
'HeapAnalysesWorker.js',
|
||||||
'HeapSnapshotFileUtils.js',
|
'HeapSnapshotFileUtils.js',
|
||||||
|
@ -21,6 +21,7 @@ const HeapAnalysesClient =
|
|||||||
require("devtools/shared/heapsnapshot/HeapAnalysesClient");
|
require("devtools/shared/heapsnapshot/HeapAnalysesClient");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const { CensusTreeNode } = require("devtools/shared/heapsnapshot/census-tree-node");
|
const { CensusTreeNode } = require("devtools/shared/heapsnapshot/census-tree-node");
|
||||||
|
const CensusUtils = require("devtools/shared/heapsnapshot/CensusUtils");
|
||||||
|
|
||||||
// Always log packets when running tests. runxpcshelltests.py will throw
|
// Always log packets when running tests. runxpcshelltests.py will throw
|
||||||
// the output away anyway, unless you give it the --verbose flag.
|
// the output away anyway, unless you give it the --verbose flag.
|
||||||
@ -149,7 +150,96 @@ function saveHeapSnapshotAndTakeCensus(dbg=null, censusOptions=undefined) {
|
|||||||
return snapshot.takeCensus(censusOptions);
|
return snapshot.takeCensus(censusOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that creating a CensusTreeNode from the given `report` with the
|
||||||
|
* specified `breakdown` creates the given `expected` CensusTreeNode.
|
||||||
|
*
|
||||||
|
* @param {Object} breakdown
|
||||||
|
* The census breakdown.
|
||||||
|
*
|
||||||
|
* @param {Object} report
|
||||||
|
* The census report.
|
||||||
|
*
|
||||||
|
* @param {Object} expected
|
||||||
|
* The expected CensusTreeNode result.
|
||||||
|
*
|
||||||
|
* @param {String} assertion
|
||||||
|
* The assertion message.
|
||||||
|
*/
|
||||||
function compareCensusViewData (breakdown, report, expected, assertion) {
|
function compareCensusViewData (breakdown, report, expected, assertion) {
|
||||||
let data = new CensusTreeNode(breakdown, report);
|
let data = new CensusTreeNode(breakdown, report);
|
||||||
equal(JSON.stringify(data), JSON.stringify(expected), assertion);
|
equal(JSON.stringify(data), JSON.stringify(expected), assertion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deep structural equivalence that can handle Map objects in addition to plain
|
||||||
|
// objects.
|
||||||
|
function assertStructurallyEquivalent(actual, expected, path="root") {
|
||||||
|
equal(typeof actual, typeof expected, `${path}: typeof should be the same`);
|
||||||
|
|
||||||
|
if (actual && typeof actual === "object") {
|
||||||
|
const actualProtoString = Object.prototype.toString.call(actual);
|
||||||
|
const expectedProtoString = Object.prototype.toString.call(expected);
|
||||||
|
equal(actualProtoString, expectedProtoString,
|
||||||
|
`${path}: Object.prototype.toString.call() should be the same`);
|
||||||
|
|
||||||
|
if (actualProtoString === "[object Map]") {
|
||||||
|
const expectedKeys = new Set([...expected.keys()]);
|
||||||
|
|
||||||
|
for (let key of actual.keys()) {
|
||||||
|
ok(expectedKeys.has(key),
|
||||||
|
`${path}: every key in actual should exist in expected: ${String(key).slice(0, 10)}`);
|
||||||
|
expectedKeys.delete(key);
|
||||||
|
|
||||||
|
assertStructurallyEquivalent(actual.get(key), expected.get(key),
|
||||||
|
path + ".get(" + String(key).slice(0, 20) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
equal(expectedKeys.size, 0,
|
||||||
|
`${path}: every key in expected should also exist in actual`);
|
||||||
|
} else {
|
||||||
|
const expectedKeys = new Set(Object.keys(expected));
|
||||||
|
|
||||||
|
for (let key of Object.keys(actual)) {
|
||||||
|
ok(expectedKeys.has(key),
|
||||||
|
`${path}: every key in actual should exist in expected: ${key}`);
|
||||||
|
expectedKeys.delete(key);
|
||||||
|
|
||||||
|
assertStructurallyEquivalent(actual[key], expected[key], path + "." + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
equal(expectedKeys.size, 0,
|
||||||
|
`${path}: every key in expected should also exist in actual`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
equal(actual, expected, `${path}: primitives should be equal`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assert that creating a diff of the `first` and `second` census reports
|
||||||
|
* creates the `expected` delta-report.
|
||||||
|
*
|
||||||
|
* @param {Object} breakdown
|
||||||
|
* The census breakdown.
|
||||||
|
*
|
||||||
|
* @param {Object} first
|
||||||
|
* The first census report.
|
||||||
|
*
|
||||||
|
* @param {Object} second
|
||||||
|
* The second census report.
|
||||||
|
*
|
||||||
|
* @param {Object} expected
|
||||||
|
* The expected delta-report.
|
||||||
|
*/
|
||||||
|
function assertDiff(breakdown, first, second, expected) {
|
||||||
|
dumpn("Diffing census reports:");
|
||||||
|
dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4));
|
||||||
|
dumpn("First census report: " + JSON.stringify(first, null, 4));
|
||||||
|
dumpn("Second census report: " + JSON.stringify(second, null, 4));
|
||||||
|
dumpn("Expected delta-report: " + JSON.stringify(expected, null, 4));
|
||||||
|
|
||||||
|
const actual = CensusUtils.diff(breakdown, first, second);
|
||||||
|
dumpn("Actual delta-report: " + JSON.stringify(actual, null, 4));
|
||||||
|
|
||||||
|
assertStructurallyEquivalent(actual, expected);
|
||||||
|
}
|
||||||
|
@ -0,0 +1,49 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test that the HeapAnalyses{Client,Worker} can take diffs between censuses.
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
const BREAKDOWN = {
|
||||||
|
by: "objectClass",
|
||||||
|
then: { by: "count", count: true, bytes: false },
|
||||||
|
other: { by: "count", count: true, bytes: false },
|
||||||
|
};
|
||||||
|
|
||||||
|
add_task(function* () {
|
||||||
|
const client = new HeapAnalysesClient();
|
||||||
|
|
||||||
|
const markers = [allocationMarker()];
|
||||||
|
|
||||||
|
const firstSnapshotFilePath = saveNewHeapSnapshot();
|
||||||
|
|
||||||
|
// Allocate and hold an additional AllocationMarker object so we can see it in
|
||||||
|
// the next heap snapshot.
|
||||||
|
markers.push(allocationMarker());
|
||||||
|
|
||||||
|
const secondSnapshotFilePath = saveNewHeapSnapshot();
|
||||||
|
|
||||||
|
yield client.readHeapSnapshot(firstSnapshotFilePath);
|
||||||
|
yield client.readHeapSnapshot(secondSnapshotFilePath);
|
||||||
|
ok(true, "Should have read both heap snapshot files");
|
||||||
|
|
||||||
|
const delta = yield client.takeCensusDiff(firstSnapshotFilePath,
|
||||||
|
secondSnapshotFilePath,
|
||||||
|
{ breakdown: BREAKDOWN });
|
||||||
|
|
||||||
|
equal(delta.AllocationMarker.count, 1,
|
||||||
|
"There exists one new AllocationMarker in the second heap snapshot");
|
||||||
|
|
||||||
|
const deltaTreeNode = yield client.takeCensusDiff(firstSnapshotFilePath,
|
||||||
|
secondSnapshotFilePath,
|
||||||
|
{ breakdown: BREAKDOWN },
|
||||||
|
{ asTreeNode: true });
|
||||||
|
|
||||||
|
compareCensusViewData(BREAKDOWN, delta, deltaTreeNode,
|
||||||
|
"Returning delta-census as a tree node represents same data as the report");
|
||||||
|
|
||||||
|
client.destroy();
|
||||||
|
});
|
@ -0,0 +1,74 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test diffing census reports of breakdown by "internalType".
|
||||||
|
|
||||||
|
const BREAKDOWN = {
|
||||||
|
by: "internalType",
|
||||||
|
then: { by: "count", count: true, bytes: true }
|
||||||
|
};
|
||||||
|
|
||||||
|
const REPORT1 = {
|
||||||
|
"JSObject": {
|
||||||
|
"count": 10,
|
||||||
|
"bytes": 100,
|
||||||
|
},
|
||||||
|
"js::Shape": {
|
||||||
|
"count": 50,
|
||||||
|
"bytes": 500,
|
||||||
|
},
|
||||||
|
"JSString": {
|
||||||
|
"count": 0,
|
||||||
|
"bytes": 0,
|
||||||
|
},
|
||||||
|
"js::LazyScript": {
|
||||||
|
"count": 1,
|
||||||
|
"bytes": 10,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const REPORT2 = {
|
||||||
|
"JSObject": {
|
||||||
|
"count": 11,
|
||||||
|
"bytes": 110,
|
||||||
|
},
|
||||||
|
"js::Shape": {
|
||||||
|
"count": 51,
|
||||||
|
"bytes": 510,
|
||||||
|
},
|
||||||
|
"JSString": {
|
||||||
|
"count": 1,
|
||||||
|
"bytes": 1,
|
||||||
|
},
|
||||||
|
"js::BaseShape": {
|
||||||
|
"count": 1,
|
||||||
|
"bytes": 42,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const EXPECTED = {
|
||||||
|
"JSObject": {
|
||||||
|
"count": 1,
|
||||||
|
"bytes": 10,
|
||||||
|
},
|
||||||
|
"js::Shape": {
|
||||||
|
"count": 1,
|
||||||
|
"bytes": 10,
|
||||||
|
},
|
||||||
|
"JSString": {
|
||||||
|
"count": 1,
|
||||||
|
"bytes": 1,
|
||||||
|
},
|
||||||
|
"js::LazyScript": {
|
||||||
|
"count": -1,
|
||||||
|
"bytes": -10,
|
||||||
|
},
|
||||||
|
"js::BaseShape": {
|
||||||
|
"count": 1,
|
||||||
|
"bytes": 42,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test diffing census reports of breakdown by "count".
|
||||||
|
|
||||||
|
const BREAKDOWN = { by: "count", count: true, bytes: true };
|
||||||
|
|
||||||
|
const REPORT1 = {
|
||||||
|
"count": 10,
|
||||||
|
"bytes": 100,
|
||||||
|
};
|
||||||
|
|
||||||
|
const REPORT2 = {
|
||||||
|
"count": 11,
|
||||||
|
"bytes": 110,
|
||||||
|
};
|
||||||
|
|
||||||
|
const EXPECTED = {
|
||||||
|
"count": 1,
|
||||||
|
"bytes": 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
|
||||||
|
}
|
@ -0,0 +1,73 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test diffing census reports of breakdown by "coarseType".
|
||||||
|
|
||||||
|
const BREAKDOWN = {
|
||||||
|
by: "coarseType",
|
||||||
|
objects: { by: "count", count: true, bytes: true },
|
||||||
|
scripts: { by: "count", count: true, bytes: true },
|
||||||
|
strings: { by: "count", count: true, bytes: true },
|
||||||
|
other: { by: "count", count: true, bytes: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const REPORT1 = {
|
||||||
|
objects: {
|
||||||
|
count: 1,
|
||||||
|
bytes: 10,
|
||||||
|
},
|
||||||
|
scripts: {
|
||||||
|
count: 1,
|
||||||
|
bytes: 10,
|
||||||
|
},
|
||||||
|
strings: {
|
||||||
|
count: 1,
|
||||||
|
bytes: 10,
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
count: 3,
|
||||||
|
bytes: 30,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const REPORT2 = {
|
||||||
|
objects: {
|
||||||
|
count: 1,
|
||||||
|
bytes: 10,
|
||||||
|
},
|
||||||
|
scripts: {
|
||||||
|
count: 0,
|
||||||
|
bytes: 0,
|
||||||
|
},
|
||||||
|
strings: {
|
||||||
|
count: 2,
|
||||||
|
bytes: 20,
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
count: 4,
|
||||||
|
bytes: 40,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const EXPECTED = {
|
||||||
|
objects: {
|
||||||
|
count: 0,
|
||||||
|
bytes: 0,
|
||||||
|
},
|
||||||
|
scripts: {
|
||||||
|
count: -1,
|
||||||
|
bytes: -10,
|
||||||
|
},
|
||||||
|
strings: {
|
||||||
|
count: 1,
|
||||||
|
bytes: 10,
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
count: 1,
|
||||||
|
bytes: 10,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test diffing census reports of breakdown by "objectClass".
|
||||||
|
|
||||||
|
const BREAKDOWN = {
|
||||||
|
by: "objectClass",
|
||||||
|
then: { by: "count", count: true, bytes: true },
|
||||||
|
other: { by: "count", count: true, bytes: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const REPORT1 = {
|
||||||
|
"Array": {
|
||||||
|
count: 1,
|
||||||
|
bytes: 100,
|
||||||
|
},
|
||||||
|
"Function": {
|
||||||
|
count: 10,
|
||||||
|
bytes: 10,
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
count: 10,
|
||||||
|
bytes: 100,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const REPORT2 = {
|
||||||
|
"Object": {
|
||||||
|
count: 1,
|
||||||
|
bytes: 100,
|
||||||
|
},
|
||||||
|
"Function": {
|
||||||
|
count: 20,
|
||||||
|
bytes: 20,
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
count: 10,
|
||||||
|
bytes: 100,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const EXPECTED = {
|
||||||
|
"Array": {
|
||||||
|
count: -1,
|
||||||
|
bytes: -100,
|
||||||
|
},
|
||||||
|
"Function": {
|
||||||
|
count: 10,
|
||||||
|
bytes: 10,
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
count: 0,
|
||||||
|
bytes: 0,
|
||||||
|
},
|
||||||
|
"Object": {
|
||||||
|
count: 1,
|
||||||
|
bytes: 100,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test diffing census reports of breakdown by "allocationStack".
|
||||||
|
|
||||||
|
const BREAKDOWN = {
|
||||||
|
by: "allocationStack",
|
||||||
|
then: { by: "count", count: true, bytes: true },
|
||||||
|
noStack: { by: "count", count: true, bytes: true },
|
||||||
|
};
|
||||||
|
|
||||||
|
const stack1 = saveStack();
|
||||||
|
const stack2 = saveStack();
|
||||||
|
const stack3 = saveStack();
|
||||||
|
|
||||||
|
const REPORT1 = new Map([
|
||||||
|
[stack1, { "count": 10, "bytes": 100 }],
|
||||||
|
[stack2, { "count": 1, "bytes": 10 }],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const REPORT2 = new Map([
|
||||||
|
[stack2, { "count": 10, "bytes": 100 }],
|
||||||
|
[stack3, { "count": 1, "bytes": 10 }],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const EXPECTED = new Map([
|
||||||
|
[stack1, { "count": -10, "bytes": -100 }],
|
||||||
|
[stack2, { "count": 9, "bytes": 90 }],
|
||||||
|
[stack3, { "count": 1, "bytes": 10 }],
|
||||||
|
]);
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
|
||||||
|
}
|
137
devtools/shared/heapsnapshot/tests/unit/test_census_diff_06.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
// Test diffing census reports of a "complex" and "realistic" breakdown.
|
||||||
|
|
||||||
|
const BREAKDOWN = {
|
||||||
|
by: "coarseType",
|
||||||
|
objects: {
|
||||||
|
by: "allocationStack",
|
||||||
|
then: {
|
||||||
|
by: "objectClass",
|
||||||
|
then: { by: "count", count: false, bytes: true },
|
||||||
|
other: { by: "count", count: false, bytes: true }
|
||||||
|
},
|
||||||
|
noStack: {
|
||||||
|
by: "objectClass",
|
||||||
|
then: { by: "count", count: false, bytes: true },
|
||||||
|
other: { by: "count", count: false, bytes: true }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
strings: {
|
||||||
|
by: "internalType",
|
||||||
|
then: { by: "count", count: false, bytes: true }
|
||||||
|
},
|
||||||
|
scripts: {
|
||||||
|
by: "internalType",
|
||||||
|
then: { by: "count", count: false, bytes: true }
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
by: "internalType",
|
||||||
|
then: { by: "count", count: false, bytes: true }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const stack1 = saveStack();
|
||||||
|
const stack2 = saveStack();
|
||||||
|
const stack3 = saveStack();
|
||||||
|
|
||||||
|
const REPORT1 = {
|
||||||
|
objects: new Map([
|
||||||
|
[stack1, { Function: { bytes: 1 },
|
||||||
|
Object: { bytes: 2 },
|
||||||
|
other: { bytes: 0 },
|
||||||
|
}],
|
||||||
|
[stack2, { Array: { bytes: 3 },
|
||||||
|
Date: { bytes: 4 },
|
||||||
|
other: { bytes: 0 },
|
||||||
|
}],
|
||||||
|
["noStack", { Object: { bytes: 3 }}],
|
||||||
|
]),
|
||||||
|
strings: {
|
||||||
|
JSAtom: { bytes: 10 },
|
||||||
|
JSLinearString: { bytes: 5 },
|
||||||
|
},
|
||||||
|
scripts: {
|
||||||
|
JSScript: { bytes: 1 },
|
||||||
|
"js::jit::JitCode": { bytes: 2 },
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
"mozilla::dom::Thing": { bytes: 1 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const REPORT2 = {
|
||||||
|
objects: new Map([
|
||||||
|
[stack2, { Array: { bytes: 1 },
|
||||||
|
Date: { bytes: 2 },
|
||||||
|
other: { bytes: 3 },
|
||||||
|
}],
|
||||||
|
[stack3, { Function: { bytes: 1 },
|
||||||
|
Object: { bytes: 2 },
|
||||||
|
other: { bytes: 0 },
|
||||||
|
}],
|
||||||
|
["noStack", { Object: { bytes: 3 }}],
|
||||||
|
]),
|
||||||
|
strings: {
|
||||||
|
JSAtom: { bytes: 5 },
|
||||||
|
JSLinearString: { bytes: 10 },
|
||||||
|
},
|
||||||
|
scripts: {
|
||||||
|
JSScript: { bytes: 2 },
|
||||||
|
"js::LazyScript": { bytes: 42 },
|
||||||
|
"js::jit::JitCode": { bytes: 1 },
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
"mozilla::dom::OtherThing": { bytes: 1 },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const EXPECTED = {
|
||||||
|
"objects": new Map([
|
||||||
|
[stack1, { Function: { bytes: -1 },
|
||||||
|
Object: { bytes: -2 },
|
||||||
|
other: { bytes: 0 },
|
||||||
|
}],
|
||||||
|
[stack2, { Array: { bytes: -2 },
|
||||||
|
Date: { bytes: -2 },
|
||||||
|
other: { bytes: 3 },
|
||||||
|
}],
|
||||||
|
[stack3, { Function: { bytes: 1 },
|
||||||
|
Object: { bytes: 2 },
|
||||||
|
other: { bytes: 0 },
|
||||||
|
}],
|
||||||
|
["noStack", { Object: { bytes: 0 }}],
|
||||||
|
]),
|
||||||
|
"scripts": {
|
||||||
|
"JSScript": {
|
||||||
|
"bytes": 1
|
||||||
|
},
|
||||||
|
"js::jit::JitCode": {
|
||||||
|
"bytes": -1
|
||||||
|
},
|
||||||
|
"js::LazyScript": {
|
||||||
|
"bytes": 42
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strings": {
|
||||||
|
"JSAtom": {
|
||||||
|
"bytes": -5
|
||||||
|
},
|
||||||
|
"JSLinearString": {
|
||||||
|
"bytes": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"other": {
|
||||||
|
"mozilla::dom::Thing": {
|
||||||
|
"bytes": -1
|
||||||
|
},
|
||||||
|
"mozilla::dom::OtherThing": {
|
||||||
|
"bytes": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
assertDiff(BREAKDOWN, REPORT1, REPORT2, EXPECTED);
|
||||||
|
}
|
@ -9,10 +9,17 @@ support-files =
|
|||||||
heap-snapshot-worker.js
|
heap-snapshot-worker.js
|
||||||
Match.jsm
|
Match.jsm
|
||||||
|
|
||||||
|
[test_census_diff_01.js]
|
||||||
|
[test_census_diff_02.js]
|
||||||
|
[test_census_diff_03.js]
|
||||||
|
[test_census_diff_04.js]
|
||||||
|
[test_census_diff_05.js]
|
||||||
|
[test_census_diff_06.js]
|
||||||
[test_census-tree-node-01.js]
|
[test_census-tree-node-01.js]
|
||||||
[test_census-tree-node-02.js]
|
[test_census-tree-node-02.js]
|
||||||
[test_census-tree-node-03.js]
|
[test_census-tree-node-03.js]
|
||||||
[test_HeapAnalyses_readHeapSnapshot_01.js]
|
[test_HeapAnalyses_readHeapSnapshot_01.js]
|
||||||
|
[test_HeapAnalyses_takeCensusDiff_01.js]
|
||||||
[test_HeapAnalyses_takeCensus_01.js]
|
[test_HeapAnalyses_takeCensus_01.js]
|
||||||
[test_HeapAnalyses_takeCensus_02.js]
|
[test_HeapAnalyses_takeCensus_02.js]
|
||||||
[test_HeapAnalyses_takeCensus_03.js]
|
[test_HeapAnalyses_takeCensus_03.js]
|
||||||
|
@ -35,6 +35,8 @@ namespace {
|
|||||||
static BluetoothA2dpInterface* sBtA2dpInterface;
|
static BluetoothA2dpInterface* sBtA2dpInterface;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
const int BluetoothA2dpManager::MAX_NUM_CLIENTS = 1;
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
BluetoothA2dpManager::Observe(nsISupports* aSubject,
|
BluetoothA2dpManager::Observe(nsISupports* aSubject,
|
||||||
const char* aTopic,
|
const char* aTopic,
|
||||||
@ -86,40 +88,52 @@ AvStatusToSinkString(BluetoothA2dpConnectionState aState, nsAString& aString)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothA2dpManager::InitResultHandler final
|
class BluetoothA2dpManager::RegisterModuleResultHandler final
|
||||||
: public BluetoothA2dpResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InitResultHandler(BluetoothProfileResultHandler* aRes)
|
RegisterModuleResultHandler(BluetoothA2dpInterface* aInterface,
|
||||||
: mRes(aRes)
|
BluetoothProfileResultHandler* aRes)
|
||||||
|
: mInterface(aInterface)
|
||||||
|
, mRes(aRes)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
void OnError(BluetoothStatus aStatus) override
|
||||||
{
|
{
|
||||||
BT_WARNING("BluetoothA2dpInterface::Init failed: %d",
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BT_WARNING("BluetoothSetupInterface::RegisterModule failed for A2DP: %d",
|
||||||
(int)aStatus);
|
(int)aStatus);
|
||||||
|
|
||||||
|
mInterface->SetNotificationHandler(nullptr);
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->OnError(NS_ERROR_FAILURE);
|
mRes->OnError(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init() override
|
void RegisterModule() override
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
sBtA2dpInterface = mInterface;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->Init();
|
mRes->Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
BluetoothA2dpInterface* mInterface;
|
||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BluetoothA2dpManager::OnErrorProfileResultHandlerRunnable final
|
class BluetoothA2dpManager::InitProfileResultHandlerRunnable final
|
||||||
: public nsRunnable
|
: public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||||
nsresult aRv)
|
nsresult aRv)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
, mRv(aRv)
|
, mRv(aRv)
|
||||||
{
|
{
|
||||||
@ -128,7 +142,13 @@ public:
|
|||||||
|
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
mRes->OnError(mRv);
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(mRv)) {
|
||||||
|
mRes->Init();
|
||||||
|
} else {
|
||||||
|
mRes->OnError(mRv);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,32 +167,64 @@ private:
|
|||||||
void
|
void
|
||||||
BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
||||||
{
|
{
|
||||||
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (sBtA2dpInterface) {
|
||||||
|
BT_LOGR("Bluetooth A2DP interface is already initalized.");
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch A2DP Init runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto btInf = BluetoothInterface::GetInstance();
|
||||||
|
|
||||||
if (NS_WARN_IF(!btInf)) {
|
if (NS_WARN_IF(!btInf)) {
|
||||||
// If there's no HFP interface, we dispatch a runnable
|
// If there's no Bluetooth interface, we dispatch a runnable
|
||||||
// that calls the profile result handler.
|
// that calls the profile result handler.
|
||||||
nsRefPtr<nsRunnable> r =
|
nsRefPtr<nsRunnable> r =
|
||||||
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sBtA2dpInterface = btInf->GetBluetoothA2dpInterface();
|
auto setupInterface = btInf->GetBluetoothSetupInterface();
|
||||||
if (NS_WARN_IF(!sBtA2dpInterface)) {
|
|
||||||
// If there's no HFP interface, we dispatch a runnable
|
if (NS_WARN_IF(!setupInterface)) {
|
||||||
|
// If there's no Setup interface, we dispatch a runnable
|
||||||
// that calls the profile result handler.
|
// that calls the profile result handler.
|
||||||
nsRefPtr<nsRunnable> r =
|
nsRefPtr<nsRunnable> r =
|
||||||
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
|
auto a2dpInterface = btInf->GetBluetoothA2dpInterface();
|
||||||
sBtA2dpInterface->Init(a2dpManager, new InitResultHandler(aRes));
|
|
||||||
|
if (NS_WARN_IF(!a2dpInterface)) {
|
||||||
|
// If there's no A2DP interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set notification handler _before_ registering the module. It could
|
||||||
|
// happen that we receive notifications, before the result handler runs.
|
||||||
|
a2dpInterface->SetNotificationHandler(BluetoothA2dpManager::Get());
|
||||||
|
|
||||||
|
setupInterface->RegisterModule(
|
||||||
|
SETUP_SERVICE_ID_A2DP, 0, MAX_NUM_CLIENTS,
|
||||||
|
new RegisterModuleResultHandler(a2dpInterface, aRes));
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothA2dpManager::~BluetoothA2dpManager()
|
BluetoothA2dpManager::~BluetoothA2dpManager()
|
||||||
@ -227,19 +279,22 @@ BluetoothA2dpManager::Get()
|
|||||||
return sBluetoothA2dpManager;
|
return sBluetoothA2dpManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothA2dpManager::CleanupResultHandler final
|
class BluetoothA2dpManager::UnregisterModuleResultHandler final
|
||||||
: public BluetoothA2dpResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
|
UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
void OnError(BluetoothStatus aStatus) override
|
||||||
{
|
{
|
||||||
BT_WARNING("BluetoothA2dpInterface::Cleanup failed: %d",
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for A2DP: %d",
|
||||||
(int)aStatus);
|
(int)aStatus);
|
||||||
|
|
||||||
|
sBtA2dpInterface->SetNotificationHandler(nullptr);
|
||||||
sBtA2dpInterface = nullptr;
|
sBtA2dpInterface = nullptr;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
@ -247,8 +302,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cleanup() override
|
void UnregisterModule() override
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
sBtA2dpInterface->SetNotificationHandler(nullptr);
|
||||||
sBtA2dpInterface = nullptr;
|
sBtA2dpInterface = nullptr;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
@ -260,26 +318,33 @@ private:
|
|||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BluetoothA2dpManager::CleanupResultHandlerRunnable final
|
class BluetoothA2dpManager::DeinitProfileResultHandlerRunnable final
|
||||||
: public nsRunnable
|
: public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
|
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||||
|
nsresult aRv)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
{ }
|
, mRv(aRv)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mRes);
|
||||||
|
}
|
||||||
|
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
sBtA2dpInterface = nullptr;
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
if (mRes) {
|
if (NS_SUCCEEDED(mRv)) {
|
||||||
mRes->Deinit();
|
mRes->Deinit();
|
||||||
|
} else {
|
||||||
|
mRes->OnError(mRv);
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
|
nsresult mRv;
|
||||||
};
|
};
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -288,16 +353,45 @@ BluetoothA2dpManager::DeinitA2dpInterface(BluetoothProfileResultHandler* aRes)
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
if (sBtA2dpInterface) {
|
if (!sBtA2dpInterface) {
|
||||||
sBtA2dpInterface->Cleanup(new CleanupResultHandler(aRes));
|
BT_LOGR("Bluetooth A2DP interface has not been initalized.");
|
||||||
} else if (aRes) {
|
nsRefPtr<nsRunnable> r =
|
||||||
// We dispatch a runnable here to make the profile resource handler
|
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||||
// behave as if A2DP was initialized.
|
|
||||||
nsRefPtr<nsRunnable> r = new CleanupResultHandlerRunnable(aRes);
|
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
|
BT_LOGR("Failed to dispatch A2DP Deinit runnable");
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto btInf = BluetoothInterface::GetInstance();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!btInf)) {
|
||||||
|
// If there's no backend interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto setupInterface = btInf->GetBluetoothSetupInterface();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!setupInterface)) {
|
||||||
|
// If there's no Setup interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch A2DP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupInterface->UnregisterModule(
|
||||||
|
SETUP_SERVICE_ID_A2DP,
|
||||||
|
new UnregisterModuleResultHandler(aRes));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -17,6 +17,8 @@ class BluetoothA2dpManager : public BluetoothProfileManagerBase
|
|||||||
, public BluetoothA2dpNotificationHandler
|
, public BluetoothA2dpNotificationHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static const int MAX_NUM_CLIENTS;
|
||||||
|
|
||||||
BT_DECL_PROFILE_MGR_BASE
|
BT_DECL_PROFILE_MGR_BASE
|
||||||
virtual void GetName(nsACString& aName)
|
virtual void GetName(nsACString& aName)
|
||||||
{
|
{
|
||||||
@ -47,12 +49,12 @@ protected:
|
|||||||
virtual ~BluetoothA2dpManager();
|
virtual ~BluetoothA2dpManager();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class CleanupResultHandler;
|
|
||||||
class CleanupResultHandlerRunnable;
|
|
||||||
class ConnectResultHandler;
|
class ConnectResultHandler;
|
||||||
|
class DeinitProfileResultHandlerRunnable;
|
||||||
class DisconnectResultHandler;
|
class DisconnectResultHandler;
|
||||||
class InitResultHandler;
|
class InitProfileResultHandlerRunnable;
|
||||||
class OnErrorProfileResultHandlerRunnable;
|
class RegisterModuleResultHandler;
|
||||||
|
class UnregisterModuleResultHandler;
|
||||||
|
|
||||||
BluetoothA2dpManager();
|
BluetoothA2dpManager();
|
||||||
|
|
||||||
|
@ -35,6 +35,8 @@ namespace {
|
|||||||
static BluetoothAvrcpInterface* sBtAvrcpInterface;
|
static BluetoothAvrcpInterface* sBtAvrcpInterface;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
const int BluetoothAvrcpManager::MAX_NUM_CLIENTS = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function maps attribute id and returns corresponding values
|
* This function maps attribute id and returns corresponding values
|
||||||
*/
|
*/
|
||||||
@ -118,18 +120,27 @@ BluetoothAvrcpManager::Reset()
|
|||||||
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
|
mPlayStatus = ControlPlayStatus::PLAYSTATUS_STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothAvrcpManager::InitResultHandler final
|
class BluetoothAvrcpManager::RegisterModuleResultHandler final
|
||||||
: public BluetoothAvrcpResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InitResultHandler(BluetoothProfileResultHandler* aRes)
|
RegisterModuleResultHandler(BluetoothAvrcpInterface* aInterface,
|
||||||
: mRes(aRes)
|
BluetoothProfileResultHandler* aRes)
|
||||||
{ }
|
: mInterface(aInterface)
|
||||||
|
, mRes(aRes)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mInterface);
|
||||||
|
}
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
void OnError(BluetoothStatus aStatus) override
|
||||||
{
|
{
|
||||||
BT_WARNING("BluetoothAvrcpInterface::Init failed: %d",
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BT_WARNING("BluetoothSetupInterface::RegisterModule failed for AVRCP: %d",
|
||||||
(int)aStatus);
|
(int)aStatus);
|
||||||
|
|
||||||
|
mInterface->SetNotificationHandler(nullptr);
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
if (aStatus == STATUS_UNSUPPORTED) {
|
if (aStatus == STATUS_UNSUPPORTED) {
|
||||||
/* Not all versions of Bluedroid support AVRCP. So if the
|
/* Not all versions of Bluedroid support AVRCP. So if the
|
||||||
@ -143,23 +154,28 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init() override
|
void RegisterModule() override
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
sBtAvrcpInterface = mInterface;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->Init();
|
mRes->Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
BluetoothAvrcpInterface* mInterface;
|
||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BluetoothAvrcpManager::OnErrorProfileResultHandlerRunnable final
|
class BluetoothAvrcpManager::InitProfileResultHandlerRunnable final
|
||||||
: public nsRunnable
|
: public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||||
nsresult aRv)
|
nsresult aRv)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
, mRv(aRv)
|
, mRv(aRv)
|
||||||
{
|
{
|
||||||
@ -168,7 +184,13 @@ public:
|
|||||||
|
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
mRes->OnError(mRv);
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(mRv)) {
|
||||||
|
mRes->Init();
|
||||||
|
} else {
|
||||||
|
mRes->OnError(mRv);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,32 +206,64 @@ private:
|
|||||||
void
|
void
|
||||||
BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
BluetoothAvrcpManager::InitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
||||||
{
|
{
|
||||||
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
if (NS_WARN_IF(!btInf)) {
|
|
||||||
// If there's no HFP interface, we dispatch a runnable
|
if (sBtAvrcpInterface) {
|
||||||
// that calls the profile result handler.
|
BT_LOGR("Bluetooth AVRCP interface is already initalized.");
|
||||||
nsRefPtr<nsRunnable> r =
|
nsRefPtr<nsRunnable> r =
|
||||||
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
BT_LOGR("Failed to dispatch AVRCP Init runnable");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
|
auto btInf = BluetoothInterface::GetInstance();
|
||||||
if (NS_WARN_IF(!sBtAvrcpInterface)) {
|
|
||||||
|
if (NS_WARN_IF(!btInf)) {
|
||||||
|
// If there's no Bluetooth interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto setupInterface = btInf->GetBluetoothSetupInterface();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!setupInterface)) {
|
||||||
|
// If there's no Setup interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto avrcpInterface = btInf->GetBluetoothAvrcpInterface();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!avrcpInterface)) {
|
||||||
// If there's no AVRCP interface, we dispatch a runnable
|
// If there's no AVRCP interface, we dispatch a runnable
|
||||||
// that calls the profile result handler.
|
// that calls the profile result handler.
|
||||||
nsRefPtr<nsRunnable> r =
|
nsRefPtr<nsRunnable> r =
|
||||||
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothAvrcpManager* avrcpManager = BluetoothAvrcpManager::Get();
|
// Set notification handler _before_ registering the module. It could
|
||||||
sBtAvrcpInterface->Init(avrcpManager, new InitResultHandler(aRes));
|
// happen that we receive notifications, before the result handler runs.
|
||||||
|
avrcpInterface->SetNotificationHandler(BluetoothAvrcpManager::Get());
|
||||||
|
|
||||||
|
setupInterface->RegisterModule(
|
||||||
|
SETUP_SERVICE_ID_AVRCP, 0, MAX_NUM_CLIENTS,
|
||||||
|
new RegisterModuleResultHandler(avrcpInterface, aRes));
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothAvrcpManager::~BluetoothAvrcpManager()
|
BluetoothAvrcpManager::~BluetoothAvrcpManager()
|
||||||
@ -245,37 +299,36 @@ BluetoothAvrcpManager::Get()
|
|||||||
return sBluetoothAvrcpManager;
|
return sBluetoothAvrcpManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothAvrcpManager::CleanupResultHandler final
|
class BluetoothAvrcpManager::UnregisterModuleResultHandler final
|
||||||
: public BluetoothAvrcpResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
|
UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
void OnError(BluetoothStatus aStatus) override
|
||||||
{
|
{
|
||||||
BT_WARNING("BluetoothAvrcpInterface::Cleanup failed: %d",
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for AVRCP: %d",
|
||||||
(int)aStatus);
|
(int)aStatus);
|
||||||
|
|
||||||
|
sBtAvrcpInterface->SetNotificationHandler(nullptr);
|
||||||
sBtAvrcpInterface = nullptr;
|
sBtAvrcpInterface = nullptr;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
if (aStatus == STATUS_UNSUPPORTED) {
|
mRes->OnError(NS_ERROR_FAILURE);
|
||||||
/* Not all versions of Bluedroid support AVRCP. So if the
|
|
||||||
* cleanup fails with STATUS_UNSUPPORTED, we still signal
|
|
||||||
* success.
|
|
||||||
*/
|
|
||||||
mRes->Deinit();
|
|
||||||
} else {
|
|
||||||
mRes->OnError(NS_ERROR_FAILURE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cleanup() override
|
void UnregisterModule() override
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
sBtAvrcpInterface->SetNotificationHandler(nullptr);
|
||||||
sBtAvrcpInterface = nullptr;
|
sBtAvrcpInterface = nullptr;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->Deinit();
|
mRes->Deinit();
|
||||||
}
|
}
|
||||||
@ -285,25 +338,33 @@ private:
|
|||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BluetoothAvrcpManager::CleanupResultHandlerRunnable final
|
class BluetoothAvrcpManager::DeinitProfileResultHandlerRunnable final
|
||||||
: public nsRunnable
|
: public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
|
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||||
|
nsresult aRv)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
|
, mRv(aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mRes);
|
MOZ_ASSERT(mRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
mRes->Deinit();
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(mRv)) {
|
||||||
|
mRes->Deinit();
|
||||||
|
} else {
|
||||||
|
mRes->OnError(mRv);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
|
nsresult mRv;
|
||||||
};
|
};
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -312,16 +373,45 @@ BluetoothAvrcpManager::DeinitAvrcpInterface(BluetoothProfileResultHandler* aRes)
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
if (sBtAvrcpInterface) {
|
if (!sBtAvrcpInterface) {
|
||||||
sBtAvrcpInterface->Cleanup(new CleanupResultHandler(aRes));
|
BT_LOGR("Bluetooth AVRCP interface has not been initalized.");
|
||||||
} else if (aRes) {
|
nsRefPtr<nsRunnable> r =
|
||||||
// We dispatch a runnable here to make the profile resource handler
|
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||||
// behave as if AVRCP was initialized.
|
|
||||||
nsRefPtr<nsRunnable> r = new CleanupResultHandlerRunnable(aRes);
|
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
|
BT_LOGR("Failed to dispatch AVRCP Deinit runnable");
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto btInf = BluetoothInterface::GetInstance();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!btInf)) {
|
||||||
|
// If there's no backend interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto setupInterface = btInf->GetBluetoothSetupInterface();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!setupInterface)) {
|
||||||
|
// If there's no Setup interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch AVRCP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupInterface->UnregisterModule(
|
||||||
|
SETUP_SERVICE_ID_AVRCP,
|
||||||
|
new UnregisterModuleResultHandler(aRes));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -17,6 +17,8 @@ class BluetoothAvrcpManager : public BluetoothProfileManagerBase
|
|||||||
, public BluetoothAvrcpNotificationHandler
|
, public BluetoothAvrcpNotificationHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static const int MAX_NUM_CLIENTS;
|
||||||
|
|
||||||
BT_DECL_PROFILE_MGR_BASE
|
BT_DECL_PROFILE_MGR_BASE
|
||||||
virtual void GetName(nsACString& aName)
|
virtual void GetName(nsACString& aName)
|
||||||
{
|
{
|
||||||
@ -60,12 +62,12 @@ protected:
|
|||||||
virtual ~BluetoothAvrcpManager();
|
virtual ~BluetoothAvrcpManager();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class CleanupResultHandler;
|
|
||||||
class CleanupResultHandlerRunnable;
|
|
||||||
class ConnectRunnable;
|
class ConnectRunnable;
|
||||||
|
class DeinitProfileResultHandlerRunnable;
|
||||||
class DisconnectRunnable;
|
class DisconnectRunnable;
|
||||||
class InitResultHandler;
|
class InitProfileResultHandlerRunnable;
|
||||||
class OnErrorProfileResultHandlerRunnable;
|
class RegisterModuleResultHandler;
|
||||||
|
class UnregisterModuleResultHandler;
|
||||||
|
|
||||||
BluetoothAvrcpManager();
|
BluetoothAvrcpManager();
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@ using namespace mozilla::ipc;
|
|||||||
// A2DP module
|
// A2DP module
|
||||||
//
|
//
|
||||||
|
|
||||||
const int BluetoothDaemonA2dpModule::MAX_NUM_CLIENTS = 1;
|
|
||||||
|
|
||||||
BluetoothA2dpNotificationHandler*
|
BluetoothA2dpNotificationHandler*
|
||||||
BluetoothDaemonA2dpModule::sNotificationHandler;
|
BluetoothDaemonA2dpModule::sNotificationHandler;
|
||||||
|
|
||||||
@ -235,109 +233,13 @@ BluetoothDaemonA2dpInterface::BluetoothDaemonA2dpInterface(
|
|||||||
BluetoothDaemonA2dpInterface::~BluetoothDaemonA2dpInterface()
|
BluetoothDaemonA2dpInterface::~BluetoothDaemonA2dpInterface()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
class BluetoothDaemonA2dpInterface::InitResultHandler final
|
|
||||||
: public BluetoothSetupResultHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
InitResultHandler(BluetoothA2dpResultHandler* aRes)
|
|
||||||
: mRes(aRes)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mRes->OnError(aStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterModule() override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mRes->Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<BluetoothA2dpResultHandler> mRes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothDaemonA2dpInterface::Init(
|
BluetoothDaemonA2dpInterface::SetNotificationHandler(
|
||||||
BluetoothA2dpNotificationHandler* aNotificationHandler,
|
BluetoothA2dpNotificationHandler* aNotificationHandler)
|
||||||
BluetoothA2dpResultHandler* aRes)
|
|
||||||
{
|
{
|
||||||
// Set notification handler _before_ registering the module. It could
|
MOZ_ASSERT(mModule);
|
||||||
// happen that we receive notifications, before the result handler runs.
|
|
||||||
mModule->SetNotificationHandler(aNotificationHandler);
|
mModule->SetNotificationHandler(aNotificationHandler);
|
||||||
|
|
||||||
InitResultHandler* res;
|
|
||||||
|
|
||||||
if (aRes) {
|
|
||||||
res = new InitResultHandler(aRes);
|
|
||||||
} else {
|
|
||||||
// We don't need a result handler if the caller is not interested.
|
|
||||||
res = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = mModule->RegisterModule(BluetoothDaemonA2dpModule::SERVICE_ID,
|
|
||||||
0x00, BluetoothDaemonA2dpModule::MAX_NUM_CLIENTS, res);
|
|
||||||
if (NS_FAILED(rv) && aRes) {
|
|
||||||
DispatchError(aRes, rv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BluetoothDaemonA2dpInterface::CleanupResultHandler final
|
|
||||||
: public BluetoothSetupResultHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CleanupResultHandler(BluetoothDaemonA2dpModule* aModule,
|
|
||||||
BluetoothA2dpResultHandler* aRes)
|
|
||||||
: mModule(aModule)
|
|
||||||
, mRes(aRes)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (mRes) {
|
|
||||||
mRes->OnError(aStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnregisterModule() override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
// Clear notification handler _after_ module has been
|
|
||||||
// unregistered. While unregistering the module, we might
|
|
||||||
// still receive notifications.
|
|
||||||
mModule->SetNotificationHandler(nullptr);
|
|
||||||
|
|
||||||
if (mRes) {
|
|
||||||
mRes->Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BluetoothDaemonA2dpModule* mModule;
|
|
||||||
nsRefPtr<BluetoothA2dpResultHandler> mRes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothDaemonA2dpInterface::Cleanup(
|
|
||||||
BluetoothA2dpResultHandler* aRes)
|
|
||||||
{
|
|
||||||
nsresult rv = mModule->UnregisterModule(
|
|
||||||
BluetoothDaemonA2dpModule::SERVICE_ID,
|
|
||||||
new CleanupResultHandler(mModule, aRes));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
DispatchError(aRes, rv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connect / Disconnect */
|
/* Connect / Disconnect */
|
||||||
|
@ -30,18 +30,9 @@ public:
|
|||||||
OPCODE_DISCONNECT = 0x02
|
OPCODE_DISCONNECT = 0x02
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int MAX_NUM_CLIENTS;
|
|
||||||
|
|
||||||
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
||||||
DaemonSocketResultHandler* aRes) = 0;
|
DaemonSocketResultHandler* aRes) = 0;
|
||||||
|
|
||||||
virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
|
|
||||||
uint32_t aMaxNumClients,
|
|
||||||
BluetoothSetupResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
virtual nsresult UnregisterModule(uint8_t aId,
|
|
||||||
BluetoothSetupResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
void SetNotificationHandler(
|
void SetNotificationHandler(
|
||||||
BluetoothA2dpNotificationHandler* aNotificationHandler);
|
BluetoothA2dpNotificationHandler* aNotificationHandler);
|
||||||
|
|
||||||
@ -129,17 +120,12 @@ protected:
|
|||||||
class BluetoothDaemonA2dpInterface final
|
class BluetoothDaemonA2dpInterface final
|
||||||
: public BluetoothA2dpInterface
|
: public BluetoothA2dpInterface
|
||||||
{
|
{
|
||||||
class CleanupResultHandler;
|
|
||||||
class InitResultHandler;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BluetoothDaemonA2dpInterface(BluetoothDaemonA2dpModule* aModule);
|
BluetoothDaemonA2dpInterface(BluetoothDaemonA2dpModule* aModule);
|
||||||
~BluetoothDaemonA2dpInterface();
|
~BluetoothDaemonA2dpInterface();
|
||||||
|
|
||||||
void Init(
|
void SetNotificationHandler(
|
||||||
BluetoothA2dpNotificationHandler* aNotificationHandler,
|
BluetoothA2dpNotificationHandler* aNotificationHandler) override;
|
||||||
BluetoothA2dpResultHandler* aRes) override;
|
|
||||||
void Cleanup(BluetoothA2dpResultHandler* aRes) override;
|
|
||||||
|
|
||||||
/* Connect / Disconnect */
|
/* Connect / Disconnect */
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@ using namespace mozilla::ipc;
|
|||||||
// AVRCP module
|
// AVRCP module
|
||||||
//
|
//
|
||||||
|
|
||||||
const int BluetoothDaemonAvrcpModule::MAX_NUM_CLIENTS = 1;
|
|
||||||
|
|
||||||
BluetoothAvrcpNotificationHandler*
|
BluetoothAvrcpNotificationHandler*
|
||||||
BluetoothDaemonAvrcpModule::sNotificationHandler;
|
BluetoothDaemonAvrcpModule::sNotificationHandler;
|
||||||
|
|
||||||
@ -805,115 +803,13 @@ BluetoothDaemonAvrcpInterface::BluetoothDaemonAvrcpInterface(
|
|||||||
BluetoothDaemonAvrcpInterface::~BluetoothDaemonAvrcpInterface()
|
BluetoothDaemonAvrcpInterface::~BluetoothDaemonAvrcpInterface()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
class BluetoothDaemonAvrcpInterface::InitResultHandler final
|
|
||||||
: public BluetoothSetupResultHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
InitResultHandler(BluetoothAvrcpResultHandler* aRes)
|
|
||||||
: mRes(aRes)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mRes->OnError(aStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterModule() override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mRes->Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<BluetoothAvrcpResultHandler> mRes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothDaemonAvrcpInterface::Init(
|
BluetoothDaemonAvrcpInterface::SetNotificationHandler(
|
||||||
BluetoothAvrcpNotificationHandler* aNotificationHandler,
|
BluetoothAvrcpNotificationHandler* aNotificationHandler)
|
||||||
BluetoothAvrcpResultHandler* aRes)
|
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mModule);
|
MOZ_ASSERT(mModule);
|
||||||
|
|
||||||
// Set notification handler _before_ registering the module. It could
|
|
||||||
// happen that we receive notifications, before the result handler runs.
|
|
||||||
mModule->SetNotificationHandler(aNotificationHandler);
|
mModule->SetNotificationHandler(aNotificationHandler);
|
||||||
|
|
||||||
InitResultHandler* res;
|
|
||||||
|
|
||||||
if (aRes) {
|
|
||||||
res = new InitResultHandler(aRes);
|
|
||||||
} else {
|
|
||||||
// We don't need a result handler if the caller is not interested.
|
|
||||||
res = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = mModule->RegisterModule(
|
|
||||||
BluetoothDaemonAvrcpModule::SERVICE_ID,
|
|
||||||
BluetoothDaemonAvrcpModule::MAX_NUM_CLIENTS, 0x00, res);
|
|
||||||
|
|
||||||
if (NS_FAILED(rv) && aRes) {
|
|
||||||
DispatchError(aRes, rv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BluetoothDaemonAvrcpInterface::CleanupResultHandler final
|
|
||||||
: public BluetoothSetupResultHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CleanupResultHandler(BluetoothDaemonAvrcpModule* aModule,
|
|
||||||
BluetoothAvrcpResultHandler* aRes)
|
|
||||||
: mModule(aModule)
|
|
||||||
, mRes(aRes)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
if (mRes) {
|
|
||||||
mRes->OnError(aStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnregisterModule() override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
// Clear notification handler _after_ module has been
|
|
||||||
// unregistered. While unregistering the module, we might
|
|
||||||
// still receive notifications.
|
|
||||||
mModule->SetNotificationHandler(nullptr);
|
|
||||||
|
|
||||||
if (mRes) {
|
|
||||||
mRes->Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BluetoothDaemonAvrcpModule* mModule;
|
|
||||||
nsRefPtr<BluetoothAvrcpResultHandler> mRes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothDaemonAvrcpInterface::Cleanup(
|
|
||||||
BluetoothAvrcpResultHandler* aRes)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mModule);
|
|
||||||
|
|
||||||
nsresult rv = mModule->UnregisterModule(
|
|
||||||
BluetoothDaemonAvrcpModule::SERVICE_ID,
|
|
||||||
new CleanupResultHandler(mModule, aRes));
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
DispatchError(aRes, rv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -62,18 +62,9 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int MAX_NUM_CLIENTS;
|
|
||||||
|
|
||||||
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
||||||
DaemonSocketResultHandler* aRes) = 0;
|
DaemonSocketResultHandler* aRes) = 0;
|
||||||
|
|
||||||
virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
|
|
||||||
uint32_t aMaxNumClients,
|
|
||||||
BluetoothSetupResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
virtual nsresult UnregisterModule(uint8_t aId,
|
|
||||||
BluetoothSetupResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
void SetNotificationHandler(
|
void SetNotificationHandler(
|
||||||
BluetoothAvrcpNotificationHandler* aNotificationHandler);
|
BluetoothAvrcpNotificationHandler* aNotificationHandler);
|
||||||
|
|
||||||
@ -305,10 +296,8 @@ public:
|
|||||||
BluetoothDaemonAvrcpInterface(BluetoothDaemonAvrcpModule* aModule);
|
BluetoothDaemonAvrcpInterface(BluetoothDaemonAvrcpModule* aModule);
|
||||||
~BluetoothDaemonAvrcpInterface();
|
~BluetoothDaemonAvrcpInterface();
|
||||||
|
|
||||||
void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler,
|
void SetNotificationHandler(
|
||||||
BluetoothAvrcpResultHandler* aRes) override;
|
BluetoothAvrcpNotificationHandler* aNotificationHandler) override;
|
||||||
|
|
||||||
void Cleanup(BluetoothAvrcpResultHandler* aRes) override;
|
|
||||||
|
|
||||||
void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
|
void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
|
||||||
uint32_t aSongLen, uint32_t aSongPos,
|
uint32_t aSongLen, uint32_t aSongPos,
|
||||||
|
@ -15,8 +15,6 @@ using namespace mozilla::ipc;
|
|||||||
// GATT module
|
// GATT module
|
||||||
//
|
//
|
||||||
|
|
||||||
const int BluetoothDaemonGattModule::MAX_NUM_CLIENTS = 1;
|
|
||||||
|
|
||||||
BluetoothGattNotificationHandler*
|
BluetoothGattNotificationHandler*
|
||||||
BluetoothDaemonGattModule::sNotificationHandler;
|
BluetoothDaemonGattModule::sNotificationHandler;
|
||||||
|
|
||||||
@ -2010,6 +2008,7 @@ BluetoothDaemonGattInterface::BluetoothDaemonGattInterface(
|
|||||||
BluetoothDaemonGattInterface::~BluetoothDaemonGattInterface()
|
BluetoothDaemonGattInterface::~BluetoothDaemonGattInterface()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
#if 0
|
||||||
class BluetoothDaemonGattInterface::InitResultHandler final
|
class BluetoothDaemonGattInterface::InitResultHandler final
|
||||||
: public BluetoothSetupResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
@ -2057,8 +2056,8 @@ BluetoothDaemonGattInterface::Init(
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsresult rv = mModule->RegisterModule(
|
nsresult rv = mModule->RegisterModule(
|
||||||
BluetoothDaemonGattModule::SERVICE_ID, 0x00,
|
SETUP_SERVICE_ID_GATT, 0x00, BluetoothDaemonGattModule::MAX_NUM_CLIENTS,
|
||||||
BluetoothDaemonGattModule::MAX_NUM_CLIENTS, res);
|
res);
|
||||||
|
|
||||||
if (NS_FAILED(rv) && aRes) {
|
if (NS_FAILED(rv) && aRes) {
|
||||||
DispatchError(aRes, rv);
|
DispatchError(aRes, rv);
|
||||||
@ -2110,12 +2109,21 @@ BluetoothDaemonGattInterface::Cleanup(
|
|||||||
BluetoothGattResultHandler* aRes)
|
BluetoothGattResultHandler* aRes)
|
||||||
{
|
{
|
||||||
nsresult rv = mModule->UnregisterModule(
|
nsresult rv = mModule->UnregisterModule(
|
||||||
BluetoothDaemonGattModule::SERVICE_ID,
|
SETUP_SERVICE_ID_GATT, new CleanupResultHandler(mModule, aRes));
|
||||||
new CleanupResultHandler(mModule, aRes));
|
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
DispatchError(aRes, rv);
|
DispatchError(aRes, rv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothDaemonGattInterface::SetNotificationHandler(
|
||||||
|
BluetoothGattNotificationHandler* aNotificationHandler)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mModule);
|
||||||
|
|
||||||
|
mModule->SetNotificationHandler(aNotificationHandler);
|
||||||
|
}
|
||||||
|
|
||||||
/* Register / Unregister */
|
/* Register / Unregister */
|
||||||
void
|
void
|
||||||
|
@ -64,18 +64,9 @@ public:
|
|||||||
// TODO: Add L support
|
// TODO: Add L support
|
||||||
};
|
};
|
||||||
|
|
||||||
static const int MAX_NUM_CLIENTS;
|
|
||||||
|
|
||||||
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
||||||
DaemonSocketResultHandler* aRes) = 0;
|
DaemonSocketResultHandler* aRes) = 0;
|
||||||
|
|
||||||
virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
|
|
||||||
uint32_t aMaxNumClients,
|
|
||||||
BluetoothSetupResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
virtual nsresult UnregisterModule(uint8_t aId,
|
|
||||||
BluetoothSetupResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
void SetNotificationHandler(
|
void SetNotificationHandler(
|
||||||
BluetoothGattNotificationHandler* aNotificationHandler);
|
BluetoothGattNotificationHandler* aNotificationHandler);
|
||||||
|
|
||||||
@ -798,9 +789,8 @@ public:
|
|||||||
BluetoothDaemonGattInterface(BluetoothDaemonGattModule* aModule);
|
BluetoothDaemonGattInterface(BluetoothDaemonGattModule* aModule);
|
||||||
~BluetoothDaemonGattInterface();
|
~BluetoothDaemonGattInterface();
|
||||||
|
|
||||||
void Init(BluetoothGattNotificationHandler* aNotificationHandler,
|
void SetNotificationHandler(
|
||||||
BluetoothGattResultHandler* aRes) override;
|
BluetoothGattNotificationHandler* aNotificationHandler) override;
|
||||||
void Cleanup(BluetoothGattResultHandler* aRes) override;
|
|
||||||
|
|
||||||
/* Register / Unregister */
|
/* Register / Unregister */
|
||||||
void RegisterClient(const BluetoothUuid& aUuid,
|
void RegisterClient(const BluetoothUuid& aUuid,
|
||||||
|
@ -1409,115 +1409,12 @@ BluetoothDaemonHandsfreeInterface::BluetoothDaemonHandsfreeInterface(
|
|||||||
BluetoothDaemonHandsfreeInterface::~BluetoothDaemonHandsfreeInterface()
|
BluetoothDaemonHandsfreeInterface::~BluetoothDaemonHandsfreeInterface()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
class BluetoothDaemonHandsfreeInterface::InitResultHandler final
|
void BluetoothDaemonHandsfreeInterface::SetNotificationHandler(
|
||||||
: public BluetoothSetupResultHandler
|
BluetoothHandsfreeNotificationHandler* aNotificationHandler)
|
||||||
{
|
{
|
||||||
public:
|
MOZ_ASSERT(mModule);
|
||||||
InitResultHandler(BluetoothHandsfreeResultHandler* aRes)
|
|
||||||
: mRes(aRes)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mRes->OnError(aStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RegisterModule() override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
mRes->Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<BluetoothHandsfreeResultHandler> mRes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothDaemonHandsfreeInterface::Init(
|
|
||||||
BluetoothHandsfreeNotificationHandler* aNotificationHandler,
|
|
||||||
int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes)
|
|
||||||
{
|
|
||||||
// Set notification handler _before_ registering the module. It could
|
|
||||||
// happen that we receive notifications, before the result handler runs.
|
|
||||||
mModule->SetNotificationHandler(aNotificationHandler);
|
mModule->SetNotificationHandler(aNotificationHandler);
|
||||||
|
|
||||||
InitResultHandler* res;
|
|
||||||
|
|
||||||
if (aRes) {
|
|
||||||
res = new InitResultHandler(aRes);
|
|
||||||
} else {
|
|
||||||
// We don't need a result handler if the caller is not interested.
|
|
||||||
res = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult rv = mModule->RegisterModule(
|
|
||||||
BluetoothDaemonHandsfreeModule::SERVICE_ID, MODE_NARROWBAND_SPEECH,
|
|
||||||
aMaxNumClients, res);
|
|
||||||
|
|
||||||
if (NS_FAILED(rv) && aRes) {
|
|
||||||
DispatchError(aRes, rv);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BluetoothDaemonHandsfreeInterface::CleanupResultHandler final
|
|
||||||
: public BluetoothSetupResultHandler
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CleanupResultHandler(BluetoothDaemonHandsfreeModule* aModule,
|
|
||||||
BluetoothHandsfreeResultHandler* aRes)
|
|
||||||
: mModule(aModule)
|
|
||||||
, mRes(aRes)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(mModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
BT_LOGR("%s:%d", __func__, __LINE__);
|
|
||||||
if (mRes) {
|
|
||||||
mRes->OnError(aStatus);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UnregisterModule() override
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
|
||||||
|
|
||||||
BT_LOGR("%s:%d", __func__, __LINE__);
|
|
||||||
// Clear notification handler _after_ module has been
|
|
||||||
// unregistered. While unregistering the module, we might
|
|
||||||
// still receive notifications.
|
|
||||||
mModule->SetNotificationHandler(nullptr);
|
|
||||||
|
|
||||||
if (mRes) {
|
|
||||||
mRes->Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
BluetoothDaemonHandsfreeModule* mModule;
|
|
||||||
nsRefPtr<BluetoothHandsfreeResultHandler> mRes;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothDaemonHandsfreeInterface::Cleanup(
|
|
||||||
BluetoothHandsfreeResultHandler* aRes)
|
|
||||||
{
|
|
||||||
BT_LOGR("%s:%d", __func__, __LINE__);
|
|
||||||
nsresult rv = mModule->UnregisterModule(
|
|
||||||
BluetoothDaemonHandsfreeModule::SERVICE_ID,
|
|
||||||
new CleanupResultHandler(mModule, aRes));
|
|
||||||
BT_LOGR("%s:%d", __func__, __LINE__);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
DispatchError(aRes, rv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Connect / Disconnect */
|
/* Connect / Disconnect */
|
||||||
|
@ -46,13 +46,6 @@ public:
|
|||||||
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
||||||
DaemonSocketResultHandler* aRes) = 0;
|
DaemonSocketResultHandler* aRes) = 0;
|
||||||
|
|
||||||
virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
|
|
||||||
uint32_t aMaxNumClients,
|
|
||||||
BluetoothSetupResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
virtual nsresult UnregisterModule(uint8_t aId,
|
|
||||||
BluetoothSetupResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
void SetNotificationHandler(
|
void SetNotificationHandler(
|
||||||
BluetoothHandsfreeNotificationHandler* aNotificationHandler);
|
BluetoothHandsfreeNotificationHandler* aNotificationHandler);
|
||||||
|
|
||||||
@ -400,23 +393,12 @@ protected:
|
|||||||
class BluetoothDaemonHandsfreeInterface final
|
class BluetoothDaemonHandsfreeInterface final
|
||||||
: public BluetoothHandsfreeInterface
|
: public BluetoothHandsfreeInterface
|
||||||
{
|
{
|
||||||
class CleanupResultHandler;
|
|
||||||
class InitResultHandler;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
MODE_HEADSET = 0x00,
|
|
||||||
MODE_NARROWBAND_SPEECH = 0x01,
|
|
||||||
MODE_NARRAWBAND_WIDEBAND_SPEECH = 0x02
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BluetoothDaemonHandsfreeInterface(BluetoothDaemonHandsfreeModule* aModule);
|
BluetoothDaemonHandsfreeInterface(BluetoothDaemonHandsfreeModule* aModule);
|
||||||
~BluetoothDaemonHandsfreeInterface();
|
~BluetoothDaemonHandsfreeInterface();
|
||||||
|
|
||||||
void Init(
|
void SetNotificationHandler(
|
||||||
BluetoothHandsfreeNotificationHandler* aNotificationHandler,
|
BluetoothHandsfreeNotificationHandler* aNotificationHandler) override;
|
||||||
int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes) override;
|
|
||||||
void Cleanup(BluetoothHandsfreeResultHandler* aRes) override;
|
|
||||||
|
|
||||||
/* Connect / Disconnect */
|
/* Connect / Disconnect */
|
||||||
|
|
||||||
|
@ -841,6 +841,35 @@ Convert(BluetoothScanMode aIn, int32_t& aOut)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
Convert(BluetoothSetupServiceId aIn, uint8_t& aOut)
|
||||||
|
{
|
||||||
|
static const uint8_t sServiceId[] = {
|
||||||
|
[SETUP_SERVICE_ID_SETUP] = 0x00,
|
||||||
|
[SETUP_SERVICE_ID_CORE] = 0x01,
|
||||||
|
[SETUP_SERVICE_ID_SOCKET] = 0x02,
|
||||||
|
[SETUP_SERVICE_ID_HID] = 0x03,
|
||||||
|
[SETUP_SERVICE_ID_PAN] = 0x04,
|
||||||
|
[SETUP_SERVICE_ID_HANDSFREE] = 0x05,
|
||||||
|
[SETUP_SERVICE_ID_A2DP] = 0x06,
|
||||||
|
[SETUP_SERVICE_ID_HEALTH] = 0x07,
|
||||||
|
[SETUP_SERVICE_ID_AVRCP] = 0x08,
|
||||||
|
[SETUP_SERVICE_ID_GATT] = 0x09,
|
||||||
|
[SETUP_SERVICE_ID_HANDSFREE_CLIENT] = 0x0a,
|
||||||
|
[SETUP_SERVICE_ID_MAP_CLIENT] = 0x0b,
|
||||||
|
[SETUP_SERVICE_ID_AVRCP_CONTROLLER] = 0x0c,
|
||||||
|
[SETUP_SERVICE_ID_A2DP_SINK] = 0x0d
|
||||||
|
};
|
||||||
|
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
|
||||||
|
aIn >= MOZ_ARRAY_LENGTH(sServiceId),
|
||||||
|
BluetoothServiceSetupId, uint8_t)) {
|
||||||
|
aOut = 0; // silences compiler warning
|
||||||
|
return NS_ERROR_ILLEGAL_VALUE;
|
||||||
|
}
|
||||||
|
aOut = sServiceId[aIn];
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
Convert(BluetoothSspVariant aIn, uint8_t& aOut)
|
Convert(BluetoothSspVariant aIn, uint8_t& aOut)
|
||||||
{
|
{
|
||||||
@ -1267,6 +1296,12 @@ PackPDU(BluetoothScanMode aIn, DaemonSocketPDU& aPDU)
|
|||||||
return PackPDU(PackConversion<BluetoothScanMode, int32_t>(aIn), aPDU);
|
return PackPDU(PackConversion<BluetoothScanMode, int32_t>(aIn), aPDU);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
PackPDU(BluetoothSetupServiceId aIn, DaemonSocketPDU& aPDU)
|
||||||
|
{
|
||||||
|
return PackPDU(PackConversion<BluetoothSetupServiceId, uint8_t>(aIn), aPDU);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
PackPDU(const BluetoothServiceName& aIn, DaemonSocketPDU& aPDU)
|
PackPDU(const BluetoothServiceName& aIn, DaemonSocketPDU& aPDU)
|
||||||
{
|
{
|
||||||
|
@ -97,12 +97,6 @@ struct BluetoothAvrcpEventParamPair {
|
|||||||
const BluetoothAvrcpNotificationParam& mParam;
|
const BluetoothAvrcpNotificationParam& mParam;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct BluetoothConfigurationParameter {
|
|
||||||
uint8_t mType;
|
|
||||||
uint16_t mLength;
|
|
||||||
nsAutoArrayPtr<uint8_t> mValue;
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Conversion
|
// Conversion
|
||||||
//
|
//
|
||||||
@ -236,6 +230,9 @@ Convert(BluetoothPropertyType aIn, uint8_t& aOut);
|
|||||||
nsresult
|
nsresult
|
||||||
Convert(BluetoothScanMode aIn, uint8_t& aOut);
|
Convert(BluetoothScanMode aIn, uint8_t& aOut);
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
Convert(BluetoothSetupServiceId aIn, uint8_t& aOut);
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
Convert(BluetoothSocketType aIn, uint8_t& aOut);
|
Convert(BluetoothSocketType aIn, uint8_t& aOut);
|
||||||
|
|
||||||
@ -335,6 +332,9 @@ PackPDU(BluetoothPropertyType aIn, DaemonSocketPDU& aPDU);
|
|||||||
nsresult
|
nsresult
|
||||||
PackPDU(const BluetoothServiceName& aIn, DaemonSocketPDU& aPDU);
|
PackPDU(const BluetoothServiceName& aIn, DaemonSocketPDU& aPDU);
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
PackPDU(BluetoothSetupServiceId aIn, DaemonSocketPDU& aPDU);
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
PackPDU(BluetoothSocketType aIn, DaemonSocketPDU& aPDU);
|
PackPDU(BluetoothSocketType aIn, DaemonSocketPDU& aPDU);
|
||||||
|
|
||||||
|
@ -39,24 +39,14 @@ static const int sRetryInterval = 100; // ms
|
|||||||
//
|
//
|
||||||
// Each |BluetoothDaemon*Module| class implements an individual
|
// Each |BluetoothDaemon*Module| class implements an individual
|
||||||
// module of the HAL protocol. Each class contains the abstract
|
// module of the HAL protocol. Each class contains the abstract
|
||||||
// methods
|
// method
|
||||||
//
|
//
|
||||||
// - |Send|,
|
// - |Send|.
|
||||||
// - |RegisterModule|, and
|
|
||||||
// - |UnregisterModule|.
|
|
||||||
//
|
//
|
||||||
// Module classes use |Send| to send out command PDUs. The socket
|
// Module classes use |Send| to send out command PDUs. The socket
|
||||||
// in |BluetoothDaemonProtocol| is required for sending. The abstract
|
// in |BluetoothDaemonProtocol| is required for sending. The abstract
|
||||||
// method hides all these internal details from the modules.
|
// method hides all these internal details from the modules.
|
||||||
//
|
//
|
||||||
// |RegisterModule| is required during module initialization, when
|
|
||||||
// modules must register themselves at the daemon. The register command
|
|
||||||
// is not part of the module itself, but contained in the Setup module
|
|
||||||
// (id of 0x00). The abstract method |RegisterModule| allows modules to
|
|
||||||
// call into the Setup module for generating the register command.
|
|
||||||
//
|
|
||||||
// |UnregisterModule| works like |RegisterModule|, but for cleanups.
|
|
||||||
//
|
|
||||||
// |BluetoothDaemonProtocol| also handles PDU receiving. It implements
|
// |BluetoothDaemonProtocol| also handles PDU receiving. It implements
|
||||||
// the method |Handle| from |DaemonSocketIOConsumer|. The socket
|
// the method |Handle| from |DaemonSocketIOConsumer|. The socket
|
||||||
// connections of type |DaemonSocket| invoke this method
|
// connections of type |DaemonSocket| invoke this method
|
||||||
@ -66,11 +56,9 @@ static const int sRetryInterval = 100; // ms
|
|||||||
// |HandleSvc|. Further PDU processing is module-dependent.
|
// |HandleSvc|. Further PDU processing is module-dependent.
|
||||||
//
|
//
|
||||||
// To summarize the interface between |BluetoothDaemonProtocol| and
|
// To summarize the interface between |BluetoothDaemonProtocol| and
|
||||||
// modules; the former implements the abstract methods
|
// modules; the former implements the abstract method
|
||||||
//
|
//
|
||||||
// - |Send|,
|
// - |Send|,
|
||||||
// - |RegisterModule|, and
|
|
||||||
// - |UnregisterModule|,
|
|
||||||
//
|
//
|
||||||
// which allow modules to send out data. Each module implements the
|
// which allow modules to send out data. Each module implements the
|
||||||
// method
|
// method
|
||||||
@ -95,12 +83,6 @@ public:
|
|||||||
|
|
||||||
void SetConnection(DaemonSocket* aConnection);
|
void SetConnection(DaemonSocket* aConnection);
|
||||||
|
|
||||||
nsresult RegisterModule(uint8_t aId, uint8_t aMode, uint32_t aMaxNumClients,
|
|
||||||
BluetoothSetupResultHandler* aRes) override;
|
|
||||||
|
|
||||||
nsresult UnregisterModule(uint8_t aId,
|
|
||||||
BluetoothSetupResultHandler* aRes) override;
|
|
||||||
|
|
||||||
// Outgoing PDUs
|
// Outgoing PDUs
|
||||||
//
|
//
|
||||||
|
|
||||||
@ -153,22 +135,6 @@ BluetoothDaemonProtocol::SetConnection(DaemonSocket* aConnection)
|
|||||||
mConnection = aConnection;
|
mConnection = aConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
|
||||||
BluetoothDaemonProtocol::RegisterModule(uint8_t aId, uint8_t aMode,
|
|
||||||
uint32_t aMaxNumClients,
|
|
||||||
BluetoothSetupResultHandler* aRes)
|
|
||||||
{
|
|
||||||
return BluetoothDaemonSetupModule::RegisterModuleCmd(aId, aMode,
|
|
||||||
aMaxNumClients, aRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
BluetoothDaemonProtocol::UnregisterModule(uint8_t aId,
|
|
||||||
BluetoothSetupResultHandler* aRes)
|
|
||||||
{
|
|
||||||
return BluetoothDaemonSetupModule::UnregisterModuleCmd(aId, aRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothDaemonProtocol::Send(DaemonSocketPDU* aPDU,
|
BluetoothDaemonProtocol::Send(DaemonSocketPDU* aPDU,
|
||||||
DaemonSocketResultHandler* aRes)
|
DaemonSocketResultHandler* aRes)
|
||||||
@ -422,7 +388,9 @@ public:
|
|||||||
if (!mRegisteredSocketModule) {
|
if (!mRegisteredSocketModule) {
|
||||||
mRegisteredSocketModule = true;
|
mRegisteredSocketModule = true;
|
||||||
// Init, step 5: Register Socket module
|
// Init, step 5: Register Socket module
|
||||||
mInterface->mProtocol->RegisterModuleCmd(0x02, 0x00,
|
mInterface->mProtocol->RegisterModuleCmd(
|
||||||
|
SETUP_SERVICE_ID_SOCKET,
|
||||||
|
0x00,
|
||||||
BluetoothDaemonSocketModule::MAX_NUM_CLIENTS, this);
|
BluetoothDaemonSocketModule::MAX_NUM_CLIENTS, this);
|
||||||
} else if (mRes) {
|
} else if (mRes) {
|
||||||
// Init, step 6: Signal success to caller
|
// Init, step 6: Signal success to caller
|
||||||
@ -556,7 +524,7 @@ private:
|
|||||||
if (!mUnregisteredCoreModule) {
|
if (!mUnregisteredCoreModule) {
|
||||||
mUnregisteredCoreModule = true;
|
mUnregisteredCoreModule = true;
|
||||||
// Cleanup, step 2: Unregister Core module
|
// Cleanup, step 2: Unregister Core module
|
||||||
mInterface->mProtocol->UnregisterModuleCmd(0x01, this);
|
mInterface->mProtocol->UnregisterModuleCmd(SETUP_SERVICE_ID_CORE, this);
|
||||||
} else {
|
} else {
|
||||||
// Cleanup, step 3: Close command channel
|
// Cleanup, step 3: Close command channel
|
||||||
mInterface->mCmdChannel->Close();
|
mInterface->mCmdChannel->Close();
|
||||||
@ -600,7 +568,7 @@ BluetoothDaemonInterface::Cleanup(BluetoothResultHandler* aRes)
|
|||||||
|
|
||||||
// Cleanup, step 1: Unregister Socket module
|
// Cleanup, step 1: Unregister Socket module
|
||||||
nsresult rv = mProtocol->UnregisterModuleCmd(
|
nsresult rv = mProtocol->UnregisterModuleCmd(
|
||||||
0x02, new CleanupResultHandler(this));
|
SETUP_SERVICE_ID_SOCKET, new CleanupResultHandler(this));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
DispatchError(aRes, rv);
|
DispatchError(aRes, rv);
|
||||||
return;
|
return;
|
||||||
@ -889,9 +857,21 @@ BluetoothDaemonInterface::DispatchError(BluetoothResultHandler* aRes,
|
|||||||
DispatchError(aRes, status);
|
DispatchError(aRes, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile Interfaces
|
// Service Interfaces
|
||||||
//
|
//
|
||||||
|
|
||||||
|
BluetoothSetupInterface*
|
||||||
|
BluetoothDaemonInterface::GetBluetoothSetupInterface()
|
||||||
|
{
|
||||||
|
if (mSetupInterface) {
|
||||||
|
return mSetupInterface;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSetupInterface = new BluetoothDaemonSetupInterface(mProtocol);
|
||||||
|
|
||||||
|
return mSetupInterface;
|
||||||
|
}
|
||||||
|
|
||||||
BluetoothSocketInterface*
|
BluetoothSocketInterface*
|
||||||
BluetoothDaemonInterface::GetBluetoothSocketInterface()
|
BluetoothDaemonInterface::GetBluetoothSocketInterface()
|
||||||
{
|
{
|
||||||
@ -1002,7 +982,9 @@ BluetoothDaemonInterface::OnConnectSuccess(int aIndex)
|
|||||||
|
|
||||||
// Init, step 4: Register Core module
|
// Init, step 4: Register Core module
|
||||||
nsresult rv = mProtocol->RegisterModuleCmd(
|
nsresult rv = mProtocol->RegisterModuleCmd(
|
||||||
0x01, 0x00, BluetoothDaemonCoreModule::MAX_NUM_CLIENTS,
|
SETUP_SERVICE_ID_CORE,
|
||||||
|
0x00,
|
||||||
|
BluetoothDaemonCoreModule::MAX_NUM_CLIENTS,
|
||||||
new InitResultHandler(this, res));
|
new InitResultHandler(this, res));
|
||||||
if (NS_FAILED(rv) && res) {
|
if (NS_FAILED(rv) && res) {
|
||||||
DispatchError(res, STATUS_FAIL);
|
DispatchError(res, STATUS_FAIL);
|
||||||
|
@ -27,6 +27,7 @@ class BluetoothDaemonAvrcpInterface;
|
|||||||
class BluetoothDaemonGattInterface;
|
class BluetoothDaemonGattInterface;
|
||||||
class BluetoothDaemonHandsfreeInterface;
|
class BluetoothDaemonHandsfreeInterface;
|
||||||
class BluetoothDaemonProtocol;
|
class BluetoothDaemonProtocol;
|
||||||
|
class BluetoothDaemonSetupInterface;
|
||||||
class BluetoothDaemonSocketInterface;
|
class BluetoothDaemonSocketInterface;
|
||||||
|
|
||||||
class BluetoothDaemonInterface final
|
class BluetoothDaemonInterface final
|
||||||
@ -125,8 +126,9 @@ public:
|
|||||||
|
|
||||||
void ReadEnergyInfo(BluetoothResultHandler* aRes) override;
|
void ReadEnergyInfo(BluetoothResultHandler* aRes) override;
|
||||||
|
|
||||||
/* Profile Interfaces */
|
/* Service Interfaces */
|
||||||
|
|
||||||
|
BluetoothSetupInterface* GetBluetoothSetupInterface() override;
|
||||||
BluetoothSocketInterface* GetBluetoothSocketInterface() override;
|
BluetoothSocketInterface* GetBluetoothSocketInterface() override;
|
||||||
BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() override;
|
BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() override;
|
||||||
BluetoothA2dpInterface* GetBluetoothA2dpInterface() override;
|
BluetoothA2dpInterface* GetBluetoothA2dpInterface() override;
|
||||||
@ -162,6 +164,7 @@ private:
|
|||||||
|
|
||||||
nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
|
nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
|
||||||
|
|
||||||
|
nsAutoPtr<BluetoothDaemonSetupInterface> mSetupInterface;
|
||||||
nsAutoPtr<BluetoothDaemonSocketInterface> mSocketInterface;
|
nsAutoPtr<BluetoothDaemonSocketInterface> mSocketInterface;
|
||||||
nsAutoPtr<BluetoothDaemonHandsfreeInterface> mHandsfreeInterface;
|
nsAutoPtr<BluetoothDaemonHandsfreeInterface> mHandsfreeInterface;
|
||||||
nsAutoPtr<BluetoothDaemonA2dpInterface> mA2dpInterface;
|
nsAutoPtr<BluetoothDaemonA2dpInterface> mA2dpInterface;
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
BEGIN_BLUETOOTH_NAMESPACE
|
BEGIN_BLUETOOTH_NAMESPACE
|
||||||
|
|
||||||
|
using namespace mozilla::ipc;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Setup module
|
// Setup module
|
||||||
//
|
//
|
||||||
@ -54,7 +56,7 @@ BluetoothDaemonSetupModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
|
|||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothDaemonSetupModule::RegisterModuleCmd(
|
BluetoothDaemonSetupModule::RegisterModuleCmd(
|
||||||
uint8_t aId, uint8_t aMode, uint32_t aMaxNumClients,
|
BluetoothSetupServiceId aId, uint8_t aMode, uint32_t aMaxNumClients,
|
||||||
BluetoothSetupResultHandler* aRes)
|
BluetoothSetupResultHandler* aRes)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
@ -81,7 +83,7 @@ BluetoothDaemonSetupModule::RegisterModuleCmd(
|
|||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
BluetoothDaemonSetupModule::UnregisterModuleCmd(
|
BluetoothDaemonSetupModule::UnregisterModuleCmd(
|
||||||
uint8_t aId, BluetoothSetupResultHandler* aRes)
|
BluetoothSetupServiceId aId, BluetoothSetupResultHandler* aRes)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
@ -167,4 +169,77 @@ BluetoothDaemonSetupModule::ConfigurationRsp(
|
|||||||
UnpackPDUInitOp(aPDU));
|
UnpackPDUInitOp(aPDU));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setup interface
|
||||||
|
//
|
||||||
|
|
||||||
|
BluetoothDaemonSetupInterface::BluetoothDaemonSetupInterface(
|
||||||
|
BluetoothDaemonSetupModule* aModule)
|
||||||
|
: mModule(aModule)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
BluetoothDaemonSetupInterface::~BluetoothDaemonSetupInterface()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothDaemonSetupInterface::RegisterModule(
|
||||||
|
BluetoothSetupServiceId aId, uint8_t aMode, uint32_t aMaxNumClients,
|
||||||
|
BluetoothSetupResultHandler* aRes)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mModule);
|
||||||
|
|
||||||
|
nsresult rv = mModule->RegisterModuleCmd(aId, aMode, aMaxNumClients, aRes);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
DispatchError(aRes, rv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothDaemonSetupInterface::UnregisterModule(
|
||||||
|
BluetoothSetupServiceId aId,
|
||||||
|
BluetoothSetupResultHandler* aRes)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mModule);
|
||||||
|
|
||||||
|
nsresult rv = mModule->UnregisterModuleCmd(aId, aRes);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
DispatchError(aRes, rv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothDaemonSetupInterface::Configuration(
|
||||||
|
const BluetoothConfigurationParameter* aParam, uint8_t aLen,
|
||||||
|
BluetoothSetupResultHandler* aRes)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mModule);
|
||||||
|
|
||||||
|
nsresult rv = mModule->ConfigurationCmd(aParam, aLen, aRes);
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
DispatchError(aRes, rv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothDaemonSetupInterface::DispatchError(
|
||||||
|
BluetoothSetupResultHandler* aRes, BluetoothStatus aStatus)
|
||||||
|
{
|
||||||
|
DaemonResultRunnable1<BluetoothSetupResultHandler, void,
|
||||||
|
BluetoothStatus, BluetoothStatus>::Dispatch(
|
||||||
|
aRes, &BluetoothSetupResultHandler::OnError,
|
||||||
|
ConstantInitOp1<BluetoothStatus>(aStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
BluetoothDaemonSetupInterface::DispatchError(
|
||||||
|
BluetoothSetupResultHandler* aRes, nsresult aRv)
|
||||||
|
{
|
||||||
|
BluetoothStatus status;
|
||||||
|
|
||||||
|
if (NS_WARN_IF(NS_FAILED(Convert(aRv, status)))) {
|
||||||
|
status = STATUS_FAIL;
|
||||||
|
}
|
||||||
|
DispatchError(aRes, status);
|
||||||
|
}
|
||||||
|
|
||||||
END_BLUETOOTH_NAMESPACE
|
END_BLUETOOTH_NAMESPACE
|
||||||
|
@ -37,11 +37,11 @@ public:
|
|||||||
// Commands
|
// Commands
|
||||||
//
|
//
|
||||||
|
|
||||||
nsresult RegisterModuleCmd(uint8_t aId, uint8_t aMode,
|
nsresult RegisterModuleCmd(BluetoothSetupServiceId aId, uint8_t aMode,
|
||||||
uint32_t aMaxNumClients,
|
uint32_t aMaxNumClients,
|
||||||
BluetoothSetupResultHandler* aRes);
|
BluetoothSetupResultHandler* aRes);
|
||||||
|
|
||||||
nsresult UnregisterModuleCmd(uint8_t aId,
|
nsresult UnregisterModuleCmd(BluetoothSetupServiceId aId,
|
||||||
BluetoothSetupResultHandler* aRes);
|
BluetoothSetupResultHandler* aRes);
|
||||||
|
|
||||||
nsresult ConfigurationCmd(const BluetoothConfigurationParameter* aParam,
|
nsresult ConfigurationCmd(const BluetoothConfigurationParameter* aParam,
|
||||||
@ -86,6 +86,32 @@ private:
|
|||||||
BluetoothSetupResultHandler* aRes);
|
BluetoothSetupResultHandler* aRes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BluetoothDaemonSetupInterface final
|
||||||
|
: public BluetoothSetupInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BluetoothDaemonSetupInterface(BluetoothDaemonSetupModule* aModule);
|
||||||
|
~BluetoothDaemonSetupInterface();
|
||||||
|
|
||||||
|
void RegisterModule(BluetoothSetupServiceId aId, uint8_t aMode,
|
||||||
|
uint32_t aMaxNumClients,
|
||||||
|
BluetoothSetupResultHandler* aRes) override;
|
||||||
|
|
||||||
|
void UnregisterModule(BluetoothSetupServiceId aId,
|
||||||
|
BluetoothSetupResultHandler* aRes) override;
|
||||||
|
|
||||||
|
void Configuration(const BluetoothConfigurationParameter* aParam,
|
||||||
|
uint8_t aLen,
|
||||||
|
BluetoothSetupResultHandler* aRes) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DispatchError(BluetoothSetupResultHandler* aRes,
|
||||||
|
BluetoothStatus aStatus);
|
||||||
|
void DispatchError(BluetoothSetupResultHandler* aRes, nsresult aRv);
|
||||||
|
|
||||||
|
BluetoothDaemonSetupModule* mModule;
|
||||||
|
};
|
||||||
|
|
||||||
END_BLUETOOTH_NAMESPACE
|
END_BLUETOOTH_NAMESPACE
|
||||||
|
|
||||||
#endif // mozilla_dom_bluetooth_bluedroid_BluetoothDaemonSetupInterface_h
|
#endif // mozilla_dom_bluetooth_bluedroid_BluetoothDaemonSetupInterface_h
|
||||||
|
@ -37,6 +37,8 @@ namespace {
|
|||||||
static BluetoothGattInterface* sBluetoothGattInterface;
|
static BluetoothGattInterface* sBluetoothGattInterface;
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
const int BluetoothGattManager::MAX_NUM_CLIENTS = 1;
|
||||||
|
|
||||||
bool BluetoothGattManager::mInShutdown = false;
|
bool BluetoothGattManager::mInShutdown = false;
|
||||||
|
|
||||||
static StaticAutoPtr<nsTArray<nsRefPtr<BluetoothGattClient> > > sClients;
|
static StaticAutoPtr<nsTArray<nsRefPtr<BluetoothGattClient> > > sClients;
|
||||||
@ -376,52 +378,126 @@ BluetoothGattManager::Get()
|
|||||||
return sBluetoothGattManager;
|
return sBluetoothGattManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothGattManager::InitGattResultHandler final
|
class BluetoothGattManager::RegisterModuleResultHandler final
|
||||||
: public BluetoothGattResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InitGattResultHandler(BluetoothProfileResultHandler* aRes)
|
RegisterModuleResultHandler(BluetoothGattInterface* aInterface,
|
||||||
: mRes(aRes)
|
BluetoothProfileResultHandler* aRes)
|
||||||
|
: mInterface(aInterface)
|
||||||
|
, mRes(aRes)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
void OnError(BluetoothStatus aStatus) override
|
||||||
{
|
{
|
||||||
BT_WARNING("BluetoothGattInterface::Init failed: %d",
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BT_WARNING("BluetoothSetupInterface::RegisterModule failed for GATT: %d",
|
||||||
(int)aStatus);
|
(int)aStatus);
|
||||||
|
|
||||||
|
mInterface->SetNotificationHandler(nullptr);
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->OnError(NS_ERROR_FAILURE);
|
mRes->OnError(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init() override
|
void RegisterModule() override
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
sBluetoothGattInterface = mInterface;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->Init();
|
mRes->Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
BluetoothGattInterface* mInterface;
|
||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BluetoothGattManager::InitProfileResultHandlerRunnable final
|
||||||
|
: public nsRunnable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||||
|
nsresult aRv)
|
||||||
|
: mRes(aRes)
|
||||||
|
, mRv(aRv)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(mRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
NS_IMETHOD Run() override
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(mRv)) {
|
||||||
|
mRes->Init();
|
||||||
|
} else {
|
||||||
|
mRes->OnError(mRv);
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
|
nsresult mRv;
|
||||||
|
};
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void
|
void
|
||||||
BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
|
BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
|
||||||
{
|
{
|
||||||
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
if (!btInf) {
|
|
||||||
BT_LOGR("Error: Bluetooth interface not available");
|
if (sBluetoothGattInterface) {
|
||||||
if (aRes) {
|
BT_LOGR("Bluetooth GATT interface is already initalized.");
|
||||||
aRes->OnError(NS_ERROR_FAILURE);
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch GATT Init runnable");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sBluetoothGattInterface = btInf->GetBluetoothGattInterface();
|
auto btInf = BluetoothInterface::GetInstance();
|
||||||
if (!sBluetoothGattInterface) {
|
|
||||||
BT_LOGR("Error: Bluetooth GATT interface not available");
|
if (NS_WARN_IF(!btInf)) {
|
||||||
if (aRes) {
|
// If there's no Bluetooth interface, we dispatch a runnable
|
||||||
aRes->OnError(NS_ERROR_FAILURE);
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto setupInterface = btInf->GetBluetoothSetupInterface();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!setupInterface)) {
|
||||||
|
// If there's no Setup interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto gattInterface = btInf->GetBluetoothGattInterface();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!gattInterface)) {
|
||||||
|
// If there's no GATT interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -434,30 +510,43 @@ BluetoothGattManager::InitGattInterface(BluetoothProfileResultHandler* aRes)
|
|||||||
sServers = new nsTArray<nsRefPtr<BluetoothGattServer> >;
|
sServers = new nsTArray<nsRefPtr<BluetoothGattServer> >;
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothGattManager* gattManager = BluetoothGattManager::Get();
|
// Set notification handler _before_ registering the module. It could
|
||||||
sBluetoothGattInterface->Init(gattManager,
|
// happen that we receive notifications, before the result handler runs.
|
||||||
new InitGattResultHandler(aRes));
|
gattInterface->SetNotificationHandler(BluetoothGattManager::Get());
|
||||||
|
|
||||||
|
setupInterface->RegisterModule(
|
||||||
|
SETUP_SERVICE_ID_GATT, 0, MAX_NUM_CLIENTS,
|
||||||
|
new RegisterModuleResultHandler(gattInterface, aRes));
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothGattManager::CleanupResultHandler final
|
class BluetoothGattManager::UnregisterModuleResultHandler final
|
||||||
: public BluetoothGattResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
|
UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
void OnError(BluetoothStatus aStatus) override
|
||||||
{
|
{
|
||||||
BT_WARNING("BluetoothGattInterface::Cleanup failed: %d",
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for GATT: %d",
|
||||||
(int)aStatus);
|
(int)aStatus);
|
||||||
|
|
||||||
|
sBluetoothGattInterface->SetNotificationHandler(nullptr);
|
||||||
|
sBluetoothGattInterface = nullptr;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->OnError(NS_ERROR_FAILURE);
|
mRes->OnError(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cleanup() override
|
void UnregisterModule() override
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
sBluetoothGattInterface->SetNotificationHandler(nullptr);
|
||||||
sBluetoothGattInterface = nullptr;
|
sBluetoothGattInterface = nullptr;
|
||||||
sClients = nullptr;
|
sClients = nullptr;
|
||||||
sServers = nullptr;
|
sServers = nullptr;
|
||||||
@ -471,24 +560,33 @@ private:
|
|||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BluetoothGattManager::CleanupResultHandlerRunnable final
|
class BluetoothGattManager::DeinitProfileResultHandlerRunnable final
|
||||||
: public nsRunnable
|
: public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CleanupResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
|
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||||
: mRes(aRes)
|
nsresult aRv)
|
||||||
|
: mRes(aRes)
|
||||||
|
, mRv(aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mRes);
|
MOZ_ASSERT(mRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
mRes->Deinit();
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(mRv)) {
|
||||||
|
mRes->Deinit();
|
||||||
|
} else {
|
||||||
|
mRes->OnError(mRv);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
|
nsresult mRv;
|
||||||
};
|
};
|
||||||
|
|
||||||
// static
|
// static
|
||||||
@ -497,16 +595,45 @@ BluetoothGattManager::DeinitGattInterface(BluetoothProfileResultHandler* aRes)
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
if (sBluetoothGattInterface) {
|
if (!sBluetoothGattInterface) {
|
||||||
sBluetoothGattInterface->Cleanup(new CleanupResultHandler(aRes));
|
BT_LOGR("Bluetooth GATT interface has not been initalized.");
|
||||||
} else if (aRes) {
|
nsRefPtr<nsRunnable> r =
|
||||||
// We dispatch a runnable here to make the profile resource handler
|
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||||
// behave as if GATT was initialized.
|
|
||||||
nsRefPtr<nsRunnable> r = new CleanupResultHandlerRunnable(aRes);
|
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
|
BT_LOGR("Failed to dispatch GATT Deinit runnable");
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto btInf = BluetoothInterface::GetInstance();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!btInf)) {
|
||||||
|
// If there's no backend interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto setupInterface = btInf->GetBluetoothSetupInterface();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!setupInterface)) {
|
||||||
|
// If there's no Setup interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch GATT OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupInterface->UnregisterModule(
|
||||||
|
SETUP_SERVICE_ID_GATT,
|
||||||
|
new UnregisterModuleResultHandler(aRes));
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothGattManager::RegisterClientResultHandler final
|
class BluetoothGattManager::RegisterClientResultHandler final
|
||||||
|
@ -20,6 +20,8 @@ class BluetoothGattManager final : public nsIObserver
|
|||||||
, public BluetoothGattNotificationHandler
|
, public BluetoothGattNotificationHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static const int MAX_NUM_CLIENTS;
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
NS_DECL_NSIOBSERVER
|
NS_DECL_NSIOBSERVER
|
||||||
|
|
||||||
@ -165,9 +167,16 @@ public:
|
|||||||
private:
|
private:
|
||||||
~BluetoothGattManager();
|
~BluetoothGattManager();
|
||||||
|
|
||||||
|
#if 0
|
||||||
class CleanupResultHandler;
|
class CleanupResultHandler;
|
||||||
class CleanupResultHandlerRunnable;
|
class CleanupResultHandlerRunnable;
|
||||||
class InitGattResultHandler;
|
class InitGattResultHandler;
|
||||||
|
#endif
|
||||||
|
class DeinitProfileResultHandlerRunnable;
|
||||||
|
class InitProfileResultHandlerRunnable;
|
||||||
|
class RegisterModuleResultHandler;
|
||||||
|
class UnregisterModuleResultHandler;
|
||||||
|
|
||||||
class RegisterClientResultHandler;
|
class RegisterClientResultHandler;
|
||||||
class UnregisterClientResultHandler;
|
class UnregisterClientResultHandler;
|
||||||
class StartLeScanResultHandler;
|
class StartLeScanResultHandler;
|
||||||
|
@ -276,12 +276,12 @@ BluetoothHfpManager::Init()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothHfpManager::CleanupInitResultHandler final
|
class BluetoothHfpManager::RegisterModuleResultHandler final
|
||||||
: public BluetoothHandsfreeResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CleanupInitResultHandler(BluetoothHandsfreeInterface* aInterface,
|
RegisterModuleResultHandler(BluetoothHandsfreeInterface* aInterface,
|
||||||
BluetoothProfileResultHandler* aRes)
|
BluetoothProfileResultHandler* aRes)
|
||||||
: mInterface(aInterface)
|
: mInterface(aInterface)
|
||||||
, mRes(aRes)
|
, mRes(aRes)
|
||||||
{
|
{
|
||||||
@ -290,68 +290,40 @@ public:
|
|||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
void OnError(BluetoothStatus aStatus) override
|
||||||
{
|
{
|
||||||
BT_WARNING("BluetoothHandsfreeInterface::Init failed: %d", (int)aStatus);
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BT_WARNING("BluetoothSetupInterface::RegisterModule failed for HFP: %d",
|
||||||
|
(int)aStatus);
|
||||||
|
|
||||||
|
mInterface->SetNotificationHandler(nullptr);
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->OnError(NS_ERROR_FAILURE);
|
mRes->OnError(NS_ERROR_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Init() override
|
void RegisterModule() override
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
sBluetoothHfpInterface = mInterface;
|
sBluetoothHfpInterface = mInterface;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->Init();
|
mRes->Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cleanup() override
|
|
||||||
{
|
|
||||||
sBluetoothHfpInterface = nullptr;
|
|
||||||
/* During re-initialization, a previouly initialized
|
|
||||||
* |BluetoothHandsfreeInterface| has now been cleaned
|
|
||||||
* up, so we start initialization.
|
|
||||||
*/
|
|
||||||
RunInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunInit()
|
|
||||||
{
|
|
||||||
BluetoothHfpManager* hfpManager = BluetoothHfpManager::Get();
|
|
||||||
|
|
||||||
mInterface->Init(hfpManager, BluetoothHfpManager::MAX_NUM_CLIENTS, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BluetoothHandsfreeInterface* mInterface;
|
BluetoothHandsfreeInterface* mInterface;
|
||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BluetoothHfpManager::InitResultHandlerRunnable final
|
class BluetoothHfpManager::InitProfileResultHandlerRunnable final
|
||||||
: public nsRunnable
|
: public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
InitResultHandlerRunnable(CleanupInitResultHandler* aRes)
|
InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||||
: mRes(aRes)
|
nsresult aRv)
|
||||||
{
|
|
||||||
MOZ_ASSERT(mRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHOD Run() override
|
|
||||||
{
|
|
||||||
mRes->RunInit();
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nsRefPtr<CleanupInitResultHandler> mRes;
|
|
||||||
};
|
|
||||||
|
|
||||||
class BluetoothHfpManager::OnErrorProfileResultHandlerRunnable final
|
|
||||||
: public nsRunnable
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
OnErrorProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
|
||||||
nsresult aRv)
|
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
, mRv(aRv)
|
, mRv(aRv)
|
||||||
{
|
{
|
||||||
@ -360,7 +332,13 @@ public:
|
|||||||
|
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
mRes->OnError(mRv);
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(mRv)) {
|
||||||
|
mRes->Init();
|
||||||
|
} else {
|
||||||
|
mRes->OnError(mRv);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,45 +351,64 @@ private:
|
|||||||
void
|
void
|
||||||
BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
|
BluetoothHfpManager::InitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||||
{
|
{
|
||||||
BluetoothInterface* btInf = BluetoothInterface::GetInstance();
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (sBluetoothHfpInterface) {
|
||||||
|
BT_LOGR("Bluetooth Handsfree interface is already initalized.");
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch HFP Init runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto btInf = BluetoothInterface::GetInstance();
|
||||||
|
|
||||||
if (NS_WARN_IF(!btInf)) {
|
if (NS_WARN_IF(!btInf)) {
|
||||||
// If there's no backend interface, we dispatch a runnable
|
// If there's no backend interface, we dispatch a runnable
|
||||||
// that calls the profile result handler.
|
// that calls the profile result handler.
|
||||||
nsRefPtr<nsRunnable> r =
|
nsRefPtr<nsRunnable> r =
|
||||||
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothHandsfreeInterface *interface =
|
auto setupInterface = btInf->GetBluetoothSetupInterface();
|
||||||
btInf->GetBluetoothHandsfreeInterface();
|
|
||||||
|
if (NS_WARN_IF(!setupInterface)) {
|
||||||
|
// If there's no Setup interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto interface = btInf->GetBluetoothHandsfreeInterface();
|
||||||
|
|
||||||
if (NS_WARN_IF(!interface)) {
|
if (NS_WARN_IF(!interface)) {
|
||||||
// If there's no HFP interface, we dispatch a runnable
|
// If there's no HFP interface, we dispatch a runnable
|
||||||
// that calls the profile result handler.
|
// that calls the profile result handler.
|
||||||
nsRefPtr<nsRunnable> r =
|
nsRefPtr<nsRunnable> r =
|
||||||
new OnErrorProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<CleanupInitResultHandler> res =
|
// Set notification handler _before_ registering the module. It could
|
||||||
new CleanupInitResultHandler(interface, aRes);
|
// happen that we receive notifications, before the result handler runs.
|
||||||
|
interface->SetNotificationHandler(BluetoothHfpManager::Get());
|
||||||
|
|
||||||
if (sBluetoothHfpInterface) {
|
setupInterface->RegisterModule(
|
||||||
// Cleanup an initialized HFP before initializing again.
|
SETUP_SERVICE_ID_HANDSFREE, MODE_NARROWBAND_SPEECH, MAX_NUM_CLIENTS,
|
||||||
sBluetoothHfpInterface->Cleanup(res);
|
new RegisterModuleResultHandler(interface, aRes));
|
||||||
} else {
|
|
||||||
// If there's no HFP interface to cleanup first, we dispatch
|
|
||||||
// a runnable that calls the profile result handler.
|
|
||||||
nsRefPtr<nsRunnable> r = new InitResultHandlerRunnable(res);
|
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
|
||||||
BT_LOGR("Failed to dispatch HFP init runnable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BluetoothHfpManager::~BluetoothHfpManager()
|
BluetoothHfpManager::~BluetoothHfpManager()
|
||||||
@ -432,18 +429,22 @@ BluetoothHfpManager::~BluetoothHfpManager()
|
|||||||
hal::UnregisterBatteryObserver(this);
|
hal::UnregisterBatteryObserver(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
class BluetoothHfpManager::CleanupResultHandler final
|
class BluetoothHfpManager::UnregisterModuleResultHandler final
|
||||||
: public BluetoothHandsfreeResultHandler
|
: public BluetoothSetupResultHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CleanupResultHandler(BluetoothProfileResultHandler* aRes)
|
UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void OnError(BluetoothStatus aStatus) override
|
void OnError(BluetoothStatus aStatus) override
|
||||||
{
|
{
|
||||||
BT_WARNING("BluetoothHandsfreeInterface::Cleanup failed: %d", (int)aStatus);
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for HFP: %d",
|
||||||
|
(int)aStatus);
|
||||||
|
|
||||||
|
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
|
||||||
sBluetoothHfpInterface = nullptr;
|
sBluetoothHfpInterface = nullptr;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
@ -451,9 +452,13 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cleanup() override
|
void UnregisterModule() override
|
||||||
{
|
{
|
||||||
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
sBluetoothHfpInterface->SetNotificationHandler(nullptr);
|
||||||
sBluetoothHfpInterface = nullptr;
|
sBluetoothHfpInterface = nullptr;
|
||||||
|
|
||||||
if (mRes) {
|
if (mRes) {
|
||||||
mRes->Deinit();
|
mRes->Deinit();
|
||||||
}
|
}
|
||||||
@ -463,40 +468,80 @@ private:
|
|||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BluetoothHfpManager::DeinitResultHandlerRunnable final
|
class BluetoothHfpManager::DeinitProfileResultHandlerRunnable final
|
||||||
: public nsRunnable
|
: public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeinitResultHandlerRunnable(BluetoothProfileResultHandler* aRes)
|
DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
|
||||||
|
nsresult aRv)
|
||||||
: mRes(aRes)
|
: mRes(aRes)
|
||||||
|
, mRv(aRv)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mRes);
|
MOZ_ASSERT(mRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHOD Run() override
|
NS_IMETHOD Run() override
|
||||||
{
|
{
|
||||||
mRes->Deinit();
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(mRv)) {
|
||||||
|
mRes->Deinit();
|
||||||
|
} else {
|
||||||
|
mRes->OnError(mRv);
|
||||||
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
nsRefPtr<BluetoothProfileResultHandler> mRes;
|
||||||
|
nsresult mRv;
|
||||||
};
|
};
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void
|
void
|
||||||
BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
|
BluetoothHfpManager::DeinitHfpInterface(BluetoothProfileResultHandler* aRes)
|
||||||
{
|
{
|
||||||
if (sBluetoothHfpInterface) {
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
sBluetoothHfpInterface->Cleanup(new CleanupResultHandler(aRes));
|
|
||||||
} else if (aRes) {
|
if (!sBluetoothHfpInterface) {
|
||||||
// We dispatch a runnable here to make the profile resource handler
|
BT_LOGR("Bluetooth Handsfree interface has not been initialized.");
|
||||||
// behave as if HFP was initialized.
|
nsRefPtr<nsRunnable> r =
|
||||||
nsRefPtr<nsRunnable> r = new DeinitResultHandlerRunnable(aRes);
|
new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
|
||||||
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
BT_LOGR("Failed to dispatch cleanup-result-handler runnable");
|
BT_LOGR("Failed to dispatch HFP Deinit runnable");
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto btInf = BluetoothInterface::GetInstance();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!btInf)) {
|
||||||
|
// If there's no backend interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto setupInterface = btInf->GetBluetoothSetupInterface();
|
||||||
|
|
||||||
|
if (NS_WARN_IF(!setupInterface)) {
|
||||||
|
// If there's no Setup interface, we dispatch a runnable
|
||||||
|
// that calls the profile result handler.
|
||||||
|
nsRefPtr<nsRunnable> r =
|
||||||
|
new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
|
||||||
|
if (NS_FAILED(NS_DispatchToMainThread(r))) {
|
||||||
|
BT_LOGR("Failed to dispatch HFP OnError runnable");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setupInterface->UnregisterModule(
|
||||||
|
SETUP_SERVICE_ID_HANDSFREE,
|
||||||
|
new UnregisterModuleResultHandler(aRes));
|
||||||
}
|
}
|
||||||
|
|
||||||
//static
|
//static
|
||||||
|
@ -73,6 +73,12 @@ class BluetoothHfpManager : public BluetoothHfpManagerBase
|
|||||||
, public BluetoothHandsfreeNotificationHandler
|
, public BluetoothHandsfreeNotificationHandler
|
||||||
, public BatteryObserver
|
, public BatteryObserver
|
||||||
{
|
{
|
||||||
|
enum {
|
||||||
|
MODE_HEADSET = 0x00,
|
||||||
|
MODE_NARROWBAND_SPEECH = 0x01,
|
||||||
|
MODE_NARRAWBAND_WIDEBAND_SPEECH = 0x02
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BT_DECL_HFP_MGR_BASE
|
BT_DECL_HFP_MGR_BASE
|
||||||
|
|
||||||
@ -151,21 +157,20 @@ private:
|
|||||||
class ConnectResultHandler;
|
class ConnectResultHandler;
|
||||||
class CopsResponseResultHandler;
|
class CopsResponseResultHandler;
|
||||||
class ClccResponseResultHandler;
|
class ClccResponseResultHandler;
|
||||||
class CleanupInitResultHandler;
|
|
||||||
class CleanupResultHandler;
|
|
||||||
class CloseScoRunnable;
|
class CloseScoRunnable;
|
||||||
class CloseScoTask;
|
class CloseScoTask;
|
||||||
class DeinitResultHandlerRunnable;
|
class DeinitProfileResultHandlerRunnable;
|
||||||
class DeviceStatusNotificationResultHandler;
|
class DeviceStatusNotificationResultHandler;
|
||||||
class DisconnectAudioResultHandler;
|
class DisconnectAudioResultHandler;
|
||||||
class DisconnectResultHandler;
|
class DisconnectResultHandler;
|
||||||
class FormattedAtResponseResultHandler;
|
class FormattedAtResponseResultHandler;
|
||||||
class GetVolumeTask;
|
class GetVolumeTask;
|
||||||
class InitResultHandlerRunnable;
|
class InitProfileResultHandlerRunnable;
|
||||||
class MainThreadTask;
|
class MainThreadTask;
|
||||||
class OnErrorProfileResultHandlerRunnable;
|
|
||||||
class PhoneStateChangeResultHandler;
|
class PhoneStateChangeResultHandler;
|
||||||
|
class RegisterModuleResultHandler;
|
||||||
class RespondToBLDNTask;
|
class RespondToBLDNTask;
|
||||||
|
class UnregisterModuleResultHandler;
|
||||||
class VolumeControlResultHandler;
|
class VolumeControlResultHandler;
|
||||||
|
|
||||||
friend class BluetoothHfpManagerObserver;
|
friend class BluetoothHfpManagerObserver;
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include "mozilla/Compiler.h"
|
#include "mozilla/Compiler.h"
|
||||||
#include "mozilla/Observer.h"
|
#include "mozilla/Observer.h"
|
||||||
|
#include "nsAutoPtr.h"
|
||||||
#include "nsPrintfCString.h"
|
#include "nsPrintfCString.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
@ -325,6 +326,23 @@ enum BluetoothBondState {
|
|||||||
BOND_STATE_BONDED
|
BOND_STATE_BONDED
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum BluetoothSetupServiceId {
|
||||||
|
SETUP_SERVICE_ID_SETUP,
|
||||||
|
SETUP_SERVICE_ID_CORE,
|
||||||
|
SETUP_SERVICE_ID_SOCKET,
|
||||||
|
SETUP_SERVICE_ID_HID,
|
||||||
|
SETUP_SERVICE_ID_PAN,
|
||||||
|
SETUP_SERVICE_ID_HANDSFREE,
|
||||||
|
SETUP_SERVICE_ID_A2DP,
|
||||||
|
SETUP_SERVICE_ID_HEALTH,
|
||||||
|
SETUP_SERVICE_ID_AVRCP,
|
||||||
|
SETUP_SERVICE_ID_GATT,
|
||||||
|
SETUP_SERVICE_ID_HANDSFREE_CLIENT,
|
||||||
|
SETUP_SERVICE_ID_MAP_CLIENT,
|
||||||
|
SETUP_SERVICE_ID_AVRCP_CONTROLLER,
|
||||||
|
SETUP_SERVICE_ID_A2DP_SINK
|
||||||
|
};
|
||||||
|
|
||||||
/* Physical transport for GATT connections to remote dual-mode devices */
|
/* Physical transport for GATT connections to remote dual-mode devices */
|
||||||
enum BluetoothTransport {
|
enum BluetoothTransport {
|
||||||
TRANSPORT_AUTO, /* No preference of physical transport */
|
TRANSPORT_AUTO, /* No preference of physical transport */
|
||||||
@ -480,6 +498,12 @@ struct BluetoothAddress {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BluetoothConfigurationParameter {
|
||||||
|
uint8_t mType;
|
||||||
|
uint16_t mLength;
|
||||||
|
nsAutoArrayPtr<uint8_t> mValue;
|
||||||
|
};
|
||||||
|
|
||||||
struct BluetoothUuid {
|
struct BluetoothUuid {
|
||||||
uint8_t mUuid[16];
|
uint8_t mUuid[16];
|
||||||
|
|
||||||
|
@ -39,6 +39,12 @@ void
|
|||||||
BluetoothSetupResultHandler::Configuration()
|
BluetoothSetupResultHandler::Configuration()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
// Interface
|
||||||
|
//
|
||||||
|
|
||||||
|
BluetoothSetupInterface::~BluetoothSetupInterface()
|
||||||
|
{ }
|
||||||
|
|
||||||
//
|
//
|
||||||
// Socket Interface
|
// Socket Interface
|
||||||
//
|
//
|
||||||
@ -181,14 +187,6 @@ BluetoothHandsfreeResultHandler::OnError(BluetoothStatus aStatus)
|
|||||||
BT_WARNING("Received error code %d", (int)aStatus);
|
BT_WARNING("Received error code %d", (int)aStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothHandsfreeResultHandler::Init()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothHandsfreeResultHandler::Cleanup()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothHandsfreeResultHandler::Connect()
|
BluetoothHandsfreeResultHandler::Connect()
|
||||||
{ }
|
{ }
|
||||||
@ -295,14 +293,6 @@ BluetoothA2dpResultHandler::OnError(BluetoothStatus aStatus)
|
|||||||
BT_WARNING("Received error code %d", (int)aStatus);
|
BT_WARNING("Received error code %d", (int)aStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothA2dpResultHandler::Init()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothA2dpResultHandler::Cleanup()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothA2dpResultHandler::Connect()
|
BluetoothA2dpResultHandler::Connect()
|
||||||
{ }
|
{ }
|
||||||
@ -400,14 +390,6 @@ BluetoothAvrcpResultHandler::OnError(BluetoothStatus aStatus)
|
|||||||
BT_WARNING("Received error code %d", (int)aStatus);
|
BT_WARNING("Received error code %d", (int)aStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothAvrcpResultHandler::Init()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothAvrcpResultHandler::Cleanup()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothAvrcpResultHandler::GetPlayStatusRsp()
|
BluetoothAvrcpResultHandler::GetPlayStatusRsp()
|
||||||
{ }
|
{ }
|
||||||
@ -679,14 +661,6 @@ BluetoothGattResultHandler::OnError(BluetoothStatus aStatus)
|
|||||||
BT_WARNING("Received error code %d", (int)aStatus);
|
BT_WARNING("Received error code %d", (int)aStatus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothGattResultHandler::Init()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
|
||||||
BluetoothGattResultHandler::Cleanup()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void
|
void
|
||||||
BluetoothGattResultHandler::RegisterClient()
|
BluetoothGattResultHandler::RegisterClient()
|
||||||
{ }
|
{ }
|
||||||
|
@ -30,6 +30,25 @@ protected:
|
|||||||
virtual ~BluetoothSetupResultHandler() { }
|
virtual ~BluetoothSetupResultHandler() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class BluetoothSetupInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void RegisterModule(BluetoothSetupServiceId aId,
|
||||||
|
uint8_t aMode,
|
||||||
|
uint32_t aMaxNumClients,
|
||||||
|
BluetoothSetupResultHandler* aRes) = 0;
|
||||||
|
|
||||||
|
virtual void UnregisterModule(BluetoothSetupServiceId aId,
|
||||||
|
BluetoothSetupResultHandler* aRes) = 0;
|
||||||
|
|
||||||
|
virtual void Configuration(const BluetoothConfigurationParameter* aParam,
|
||||||
|
uint8_t aLen,
|
||||||
|
BluetoothSetupResultHandler* aRes) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~BluetoothSetupInterface();
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Socket Interface
|
// Socket Interface
|
||||||
//
|
//
|
||||||
@ -155,9 +174,6 @@ class BluetoothHandsfreeResultHandler
|
|||||||
public:
|
public:
|
||||||
virtual void OnError(BluetoothStatus aStatus);
|
virtual void OnError(BluetoothStatus aStatus);
|
||||||
|
|
||||||
virtual void Init();
|
|
||||||
virtual void Cleanup();
|
|
||||||
|
|
||||||
virtual void Connect();
|
virtual void Connect();
|
||||||
virtual void Disconnect();
|
virtual void Disconnect();
|
||||||
virtual void ConnectAudio();
|
virtual void ConnectAudio();
|
||||||
@ -186,10 +202,8 @@ protected:
|
|||||||
class BluetoothHandsfreeInterface
|
class BluetoothHandsfreeInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void Init(
|
virtual void SetNotificationHandler(
|
||||||
BluetoothHandsfreeNotificationHandler* aNotificationHandler,
|
BluetoothHandsfreeNotificationHandler* aNotificationHandler) = 0;
|
||||||
int aMaxNumClients, BluetoothHandsfreeResultHandler* aRes) = 0;
|
|
||||||
virtual void Cleanup(BluetoothHandsfreeResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
/* Connect / Disconnect */
|
/* Connect / Disconnect */
|
||||||
|
|
||||||
@ -295,8 +309,6 @@ class BluetoothA2dpResultHandler
|
|||||||
public:
|
public:
|
||||||
virtual void OnError(BluetoothStatus aStatus);
|
virtual void OnError(BluetoothStatus aStatus);
|
||||||
|
|
||||||
virtual void Init();
|
|
||||||
virtual void Cleanup();
|
|
||||||
virtual void Connect();
|
virtual void Connect();
|
||||||
virtual void Disconnect();
|
virtual void Disconnect();
|
||||||
|
|
||||||
@ -307,9 +319,8 @@ protected:
|
|||||||
class BluetoothA2dpInterface
|
class BluetoothA2dpInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void Init(BluetoothA2dpNotificationHandler* aNotificationHandler,
|
virtual void SetNotificationHandler(
|
||||||
BluetoothA2dpResultHandler* aRes) = 0;
|
BluetoothA2dpNotificationHandler* aNotificationHandler) = 0;
|
||||||
virtual void Cleanup(BluetoothA2dpResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
virtual void Connect(const BluetoothAddress& aBdAddr,
|
virtual void Connect(const BluetoothAddress& aBdAddr,
|
||||||
BluetoothA2dpResultHandler* aRes) = 0;
|
BluetoothA2dpResultHandler* aRes) = 0;
|
||||||
@ -382,9 +393,6 @@ class BluetoothAvrcpResultHandler
|
|||||||
public:
|
public:
|
||||||
virtual void OnError(BluetoothStatus aStatus);
|
virtual void OnError(BluetoothStatus aStatus);
|
||||||
|
|
||||||
virtual void Init();
|
|
||||||
virtual void Cleanup();
|
|
||||||
|
|
||||||
virtual void GetPlayStatusRsp();
|
virtual void GetPlayStatusRsp();
|
||||||
|
|
||||||
virtual void ListPlayerAppAttrRsp();
|
virtual void ListPlayerAppAttrRsp();
|
||||||
@ -409,9 +417,8 @@ protected:
|
|||||||
class BluetoothAvrcpInterface
|
class BluetoothAvrcpInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler,
|
virtual void SetNotificationHandler(
|
||||||
BluetoothAvrcpResultHandler* aRes) = 0;
|
BluetoothAvrcpNotificationHandler* aNotificationHandler) = 0;
|
||||||
virtual void Cleanup(BluetoothAvrcpResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
virtual void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
|
virtual void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
|
||||||
uint32_t aSongLen, uint32_t aSongPos,
|
uint32_t aSongLen, uint32_t aSongPos,
|
||||||
@ -663,9 +670,6 @@ class BluetoothGattResultHandler
|
|||||||
public:
|
public:
|
||||||
virtual void OnError(BluetoothStatus aStatus);
|
virtual void OnError(BluetoothStatus aStatus);
|
||||||
|
|
||||||
virtual void Init();
|
|
||||||
virtual void Cleanup();
|
|
||||||
|
|
||||||
virtual void RegisterClient();
|
virtual void RegisterClient();
|
||||||
virtual void UnregisterClient();
|
virtual void UnregisterClient();
|
||||||
|
|
||||||
@ -723,9 +727,8 @@ protected:
|
|||||||
class BluetoothGattInterface
|
class BluetoothGattInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual void Init(BluetoothGattNotificationHandler* aNotificationHandler,
|
virtual void SetNotificationHandler(
|
||||||
BluetoothGattResultHandler* aRes) = 0;
|
BluetoothGattNotificationHandler* aNotificationHandler) = 0;
|
||||||
virtual void Cleanup(BluetoothGattResultHandler* aRes) = 0;
|
|
||||||
|
|
||||||
/* Register / Unregister */
|
/* Register / Unregister */
|
||||||
virtual void RegisterClient(const BluetoothUuid& aUuid,
|
virtual void RegisterClient(const BluetoothUuid& aUuid,
|
||||||
@ -1111,6 +1114,7 @@ public:
|
|||||||
|
|
||||||
/* Profile Interfaces */
|
/* Profile Interfaces */
|
||||||
|
|
||||||
|
virtual BluetoothSetupInterface* GetBluetoothSetupInterface() = 0;
|
||||||
virtual BluetoothSocketInterface* GetBluetoothSocketInterface() = 0;
|
virtual BluetoothSocketInterface* GetBluetoothSocketInterface() = 0;
|
||||||
virtual BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() = 0;
|
virtual BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() = 0;
|
||||||
virtual BluetoothA2dpInterface* GetBluetoothA2dpInterface() = 0;
|
virtual BluetoothA2dpInterface* GetBluetoothA2dpInterface() = 0;
|
||||||
|
@ -998,7 +998,7 @@ BrowserElementParent.prototype = {
|
|||||||
try {
|
try {
|
||||||
let nfcContentHelper =
|
let nfcContentHelper =
|
||||||
Cc["@mozilla.org/nfc/content-helper;1"].getService(Ci.nsINfcBrowserAPI);
|
Cc["@mozilla.org/nfc/content-helper;1"].getService(Ci.nsINfcBrowserAPI);
|
||||||
nfcContentHelper.setFocusApp(tabId, isFocus);
|
nfcContentHelper.setFocusTab(tabId, isFocus);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// Not all platforms support NFC
|
// Not all platforms support NFC
|
||||||
}
|
}
|
||||||
|
@ -97,8 +97,8 @@ NfcContentHelper.prototype = {
|
|||||||
return cpmm.sendSyncMessage("NFC:QueryInfo")[0].rfState;
|
return cpmm.sendSyncMessage("NFC:QueryInfo")[0].rfState;
|
||||||
},
|
},
|
||||||
|
|
||||||
setFocusApp: function setFocusApp(tabId, isFocus) {
|
setFocusTab: function setFocusTab(tabId, isFocus) {
|
||||||
cpmm.sendAsyncMessage("NFC:SetFocusApp", {
|
cpmm.sendAsyncMessage("NFC:SetFocusTab", {
|
||||||
tabId: tabId,
|
tabId: tabId,
|
||||||
isFocus: isFocus
|
isFocus: isFocus
|
||||||
});
|
});
|
||||||
|
@ -79,7 +79,7 @@ const NFC_IPC_MSG_ENTRIES = [
|
|||||||
"NFC:NotifyUserAcceptedP2P",
|
"NFC:NotifyUserAcceptedP2P",
|
||||||
"NFC:NotifySendFileStatus",
|
"NFC:NotifySendFileStatus",
|
||||||
"NFC:ChangeRFState",
|
"NFC:ChangeRFState",
|
||||||
"NFC:SetFocusApp"] }
|
"NFC:SetFocusTab"] }
|
||||||
];
|
];
|
||||||
|
|
||||||
// Should be consistent with NfcRequestType defined in NfcOptions.webidl.
|
// Should be consistent with NfcRequestType defined in NfcOptions.webidl.
|
||||||
@ -148,7 +148,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||||||
|
|
||||||
eventListeners: {},
|
eventListeners: {},
|
||||||
|
|
||||||
focusApp: NFC.SYSTEM_APP_ID,
|
focusId: NFC.SYSTEM_APP_ID,
|
||||||
|
|
||||||
init: function init(nfc) {
|
init: function init(nfc) {
|
||||||
this.nfc = nfc;
|
this.nfc = nfc;
|
||||||
@ -214,7 +214,7 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
notifyFocusApp: function notifyFocusApp(options) {
|
notifyFocusTab: function notifyFocusTab(options) {
|
||||||
let tabId = this.getFocusTabId();
|
let tabId = this.getFocusTabId();
|
||||||
options.tabId = tabId;
|
options.tabId = tabId;
|
||||||
|
|
||||||
@ -231,29 +231,29 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||||||
},
|
},
|
||||||
|
|
||||||
getFocusTabId: function getFocusTabId() {
|
getFocusTabId: function getFocusTabId() {
|
||||||
return this.eventListeners[this.focusApp] ? this.focusApp
|
return this.eventListeners[this.focusId] ? this.focusId
|
||||||
: NFC.SYSTEM_APP_ID;
|
: NFC.SYSTEM_APP_ID;
|
||||||
},
|
},
|
||||||
|
|
||||||
setFocusApp: function setFocusApp(id, isFocus) {
|
setFocusTab: function setFocusTab(id, isFocus) {
|
||||||
// if calling setNFCFocus(true) on the browser-element which is already
|
// if calling setNFCFocus(true) on the browser-element which is already
|
||||||
// focused, or calling setNFCFocus(false) on the browser-element which has
|
// focused, or calling setNFCFocus(false) on the browser-element which has
|
||||||
// lost focus already, ignore.
|
// lost focus already, ignore.
|
||||||
if (isFocus == (id == this.focusApp)) {
|
if (isFocus == (id == this.focusId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.focusApp != NFC.SYSTEM_APP_ID) {
|
if (this.focusId != NFC.SYSTEM_APP_ID) {
|
||||||
this.onFocusChanged(this.focusApp, false);
|
this.onFocusChanged(this.focusId, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isFocus) {
|
if (isFocus) {
|
||||||
// Now we only support one focus app.
|
// Now we only support one focus app.
|
||||||
this.focusApp = id;
|
this.focusId = id;
|
||||||
this.onFocusChanged(this.focusApp, true);
|
this.onFocusChanged(this.focusId, true);
|
||||||
} else if (this.focusApp == id){
|
} else if (this.focusId == id){
|
||||||
// Set focusApp to SystemApp means currently there is no foreground app.
|
// Set focusId to SystemApp means currently there is no foreground app.
|
||||||
this.focusApp = NFC.SYSTEM_APP_ID;
|
this.focusId = NFC.SYSTEM_APP_ID;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -325,17 +325,17 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||||||
|
|
||||||
onTagFound: function onTagFound(message) {
|
onTagFound: function onTagFound(message) {
|
||||||
message.event = NFC.TAG_EVENT_FOUND;
|
message.event = NFC.TAG_EVENT_FOUND;
|
||||||
this.notifyFocusApp(message);
|
this.notifyFocusTab(message);
|
||||||
delete message.event;
|
delete message.event;
|
||||||
},
|
},
|
||||||
|
|
||||||
onTagLost: function onTagLost(sessionToken) {
|
onTagLost: function onTagLost(sessionToken) {
|
||||||
this.notifyFocusApp({ event: NFC.TAG_EVENT_LOST,
|
this.notifyFocusTab({ event: NFC.TAG_EVENT_LOST,
|
||||||
sessionToken: sessionToken });
|
sessionToken: sessionToken });
|
||||||
},
|
},
|
||||||
|
|
||||||
onPeerEvent: function onPeerEvent(eventType, sessionToken) {
|
onPeerEvent: function onPeerEvent(eventType, sessionToken) {
|
||||||
this.notifyFocusApp({ event: eventType,
|
this.notifyFocusTab({ event: eventType,
|
||||||
sessionToken: sessionToken });
|
sessionToken: sessionToken });
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -348,13 +348,13 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onFocusChanged: function onFocusChanged(focusApp, focus) {
|
onFocusChanged: function onFocusChanged(focusId, focus) {
|
||||||
let target = this.eventListeners[focusApp];
|
let target = this.eventListeners[focusId];
|
||||||
if (!target) {
|
if (!target) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.notifyDOMEvent(target, { tabId: this.focusApp,
|
this.notifyDOMEvent(target, { tabId: this.focusId,
|
||||||
event: NFC.FOCUS_CHANGED,
|
event: NFC.FOCUS_CHANGED,
|
||||||
focus: focus });
|
focus: focus });
|
||||||
},
|
},
|
||||||
@ -386,8 +386,8 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (message.name) {
|
switch (message.name) {
|
||||||
case "NFC:SetFocusApp":
|
case "NFC:SetFocusTab":
|
||||||
this.setFocusApp(message.data.tabId, message.data.isFocus);
|
this.setFocusTab(message.data.tabId, message.data.isFocus);
|
||||||
return null;
|
return null;
|
||||||
case "NFC:AddEventListener":
|
case "NFC:AddEventListener":
|
||||||
this.addEventListener(message.target, message.data.tabId);
|
this.addEventListener(message.target, message.data.tabId);
|
||||||
|
@ -115,12 +115,12 @@ interface nsINfcRequestCallback : nsISupports
|
|||||||
void notifyError(in DOMString errorMsg);
|
void notifyError(in DOMString errorMsg);
|
||||||
};
|
};
|
||||||
|
|
||||||
[scriptable, uuid(2dbc73d4-ba16-4c89-bce5-3c22cee6b50a)]
|
[scriptable, uuid(9f86c799-6959-4ad2-bdd6-6fbf49b52d1c)]
|
||||||
interface nsINfcBrowserAPI : nsISupports
|
interface nsINfcBrowserAPI : nsISupports
|
||||||
{
|
{
|
||||||
const int32_t SYSTEM_APP_ID = 0;
|
const int32_t SYSTEM_APP_ID = 0;
|
||||||
|
|
||||||
void setFocusApp(in uint64_t tabId,
|
void setFocusTab(in uint64_t tabId,
|
||||||
in boolean isFocus);
|
in boolean isFocus);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ class BaseStackFrame {
|
|||||||
|
|
||||||
// Get a unique identifier for this StackFrame. The identifier is not valid
|
// Get a unique identifier for this StackFrame. The identifier is not valid
|
||||||
// across garbage collections.
|
// across garbage collections.
|
||||||
virtual uint64_t identifier() const { return reinterpret_cast<uint64_t>(ptr); }
|
virtual uint64_t identifier() const { return uint64_t(uintptr_t(ptr)); }
|
||||||
|
|
||||||
// Get this frame's parent frame.
|
// Get this frame's parent frame.
|
||||||
virtual StackFrame parent() const = 0;
|
virtual StackFrame parent() const = 0;
|
||||||
@ -418,7 +418,11 @@ class StackFrame : public JS::Traceable {
|
|||||||
// Methods that forward to virtual calls through BaseStackFrame.
|
// Methods that forward to virtual calls through BaseStackFrame.
|
||||||
|
|
||||||
void trace(JSTracer* trc) { base()->trace(trc); }
|
void trace(JSTracer* trc) { base()->trace(trc); }
|
||||||
uint64_t identifier() const { return base()->identifier(); }
|
uint64_t identifier() const {
|
||||||
|
auto id = base()->identifier();
|
||||||
|
MOZ_ASSERT(JS::Value::isNumberRepresentable(id));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
uint32_t line() const { return base()->line(); }
|
uint32_t line() const { return base()->line(); }
|
||||||
uint32_t column() const { return base()->column(); }
|
uint32_t column() const { return base()->column(); }
|
||||||
AtomOrTwoByteChars source() const { return base()->source(); }
|
AtomOrTwoByteChars source() const { return base()->source(); }
|
||||||
@ -564,7 +568,7 @@ class Base {
|
|||||||
// caveats about multiple objects allocated at the same address for
|
// caveats about multiple objects allocated at the same address for
|
||||||
// 'ubi::Node::operator=='.)
|
// 'ubi::Node::operator=='.)
|
||||||
using Id = uint64_t;
|
using Id = uint64_t;
|
||||||
virtual Id identifier() const { return reinterpret_cast<Id>(ptr); }
|
virtual Id identifier() const { return Id(uintptr_t(ptr)); }
|
||||||
|
|
||||||
// Returns true if this node is pointing to something on the live heap, as
|
// Returns true if this node is pointing to something on the live heap, as
|
||||||
// opposed to something from a deserialized core dump. Returns false,
|
// opposed to something from a deserialized core dump. Returns false,
|
||||||
@ -790,7 +794,11 @@ class Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
using Id = Base::Id;
|
using Id = Base::Id;
|
||||||
Id identifier() const { return base()->identifier(); }
|
Id identifier() const {
|
||||||
|
auto id = base()->identifier();
|
||||||
|
MOZ_ASSERT(JS::Value::isNumberRepresentable(id));
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
// A hash policy for ubi::Nodes.
|
// A hash policy for ubi::Nodes.
|
||||||
// This simply uses the stock PointerHasher on the ubi::Node's pointer.
|
// This simply uses the stock PointerHasher on the ubi::Node's pointer.
|
||||||
|
Before Width: | Height: | Size: 785 B After Width: | Height: | Size: 502 B |
Before Width: | Height: | Size: 90 B After Width: | Height: | Size: 254 B |
Before Width: | Height: | Size: 904 B After Width: | Height: | Size: 555 B |
Before Width: | Height: | Size: 108 B After Width: | Height: | Size: 315 B |
After Width: | Height: | Size: 688 B |
After Width: | Height: | Size: 391 B |
@ -732,7 +732,7 @@ nsHttpHandler::InitUserAgentComponents()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#if defined(ANDROID) || defined(FXOS_SIMULATOR)
|
#ifdef ANDROID
|
||||||
nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
|
nsCOMPtr<nsIPropertyBag2> infoService = do_GetService("@mozilla.org/system-info;1");
|
||||||
MOZ_ASSERT(infoService, "Could not find a system info service");
|
MOZ_ASSERT(infoService, "Could not find a system info service");
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
@ -753,15 +753,35 @@ nsHttpHandler::InitUserAgentComponents()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Add the `Mobile` or `Tablet` token when running on device or in the
|
// Add the `Mobile` or `Tablet` or `TV` token when running on device.
|
||||||
// b2g desktop simulator.
|
|
||||||
bool isTablet;
|
bool isTablet;
|
||||||
rv = infoService->GetPropertyAsBool(NS_LITERAL_STRING("tablet"), &isTablet);
|
rv = infoService->GetPropertyAsBool(NS_LITERAL_STRING("tablet"), &isTablet);
|
||||||
if (NS_SUCCEEDED(rv) && isTablet)
|
if (NS_SUCCEEDED(rv) && isTablet) {
|
||||||
mCompatDevice.AssignLiteral("Tablet");
|
mCompatDevice.AssignLiteral("Tablet");
|
||||||
else
|
} else {
|
||||||
mCompatDevice.AssignLiteral("Mobile");
|
bool isTV;
|
||||||
#endif
|
rv = infoService->GetPropertyAsBool(NS_LITERAL_STRING("tv"), &isTV);
|
||||||
|
if (NS_SUCCEEDED(rv) && isTV) {
|
||||||
|
mCompatDevice.AssignLiteral("TV");
|
||||||
|
} else {
|
||||||
|
mCompatDevice.AssignLiteral("Mobile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // ANDROID
|
||||||
|
|
||||||
|
#ifdef FXOS_SIMULATOR
|
||||||
|
{
|
||||||
|
// Add the `Mobile` or `Tablet` or `TV` token when running in the b2g
|
||||||
|
// desktop simulator via preference.
|
||||||
|
nsCString deviceType;
|
||||||
|
nsresult rv = Preferences::GetCString("devtools.useragent.device_type", &deviceType);
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
mCompatDevice.Assign(deviceType);
|
||||||
|
} else {
|
||||||
|
mCompatDevice.AssignLiteral("Mobile");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // FXOS_SIMULATOR
|
||||||
|
|
||||||
#if defined(MOZ_WIDGET_GONK)
|
#if defined(MOZ_WIDGET_GONK)
|
||||||
// Device model identifier should be a simple token, which can be composed
|
// Device model identifier should be a simple token, which can be composed
|
||||||
|
8
testing/talos/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
.Python
|
||||||
|
bin/
|
||||||
|
include/
|
||||||
|
lib/
|
||||||
|
talos.egg-info
|
||||||
|
talos/tests/tp5n.zip
|
||||||
|
talos/tests/tp5n
|
||||||
|
talos/tests/devtools/damp.manifest.develop
|
@ -358,6 +358,7 @@ class damp(PageloaderTest):
|
|||||||
sps_profile_entries = 1000000
|
sps_profile_entries = 1000000
|
||||||
win_counters = w7_counters = linux_counters = mac_counters = None
|
win_counters = w7_counters = linux_counters = mac_counters = None
|
||||||
filters = filter.ignore_first.prepare(1) + filter.median.prepare()
|
filters = filter.ignore_first.prepare(1) + filter.median.prepare()
|
||||||
|
preferences = {'devtools.memory.enabled': True}
|
||||||
|
|
||||||
|
|
||||||
@register_test()
|
@register_test()
|
||||||
|
@ -16,6 +16,7 @@ var defaultConfig = {
|
|||||||
styleEditorOpen: true,
|
styleEditorOpen: true,
|
||||||
performanceOpen: true,
|
performanceOpen: true,
|
||||||
netmonitorOpen: true,
|
netmonitorOpen: true,
|
||||||
|
saveAndReadHeapSnapshot: true,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -25,7 +26,8 @@ var testsInfo = {
|
|||||||
debuggerOpen: "Measure open/close toolbox on debugger panel",
|
debuggerOpen: "Measure open/close toolbox on debugger panel",
|
||||||
styleEditorOpen: "Measure open/close toolbox on style editor panel",
|
styleEditorOpen: "Measure open/close toolbox on style editor panel",
|
||||||
performanceOpen: "Measure open/close toolbox on performance panel",
|
performanceOpen: "Measure open/close toolbox on performance panel",
|
||||||
netmonitorOpen: "Measure open/close toolbox on network monitor panel"
|
netmonitorOpen: "Measure open/close toolbox on network monitor panel",
|
||||||
|
saveAndReadHeapSnapshot: "Measure open/close toolbox on memory panel and save/read heap snapshot",
|
||||||
};
|
};
|
||||||
|
|
||||||
function updateConfig() {
|
function updateConfig() {
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
|
|
||||||
Components.utils.import("resource:///modules/devtools/client/framework/gDevTools.jsm");
|
Components.utils.import("resource:///modules/devtools/client/framework/gDevTools.jsm");
|
||||||
const {devtools} =
|
const {devtools} =
|
||||||
Components.utils.import("resource://gre/modules/devtools/shared/Loader.jsm", {});
|
Components.utils.import("resource://gre/modules/devtools/shared/Loader.jsm", {});
|
||||||
const { getActiveTab } = devtools.require("sdk/tabs/utils");
|
const { getActiveTab } = devtools.require("sdk/tabs/utils");
|
||||||
const { getMostRecentBrowserWindow } = devtools.require("sdk/window/utils");
|
const { getMostRecentBrowserWindow } = devtools.require("sdk/window/utils");
|
||||||
|
const ThreadSafeChromeUtils = devtools.require("ThreadSafeChromeUtils");
|
||||||
|
|
||||||
const SIMPLE_URL = "chrome://damp/content/pages/simple.html";
|
const SIMPLE_URL = "chrome://damp/content/pages/simple.html";
|
||||||
const COMPLICATED_URL = "http://localhost/tests/tp5n/bild.de/www.bild.de/index.html";
|
const COMPLICATED_URL = "http://localhost/tests/tp5n/bild.de/www.bild.de/index.html";
|
||||||
|
|
||||||
function Damp() {
|
function Damp() {
|
||||||
|
// Path to the temp file where the heap snapshot file is saved. Set by
|
||||||
|
// saveHeapSnapshot and read by readHeapSnapshot.
|
||||||
|
this._heapSnapshotFilePath = null;
|
||||||
|
// HeapSnapshot instance. Set by readHeapSnapshot, used by takeCensus.
|
||||||
|
this._snapshot = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Damp.prototype = {
|
Damp.prototype = {
|
||||||
@ -69,6 +74,71 @@ Damp.prototype = {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
saveHeapSnapshot: function(label) {
|
||||||
|
let tab = getActiveTab(getMostRecentBrowserWindow());
|
||||||
|
let target = devtools.TargetFactory.forTab(tab);
|
||||||
|
let toolbox = gDevTools.getToolbox(target);
|
||||||
|
let panel = toolbox.getCurrentPanel();
|
||||||
|
let memoryFront = panel.panelWin.gFront;
|
||||||
|
|
||||||
|
let start = performance.now();
|
||||||
|
return memoryFront.saveHeapSnapshot().then(filePath => {
|
||||||
|
this._heapSnapshotFilePath = filePath;
|
||||||
|
let end = performance.now();
|
||||||
|
this._results.push({
|
||||||
|
name: label + ".saveHeapSnapshot",
|
||||||
|
value: end - start
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
readHeapSnapshot: function(label) {
|
||||||
|
let start = performance.now();
|
||||||
|
this._snapshot = ThreadSafeChromeUtils.readHeapSnapshot(this._heapSnapshotFilePath);
|
||||||
|
let end = performance.now();
|
||||||
|
this._results.push({
|
||||||
|
name: label + ".readHeapSnapshot",
|
||||||
|
value: end - start
|
||||||
|
});
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
|
takeCensus: function(label) {
|
||||||
|
let start = performance.now();
|
||||||
|
|
||||||
|
this._snapshot.takeCensus({
|
||||||
|
breakdown: {
|
||||||
|
by: "coarseType",
|
||||||
|
objects: {
|
||||||
|
by: "objectClass",
|
||||||
|
then: { by: "count", bytes: true, count: true },
|
||||||
|
other: { by: "count", bytes: true, count: true }
|
||||||
|
},
|
||||||
|
strings: {
|
||||||
|
by: "internalType",
|
||||||
|
then: { by: "count", bytes: true, count: true }
|
||||||
|
},
|
||||||
|
scripts: {
|
||||||
|
by: "internalType",
|
||||||
|
then: { by: "count", bytes: true, count: true }
|
||||||
|
},
|
||||||
|
other: {
|
||||||
|
by: "internalType",
|
||||||
|
then: { by: "count", bytes: true, count: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let end = performance.now();
|
||||||
|
|
||||||
|
this._results.push({
|
||||||
|
name: label + ".takeCensus",
|
||||||
|
value: end - start
|
||||||
|
});
|
||||||
|
|
||||||
|
return Promise.resolve();
|
||||||
|
},
|
||||||
|
|
||||||
_startTest: function() {
|
_startTest: function() {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
@ -76,6 +146,9 @@ Damp.prototype = {
|
|||||||
var closeToolbox = this.closeToolbox.bind(this);
|
var closeToolbox = this.closeToolbox.bind(this);
|
||||||
var reloadPage = this.reloadPage.bind(this);
|
var reloadPage = this.reloadPage.bind(this);
|
||||||
var next = this._nextCommand.bind(this);
|
var next = this._nextCommand.bind(this);
|
||||||
|
var saveHeapSnapshot = this.saveHeapSnapshot.bind(this);
|
||||||
|
var readHeapSnapshot = this.readHeapSnapshot.bind(this);
|
||||||
|
var takeCensus = this.takeCensus.bind(this);
|
||||||
var config = this._config;
|
var config = this._config;
|
||||||
var rest = config.rest; // How long to wait in between opening the tab and starting the test.
|
var rest = config.rest; // How long to wait in between opening the tab and starting the test.
|
||||||
|
|
||||||
@ -135,6 +208,14 @@ Damp.prototype = {
|
|||||||
() => { closeToolbox(label + ".netmonitor").then(next); },
|
() => { closeToolbox(label + ".netmonitor").then(next); },
|
||||||
],
|
],
|
||||||
|
|
||||||
|
saveAndReadHeapSnapshot: [
|
||||||
|
() => { openToolbox(label + ".memory", "memory").then(next); },
|
||||||
|
() => { reloadPage(label + ".memory").then(next); },
|
||||||
|
() => { saveHeapSnapshot(label).then(next); },
|
||||||
|
() => { readHeapSnapshot(label).then(next); },
|
||||||
|
() => { takeCensus(label).then(next); },
|
||||||
|
() => { closeToolbox(label + ".memory").then(next); },
|
||||||
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Construct the sequence array: config.repeat times config.subtests,
|
// Construct the sequence array: config.repeat times config.subtests,
|
||||||
|
@ -186,6 +186,8 @@ tests:
|
|||||||
allowed_build_tasks:
|
allowed_build_tasks:
|
||||||
tasks/builds/b2g_emulator_ics_opt.yml:
|
tasks/builds/b2g_emulator_ics_opt.yml:
|
||||||
task: tasks/tests/b2g_emulator_crashtest.yml
|
task: tasks/tests/b2g_emulator_crashtest.yml
|
||||||
|
tasks/builds/b2g_emulator_x86_kk_opt.yml:
|
||||||
|
task: tasks/tests/b2g_emulator_crashtest.yml
|
||||||
gaia-build:
|
gaia-build:
|
||||||
allowed_build_tasks:
|
allowed_build_tasks:
|
||||||
tasks/builds/b2g_desktop_opt.yml:
|
tasks/builds/b2g_desktop_opt.yml:
|
||||||
|
@ -32,7 +32,9 @@ task:
|
|||||||
extra:
|
extra:
|
||||||
chunks:
|
chunks:
|
||||||
total: 5
|
total: 5
|
||||||
|
treeherderEnv:
|
||||||
|
- production
|
||||||
|
- staging
|
||||||
treeherder:
|
treeherder:
|
||||||
groupName: Reftest
|
groupName: Reftest
|
||||||
groupSymbol: tc-R
|
groupSymbol: tc-R
|
||||||
|
@ -13,6 +13,8 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
|||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "devtools",
|
XPCOMUtils.defineLazyModuleGetter(this, "devtools",
|
||||||
"resource://gre/modules/devtools/shared/Loader.jsm");
|
"resource://gre/modules/devtools/shared/Loader.jsm");
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
|
||||||
|
"resource://gre/modules/LoginManagerContent.jsm");
|
||||||
|
|
||||||
Object.defineProperty(this, "WebConsoleUtils", {
|
Object.defineProperty(this, "WebConsoleUtils", {
|
||||||
get: function() {
|
get: function() {
|
||||||
@ -47,50 +49,6 @@ this.InsecurePasswordUtils = {
|
|||||||
Services.console.logMessage(consoleMsg);
|
Services.console.logMessage(consoleMsg);
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
|
||||||
* Checks whether the passed uri is secure
|
|
||||||
* Check Protocol Flags to determine if scheme is secure:
|
|
||||||
* URI_DOES_NOT_RETURN_DATA - e.g.
|
|
||||||
* "mailto"
|
|
||||||
* URI_IS_LOCAL_RESOURCE - e.g.
|
|
||||||
* "data",
|
|
||||||
* "resource",
|
|
||||||
* "moz-icon"
|
|
||||||
* URI_INHERITS_SECURITY_CONTEXT - e.g.
|
|
||||||
* "javascript"
|
|
||||||
* URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT - e.g.
|
|
||||||
* "https",
|
|
||||||
* "moz-safe-about"
|
|
||||||
*
|
|
||||||
* The use of this logic comes directly from nsMixedContentBlocker.cpp
|
|
||||||
* At the time it was decided to include these protocols since a secure
|
|
||||||
* uri for mixed content blocker means that the resource can't be
|
|
||||||
* easily tampered with because 1) it is sent over an encrypted channel or
|
|
||||||
* 2) it is a local resource that never hits the network
|
|
||||||
* or 3) it is a request sent without any response that could alter
|
|
||||||
* the behavior of the page. It was decided to include the same logic
|
|
||||||
* here both to be consistent with MCB and to make sure we cover all
|
|
||||||
* "safe" protocols. Eventually, the code here and the code in MCB
|
|
||||||
* will be moved to a common location that will be referenced from
|
|
||||||
* both places. Look at
|
|
||||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=899099 for more info.
|
|
||||||
*/
|
|
||||||
_checkIfURIisSecure : function(uri) {
|
|
||||||
let isSafe = false;
|
|
||||||
let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil);
|
|
||||||
let ph = Ci.nsIProtocolHandler;
|
|
||||||
|
|
||||||
if (netutil.URIChainHasFlags(uri, ph.URI_IS_LOCAL_RESOURCE) ||
|
|
||||||
netutil.URIChainHasFlags(uri, ph.URI_DOES_NOT_RETURN_DATA) ||
|
|
||||||
netutil.URIChainHasFlags(uri, ph.URI_INHERITS_SECURITY_CONTEXT) ||
|
|
||||||
netutil.URIChainHasFlags(uri, ph.URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT)) {
|
|
||||||
|
|
||||||
isSafe = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isSafe;
|
|
||||||
},
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks whether the passed nested document is insecure
|
* Checks whether the passed nested document is insecure
|
||||||
* or is inside an insecure parent document.
|
* or is inside an insecure parent document.
|
||||||
@ -109,7 +67,7 @@ this.InsecurePasswordUtils = {
|
|||||||
// We are at the top, nothing to check here
|
// We are at the top, nothing to check here
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this._checkIfURIisSecure(uri)) {
|
if (!LoginManagerContent.checkIfURIisSecure(uri)) {
|
||||||
// We are insecure
|
// We are insecure
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -127,7 +85,7 @@ this.InsecurePasswordUtils = {
|
|||||||
checkForInsecurePasswords : function (aForm) {
|
checkForInsecurePasswords : function (aForm) {
|
||||||
var domDoc = aForm.ownerDocument;
|
var domDoc = aForm.ownerDocument;
|
||||||
let pageURI = domDoc.defaultView.top.document.documentURIObject;
|
let pageURI = domDoc.defaultView.top.document.documentURIObject;
|
||||||
let isSafePage = this._checkIfURIisSecure(pageURI);
|
let isSafePage = LoginManagerContent.checkIfURIisSecure(pageURI);
|
||||||
|
|
||||||
if (!isSafePage) {
|
if (!isSafePage) {
|
||||||
this._sendWebConsoleMessage("InsecurePasswordsPresentOnPage", domDoc);
|
this._sendWebConsoleMessage("InsecurePasswordsPresentOnPage", domDoc);
|
||||||
|
@ -414,6 +414,18 @@ var LoginManagerContent = {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Returns true if this window or any subframes have insecure login forms.
|
||||||
|
let hasInsecureLoginForms = (thisWindow, parentIsInsecure) => {
|
||||||
|
let doc = thisWindow.document;
|
||||||
|
let isInsecure =
|
||||||
|
parentIsInsecure ||
|
||||||
|
!this.checkIfURIisSecure(doc.documentURIObject);
|
||||||
|
let hasLoginForm = !!this.stateForDocument(doc).loginForm;
|
||||||
|
return (hasLoginForm && isInsecure) ||
|
||||||
|
Array.some(thisWindow.frames,
|
||||||
|
frame => hasInsecureLoginForms(frame, isInsecure));
|
||||||
|
};
|
||||||
|
|
||||||
// Store the actual form to use on the state for the top-level document.
|
// Store the actual form to use on the state for the top-level document.
|
||||||
let topState = this.stateForDocument(topWindow.document);
|
let topState = this.stateForDocument(topWindow.document);
|
||||||
topState.loginFormForFill = getFirstLoginForm(topWindow);
|
topState.loginFormForFill = getFirstLoginForm(topWindow);
|
||||||
@ -423,6 +435,7 @@ var LoginManagerContent = {
|
|||||||
messageManager.sendAsyncMessage("RemoteLogins:updateLoginFormPresence", {
|
messageManager.sendAsyncMessage("RemoteLogins:updateLoginFormPresence", {
|
||||||
loginFormOrigin,
|
loginFormOrigin,
|
||||||
loginFormPresent: !!topState.loginFormForFill,
|
loginFormPresent: !!topState.loginFormForFill,
|
||||||
|
hasInsecureLoginForms: hasInsecureLoginForms(topWindow, false),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1089,6 +1102,49 @@ var LoginManagerContent = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Checks whether the passed uri is secure
|
||||||
|
* Check Protocol Flags to determine if scheme is secure:
|
||||||
|
* URI_DOES_NOT_RETURN_DATA - e.g.
|
||||||
|
* "mailto"
|
||||||
|
* URI_IS_LOCAL_RESOURCE - e.g.
|
||||||
|
* "data",
|
||||||
|
* "resource",
|
||||||
|
* "moz-icon"
|
||||||
|
* URI_INHERITS_SECURITY_CONTEXT - e.g.
|
||||||
|
* "javascript"
|
||||||
|
* URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT - e.g.
|
||||||
|
* "https",
|
||||||
|
* "moz-safe-about"
|
||||||
|
*
|
||||||
|
* The use of this logic comes directly from nsMixedContentBlocker.cpp
|
||||||
|
* At the time it was decided to include these protocols since a secure
|
||||||
|
* uri for mixed content blocker means that the resource can't be
|
||||||
|
* easily tampered with because 1) it is sent over an encrypted channel or
|
||||||
|
* 2) it is a local resource that never hits the network
|
||||||
|
* or 3) it is a request sent without any response that could alter
|
||||||
|
* the behavior of the page. It was decided to include the same logic
|
||||||
|
* here both to be consistent with MCB and to make sure we cover all
|
||||||
|
* "safe" protocols. Eventually, the code here and the code in MCB
|
||||||
|
* will be moved to a common location that will be referenced from
|
||||||
|
* both places. Look at
|
||||||
|
* https://bugzilla.mozilla.org/show_bug.cgi?id=899099 for more info.
|
||||||
|
*/
|
||||||
|
checkIfURIisSecure : function(uri) {
|
||||||
|
let isSafe = false;
|
||||||
|
let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil);
|
||||||
|
let ph = Ci.nsIProtocolHandler;
|
||||||
|
|
||||||
|
if (netutil.URIChainHasFlags(uri, ph.URI_IS_LOCAL_RESOURCE) ||
|
||||||
|
netutil.URIChainHasFlags(uri, ph.URI_DOES_NOT_RETURN_DATA) ||
|
||||||
|
netutil.URIChainHasFlags(uri, ph.URI_INHERITS_SECURITY_CONTEXT) ||
|
||||||
|
netutil.URIChainHasFlags(uri, ph.URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT)) {
|
||||||
|
|
||||||
|
isSafe = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isSafe;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var LoginUtils = {
|
var LoginUtils = {
|
||||||
|
@ -569,12 +569,23 @@ var LoginManagerParent = {
|
|||||||
return loginFormState;
|
return loginFormState;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the page currently loaded in the given browser element has
|
||||||
|
* insecure login forms. This state may be updated asynchronously, in which
|
||||||
|
* case a custom event named InsecureLoginFormsStateChange will be dispatched
|
||||||
|
* on the browser element.
|
||||||
|
*/
|
||||||
|
hasInsecureLoginForms(browser) {
|
||||||
|
return !!this.stateForBrowser(browser).hasInsecureLoginForms;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called to indicate whether a login form on the currently loaded page is
|
* Called to indicate whether a login form on the currently loaded page is
|
||||||
* present or not. This is one of the factors used to control the visibility
|
* present or not. This is one of the factors used to control the visibility
|
||||||
* of the password fill doorhanger.
|
* of the password fill doorhanger.
|
||||||
*/
|
*/
|
||||||
updateLoginFormPresence(browser, { loginFormOrigin, loginFormPresent }) {
|
updateLoginFormPresence(browser, { loginFormOrigin, loginFormPresent,
|
||||||
|
hasInsecureLoginForms }) {
|
||||||
const ANCHOR_DELAY_MS = 200;
|
const ANCHOR_DELAY_MS = 200;
|
||||||
|
|
||||||
let state = this.stateForBrowser(browser);
|
let state = this.stateForBrowser(browser);
|
||||||
@ -583,8 +594,13 @@ var LoginManagerParent = {
|
|||||||
// processed in order, this will always be the latest version to use.
|
// processed in order, this will always be the latest version to use.
|
||||||
state.loginFormOrigin = loginFormOrigin;
|
state.loginFormOrigin = loginFormOrigin;
|
||||||
state.loginFormPresent = loginFormPresent;
|
state.loginFormPresent = loginFormPresent;
|
||||||
|
state.hasInsecureLoginForms = hasInsecureLoginForms;
|
||||||
|
|
||||||
// Apply the data to the currently displayed icon later.
|
// Report the insecure login form state immediately.
|
||||||
|
browser.dispatchEvent(new browser.ownerDocument.defaultView
|
||||||
|
.CustomEvent("InsecureLoginFormsStateChange"));
|
||||||
|
|
||||||
|
// Apply the data to the currently displayed login fill icon later.
|
||||||
if (!state.anchorDeferredTask) {
|
if (!state.anchorDeferredTask) {
|
||||||
state.anchorDeferredTask = new DeferredTask(
|
state.anchorDeferredTask = new DeferredTask(
|
||||||
() => this.updateLoginAnchor(browser),
|
() => this.updateLoginAnchor(browser),
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
support-files =
|
support-files =
|
||||||
authenticate.sjs
|
authenticate.sjs
|
||||||
form_basic.html
|
form_basic.html
|
||||||
|
insecure_test.html
|
||||||
|
insecure_test_subframe.html
|
||||||
multiple_forms.html
|
multiple_forms.html
|
||||||
|
|
||||||
[browser_DOMFormHasPassword.js]
|
[browser_DOMFormHasPassword.js]
|
||||||
[browser_DOMInputPasswordAdded.js]
|
[browser_DOMInputPasswordAdded.js]
|
||||||
[browser_filldoorhanger.js]
|
[browser_filldoorhanger.js]
|
||||||
|
[browser_hasInsecureLoginForms.js]
|
||||||
[browser_notifications.js]
|
[browser_notifications.js]
|
||||||
skip-if = true # Intermittent failures: Bug 1182296, bug 1148771
|
skip-if = true # Intermittent failures: Bug 1182296, bug 1148771
|
||||||
[browser_passwordmgr_editing.js]
|
[browser_passwordmgr_editing.js]
|
||||||
|
@ -0,0 +1,93 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/LoginManagerParent.jsm", this);
|
||||||
|
|
||||||
|
const testUrlPath =
|
||||||
|
"://example.com/browser/toolkit/components/passwordmgr/test/browser/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the given number of occurrences of InsecureLoginFormsStateChange
|
||||||
|
* on the given browser element.
|
||||||
|
*/
|
||||||
|
function waitForInsecureLoginFormsStateChange(browser, count) {
|
||||||
|
return BrowserTestUtils.waitForEvent(browser, "InsecureLoginFormsStateChange",
|
||||||
|
false, () => --count == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that hasInsecureLoginForms is true for a simple HTTP page and false
|
||||||
|
* for a simple HTTPS page.
|
||||||
|
*/
|
||||||
|
add_task(function* test_simple() {
|
||||||
|
for (let scheme of ["http", "https"]) {
|
||||||
|
let tab = gBrowser.addTab(scheme + testUrlPath + "form_basic.html");
|
||||||
|
let browser = tab.linkedBrowser;
|
||||||
|
yield Promise.all([
|
||||||
|
BrowserTestUtils.switchTab(gBrowser, tab),
|
||||||
|
BrowserTestUtils.browserLoaded(browser),
|
||||||
|
// One event is triggered by pageshow and one by DOMFormHasPassword.
|
||||||
|
waitForInsecureLoginFormsStateChange(browser, 2),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Assert.equal(LoginManagerParent.hasInsecureLoginForms(browser),
|
||||||
|
scheme == "http");
|
||||||
|
|
||||||
|
gBrowser.removeTab(tab);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks that hasInsecureLoginForms is true if a password field is present in
|
||||||
|
* an HTTP page loaded as a subframe of a top-level HTTPS page, when mixed
|
||||||
|
* active content blocking is disabled.
|
||||||
|
*
|
||||||
|
* When the subframe is navigated to an HTTPS page, hasInsecureLoginForms should
|
||||||
|
* be set to false.
|
||||||
|
*
|
||||||
|
* Moving back in history should set hasInsecureLoginForms to true again.
|
||||||
|
*/
|
||||||
|
add_task(function* test_subframe_navigation() {
|
||||||
|
yield new Promise(resolve => SpecialPowers.pushPrefEnv({
|
||||||
|
"set": [["security.mixed_content.block_active_content", false]],
|
||||||
|
}, resolve));
|
||||||
|
|
||||||
|
// Load the page with the subframe in a new tab.
|
||||||
|
let tab = gBrowser.addTab("https" + testUrlPath + "insecure_test.html");
|
||||||
|
let browser = tab.linkedBrowser;
|
||||||
|
yield Promise.all([
|
||||||
|
BrowserTestUtils.switchTab(gBrowser, tab),
|
||||||
|
BrowserTestUtils.browserLoaded(browser),
|
||||||
|
// Two events are triggered by pageshow and one by DOMFormHasPassword.
|
||||||
|
waitForInsecureLoginFormsStateChange(browser, 3),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Assert.ok(LoginManagerParent.hasInsecureLoginForms(browser));
|
||||||
|
|
||||||
|
// Navigate the subframe to a secure page.
|
||||||
|
let promiseSubframeReady = Promise.all([
|
||||||
|
BrowserTestUtils.browserLoaded(browser, true),
|
||||||
|
// One event is triggered by pageshow and one by DOMFormHasPassword.
|
||||||
|
waitForInsecureLoginFormsStateChange(browser, 2),
|
||||||
|
]);
|
||||||
|
yield ContentTask.spawn(browser, null, function* () {
|
||||||
|
content.document.getElementById("test-iframe")
|
||||||
|
.contentDocument.getElementById("test-link").click();
|
||||||
|
});
|
||||||
|
yield promiseSubframeReady;
|
||||||
|
|
||||||
|
Assert.ok(!LoginManagerParent.hasInsecureLoginForms(browser));
|
||||||
|
|
||||||
|
// Navigate back to the insecure page. We only have to wait for the
|
||||||
|
// InsecureLoginFormsStateChange event that is triggered by pageshow.
|
||||||
|
let promise = waitForInsecureLoginFormsStateChange(browser, 1);
|
||||||
|
yield ContentTask.spawn(browser, null, function* () {
|
||||||
|
content.document.getElementById("test-iframe")
|
||||||
|
.contentWindow.history.back();
|
||||||
|
});
|
||||||
|
yield promise;
|
||||||
|
|
||||||
|
Assert.ok(LoginManagerParent.hasInsecureLoginForms(browser));
|
||||||
|
|
||||||
|
gBrowser.removeTab(tab);
|
||||||
|
});
|
@ -0,0 +1,9 @@
|
|||||||
|
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
|
||||||
|
<!-- Any copyright is dedicated to the Public Domain.
|
||||||
|
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||||
|
|
||||||
|
<!-- This frame is initially loaded over HTTP. -->
|
||||||
|
<iframe id="test-iframe"
|
||||||
|
src="http://example.org/browser/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html"/>
|
||||||
|
|
||||||
|
</body></html>
|
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>
|
||||||
|
<!-- Any copyright is dedicated to the Public Domain.
|
||||||
|
- http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<input name="password" type="password">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- Link to reload this page over HTTPS. -->
|
||||||
|
<a id="test-link"
|
||||||
|
href="https://example.org/browser/toolkit/components/passwordmgr/test/browser/insecure_test_subframe.html">HTTPS</a>
|
||||||
|
|
||||||
|
</body></html>
|
@ -810,11 +810,13 @@ var StackRenderer = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function SymbolicationRequest(aPrefix, aRenderHeader, aMemoryMap, aStacks) {
|
function SymbolicationRequest(aPrefix, aRenderHeader,
|
||||||
|
aMemoryMap, aStacks, aDurations = null) {
|
||||||
this.prefix = aPrefix;
|
this.prefix = aPrefix;
|
||||||
this.renderHeader = aRenderHeader;
|
this.renderHeader = aRenderHeader;
|
||||||
this.memoryMap = aMemoryMap;
|
this.memoryMap = aMemoryMap;
|
||||||
this.stacks = aStacks;
|
this.stacks = aStacks;
|
||||||
|
this.durations = aDurations;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* A callback for onreadystatechange. It replaces the numeric stack with
|
* A callback for onreadystatechange. It replaces the numeric stack with
|
||||||
@ -848,7 +850,7 @@ function SymbolicationRequest_handleSymbolResponse() {
|
|||||||
|
|
||||||
for (let i = 0; i < jsonResponse.length; ++i) {
|
for (let i = 0; i < jsonResponse.length; ++i) {
|
||||||
let stack = jsonResponse[i];
|
let stack = jsonResponse[i];
|
||||||
this.renderHeader(i);
|
this.renderHeader(i, this.durations);
|
||||||
|
|
||||||
for (let symbol of stack) {
|
for (let symbol of stack) {
|
||||||
div.appendChild(document.createTextNode(symbol));
|
div.appendChild(document.createTextNode(symbol));
|
||||||
@ -894,14 +896,14 @@ var ChromeHangs = {
|
|||||||
|
|
||||||
let stacks = hangs.stacks;
|
let stacks = hangs.stacks;
|
||||||
let memoryMap = hangs.memoryMap;
|
let memoryMap = hangs.memoryMap;
|
||||||
|
let durations = hangs.durations;
|
||||||
|
|
||||||
StackRenderer.renderStacks("chrome-hangs", stacks, memoryMap,
|
StackRenderer.renderStacks("chrome-hangs", stacks, memoryMap,
|
||||||
(index) => this.renderHangHeader(aPing, index));
|
(index) => this.renderHangHeader(index, durations));
|
||||||
},
|
},
|
||||||
|
|
||||||
renderHangHeader: function ChromeHangs_renderHangHeader(aPing, aIndex) {
|
renderHangHeader: function ChromeHangs_renderHangHeader(aIndex, aDurations) {
|
||||||
let durations = aPing.payload.chromeHangs.durations;
|
StackRenderer.renderHeader("chrome-hangs", [aIndex + 1, aDurations[aIndex]]);
|
||||||
StackRenderer.renderHeader("chrome-hangs", [aIndex + 1, durations[aIndex]]);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1391,7 +1393,9 @@ function setupListeners() {
|
|||||||
let hangs = gPingData.payload.chromeHangs;
|
let hangs = gPingData.payload.chromeHangs;
|
||||||
let req = new SymbolicationRequest("chrome-hangs",
|
let req = new SymbolicationRequest("chrome-hangs",
|
||||||
ChromeHangs.renderHangHeader,
|
ChromeHangs.renderHangHeader,
|
||||||
hangs.memoryMap, hangs.stacks);
|
hangs.memoryMap,
|
||||||
|
hangs.stacks,
|
||||||
|
hangs.durations);
|
||||||
req.fetchSymbols();
|
req.fetchSymbols();
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
@ -743,6 +743,8 @@ nsSystemInfo::Init()
|
|||||||
if (__system_property_get("ro.build.characteristics", characteristics)) {
|
if (__system_property_get("ro.build.characteristics", characteristics)) {
|
||||||
if (!strcmp(characteristics, "tablet")) {
|
if (!strcmp(characteristics, "tablet")) {
|
||||||
SetPropertyAsBool(NS_LITERAL_STRING("tablet"), true);
|
SetPropertyAsBool(NS_LITERAL_STRING("tablet"), true);
|
||||||
|
} else if (!strcmp(characteristics, "tv")) {
|
||||||
|
SetPropertyAsBool(NS_LITERAL_STRING("tv"), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|