Merge m-c to inbound a=merge

This commit is contained in:
Wes Kocher 2014-12-30 16:04:20 -08:00
commit e8cbaaf86b
34 changed files with 351 additions and 228 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e"> <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<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="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -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="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>

View File

@ -17,7 +17,7 @@
</project> </project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<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="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/> <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a2e84985476d4b1fa518b7465a26cfe596923e7"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a2e84985476d4b1fa518b7465a26cfe596923e7"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e"> <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<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="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -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="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/> <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d5d3f93914558b6f168447b805cd799c8233e300"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e"> <project name="platform_build" path="build" remote="b2g" revision="e0c735ec89df011ea7dd435087a9045ecff9ff9e">
<copyfile dest="Makefile" src="core/root.mk"/> <copyfile dest="Makefile" src="core/root.mk"/>
</project> </project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<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="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project> </project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<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="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/> <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a2e84985476d4b1fa518b7465a26cfe596923e7"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a2e84985476d4b1fa518b7465a26cfe596923e7"/>

View File

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

View File

@ -17,7 +17,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="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/> <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>

View File

@ -15,7 +15,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="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project> </project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<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="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/> <project name="moztt" path="external/moztt" remote="b2g" revision="fe893bb760a3bb64375f62fdf4762a58c59df9ef"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a2e84985476d4b1fa518b7465a26cfe596923e7"/> <project name="apitrace" path="external/apitrace" remote="apitrace" revision="6a2e84985476d4b1fa518b7465a26cfe596923e7"/>

View File

@ -17,7 +17,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="322ef5116a5827a30c9a3cd9b842449a9c66a5b3"/> <project name="gaia.git" path="gaia" remote="mozillaorg" revision="26d479f0fccb7174e06255121e4e938c1b280d67"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/> <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="8aee09c106f479f36c57b2a29af72d455e359211"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/> <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/> <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -533,6 +533,7 @@
@BINPATH@/components/nsNfc.js @BINPATH@/components/nsNfc.js
@BINPATH@/components/Nfc.manifest @BINPATH@/components/Nfc.manifest
@BINPATH@/components/Nfc.js @BINPATH@/components/Nfc.js
@BINPATH@/components/NfcContentHelper.manifest
@BINPATH@/components/NfcContentHelper.js @BINPATH@/components/NfcContentHelper.js
#endif #endif
#ifdef MOZ_ENABLE_DBUS #ifdef MOZ_ENABLE_DBUS

View File

@ -301,13 +301,22 @@ NfcContentHelper.prototype = {
this.eventListener.notifyPeerLost(result.sessionToken); this.eventListener.notifyPeerLost(result.sessionToken);
break; break;
case NFC.TAG_EVENT_FOUND: case NFC.TAG_EVENT_FOUND:
let event = new NfcTagEvent(result.techList, let ndefInfo = null;
result.tagType, if (result.tagType !== undefined &&
result.maxNDEFSize !== undefined &&
result.isReadOnly !== undefined &&
result.isFormatable !== undefined) {
ndefInfo = new TagNDEFInfo(result.tagType,
result.maxNDEFSize, result.maxNDEFSize,
result.isReadOnly, result.isReadOnly,
result.isFormatable); result.isFormatable);
}
this.eventListener.notifyTagFound(result.sessionToken, event, result.records); let tagInfo = new TagInfo(result.techList);
this.eventListener.notifyTagFound(result.sessionToken,
tagInfo,
ndefInfo,
result.records);
break; break;
case NFC.TAG_EVENT_LOST: case NFC.TAG_EVENT_LOST:
this.eventListener.notifyTagLost(result.sessionToken); this.eventListener.notifyTagLost(result.sessionToken);
@ -387,23 +396,30 @@ NfcContentHelper.prototype = {
}, },
}; };
function NfcTagEvent(techList, tagType, maxNDEFSize, isReadOnly, isFormatable) { function TagNDEFInfo(tagType, maxNDEFSize, isReadOnly, isFormatable) {
this.techList = techList;
this.tagType = tagType; this.tagType = tagType;
this.maxNDEFSize = maxNDEFSize; this.maxNDEFSize = maxNDEFSize;
this.isReadOnly = isReadOnly; this.isReadOnly = isReadOnly;
this.isFormatable = isFormatable; this.isFormatable = isFormatable;
} }
NfcTagEvent.prototype = { TagNDEFInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsINfcTagEvent]), QueryInterface: XPCOMUtils.generateQI([Ci.nsITagNDEFInfo]),
techList: null,
tagType: null, tagType: null,
maxNDEFSize: 0, maxNDEFSize: 0,
isReadOnly: false, isReadOnly: false,
isFormatable: false isFormatable: false
}; };
function TagInfo(techList) {
this.techList = techList;
}
TagInfo.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsITagInfo]),
techList: null,
};
if (NFC_ENABLED) { if (NFC_ENABLED) {
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NfcContentHelper]); this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NfcContentHelper]);
} }

View File

@ -0,0 +1,7 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# NfcContentHelper.js
component {4d72c120-da5f-11e1-9b23-0800200c9a66} NfcContentHelper.js
contract @mozilla.org/nfc/content-helper;1 {4d72c120-da5f-11e1-9b23-0800200c9a66}
category profile-after-change NfcContentHelper @mozilla.org/nfc/content-helper;1

View File

@ -9,7 +9,3 @@ component {2ff24790-5e74-11e1-b86c-0800200c9a66} Nfc.js
contract @mozilla.org/nfc;1 {2ff24790-5e74-11e1-b86c-0800200c9a66} contract @mozilla.org/nfc;1 {2ff24790-5e74-11e1-b86c-0800200c9a66}
category profile-after-change Nfc @mozilla.org/nfc;1 category profile-after-change Nfc @mozilla.org/nfc;1
# NfcContentHelper.js
component {4d72c120-da5f-11e1-9b23-0800200c9a66} NfcContentHelper.js
contract @mozilla.org/nfc/content-helper;1 {4d72c120-da5f-11e1-9b23-0800200c9a66}
category profile-after-change NfcContentHelper @mozilla.org/nfc/content-helper;1

View File

@ -19,6 +19,7 @@ if CONFIG['MOZ_NFC']:
] ]
EXTRA_COMPONENTS += [ EXTRA_COMPONENTS += [
'NfcContentHelper.js', 'NfcContentHelper.js',
'NfcContentHelper.manifest',
'nsNfc.js', 'nsNfc.js',
'nsNfc.manifest', 'nsNfc.manifest',
] ]

View File

@ -7,11 +7,18 @@
interface nsIVariant; interface nsIVariant;
interface nsIDOMWindow; interface nsIDOMWindow;
[scriptable, uuid(9b43bdda-52f4-4712-b28c-ad7cba736e14)] [scriptable, uuid(30d77baf-50ed-4a6b-ab75-25bade40977a)]
interface nsINfcTagEvent : nsISupports interface nsITagInfo : nsISupports
{ {
/**
* Array of technolgies supported. See NFCTechType in MozNFCTag.webidl
*/
readonly attribute nsIVariant techList; readonly attribute nsIVariant techList;
};
[scriptable, uuid(74d70ebb-557f-4ac8-8296-7885961cd1dc)]
interface nsITagNDEFInfo : nsISupports
{
// one of NFCTagType defined in MozNFCTag.webidl. // one of NFCTagType defined in MozNFCTag.webidl.
readonly attribute DOMString tagType; readonly attribute DOMString tagType;
@ -22,7 +29,7 @@ interface nsINfcTagEvent : nsISupports
readonly attribute boolean isFormatable; readonly attribute boolean isFormatable;
}; };
[scriptable, uuid(fcbd98d6-3d04-4657-bd64-1164e311b399)] [scriptable, uuid(be09c440-8385-4210-bb7b-7d3333ec3d43)]
interface nsINfcEventListener : nsISupports interface nsINfcEventListener : nsISupports
{ {
/** /**
@ -30,13 +37,17 @@ interface nsINfcEventListener : nsISupports
* *
* @param sessionToken * @param sessionToken
* SessionToken received from parent process * SessionToken received from parent process
* @param event * @param tagInfo
* nsINfcTagFoundEvent received from parent process. * nsITagInfo received from parent process.
* @param ndefInfo
* nsITagNDEFInfo received from parent process, could be null if the
* tag is not formated as NDEF.
* @param ndefRecords * @param ndefRecords
* NDEF records pre-read during tag-discovered. * NDEF records pre-read during tag-discovered.
*/ */
void notifyTagFound(in DOMString sessionToken, void notifyTagFound(in DOMString sessionToken,
in nsINfcTagEvent event, in nsITagInfo tagInfo,
in nsITagNDEFInfo ndefInfo,
in nsIVariant ndefRecords); in nsIVariant ndefRecords);
/** /**

View File

@ -94,23 +94,25 @@ NfcCallback.prototype = {
* *
* @param window global window object. * @param window global window object.
* @param sessionToken session token received from parent process. * @param sessionToken session token received from parent process.
* @parem event type of nsINfcTagEvent received from parent process. * @param tagInfo type of nsITagInfo received from parent process.
* @parem ndefInfo type of nsITagNDEFInfo received from parent process.
*/ */
function MozNFCTagImpl(window, sessionToken, event) { function MozNFCTagImpl(window, sessionToken, tagInfo, ndefInfo) {
debug("In MozNFCTagImpl Constructor"); debug("In MozNFCTagImpl Constructor");
this._nfcContentHelper = Cc["@mozilla.org/nfc/content-helper;1"] this._nfcContentHelper = Cc["@mozilla.org/nfc/content-helper;1"]
.getService(Ci.nsINfcContentHelper); .getService(Ci.nsINfcContentHelper);
this._window = window; this._window = window;
this.session = sessionToken; this.session = sessionToken;
this.techList = event.techList; this.techList = tagInfo.techList;
this.type = event.tagType || null;
this.maxNDEFSize = event.maxNDEFSize || null; if (ndefInfo) {
this.isReadOnly = event.isReadOnly || null; this.type = ndefInfo.tagType;
this.isFormatable = event.isFormatable || null; this.maxNDEFSize = ndefInfo.maxNDEFSize;
this.canBeMadeReadOnly = this.type ? this.isReadOnly = ndefInfo.isReadOnly;
(this.type == "type1" || this.type == "type2" || this.isFormatable = ndefInfo.isFormatable;
this.type == "mifare_classic") : this.canBeMadeReadOnly = this.type == "type1" || this.type == "type2" ||
null; this.type == "mifare_classic";
}
} }
MozNFCTagImpl.prototype = { MozNFCTagImpl.prototype = {
_nfcContentHelper: null, _nfcContentHelper: null,
@ -118,10 +120,10 @@ MozNFCTagImpl.prototype = {
session: null, session: null,
techList: null, techList: null,
type: null, type: null,
maxNDEFSize: 0, maxNDEFSize: null,
isReadOnly: false, isReadOnly: null,
isFormatable: false, isFormatable: null,
canBeMadeReadOnly: false, canBeMadeReadOnly: null,
isLost: false, isLost: false,
// NFCTag interface: // NFCTag interface:
@ -365,7 +367,7 @@ MozNFCImpl.prototype = {
this._nfcContentHelper.unregisterTargetForPeerReady(appId); this._nfcContentHelper.unregisterTargetForPeerReady(appId);
}, },
notifyTagFound: function notifyTagFound(sessionToken, event, records) { notifyTagFound: function notifyTagFound(sessionToken, tagInfo, ndefInfo, records) {
if (this.hasDeadWrapper()) { if (this.hasDeadWrapper()) {
dump("this._window or this.__DOM_IMPL__ is a dead wrapper."); dump("this._window or this.__DOM_IMPL__ is a dead wrapper.");
return; return;
@ -383,7 +385,7 @@ MozNFCImpl.prototype = {
this.eventService.addSystemEventListener(this._window, "visibilitychange", this.eventService.addSystemEventListener(this._window, "visibilitychange",
this, /* useCapture */false); this, /* useCapture */false);
let tagImpl = new MozNFCTagImpl(this._window, sessionToken, event); let tagImpl = new MozNFCTagImpl(this._window, sessionToken, tagInfo, ndefInfo);
let tag = this._window.MozNFCTag._create(this._window, tagImpl); let tag = this._window.MozNFCTag._create(this._window, tagImpl);
this.nfcTag = tag; this.nfcTag = tag;

View File

@ -254,6 +254,7 @@ class PaintedLayerData {
public: public:
PaintedLayerData() : PaintedLayerData() :
mAnimatedGeometryRoot(nullptr), mAnimatedGeometryRoot(nullptr),
mIsAsyncScrollable(false),
mFixedPosFrameForLayerData(nullptr), mFixedPosFrameForLayerData(nullptr),
mReferenceFrame(nullptr), mReferenceFrame(nullptr),
mLayer(nullptr), mLayer(nullptr),
@ -342,7 +343,16 @@ public:
void CopyAboveRegion(PaintedLayerData* aOther) void CopyAboveRegion(PaintedLayerData* aOther)
{ {
if (aOther->mAllDrawingAbove || mAllDrawingAbove) { // If aOther has a draw region and is subject to async transforms then the
// layer can potentially be moved arbitrarily on the compositor. So we
// should avoid moving display items from on top of the layer to below the
// layer, which we do by calling SetAllDrawingAbove. Note that if the draw
// region is empty (such as when aOther has only event-regions items) then
// we don't need to do this.
bool aOtherCanDrawAnywhere = aOther->IsSubjectToAsyncTransforms()
&& !aOther->mDrawRegion.IsEmpty();
if (aOther->mAllDrawingAbove || mAllDrawingAbove || aOtherCanDrawAnywhere) {
SetAllDrawingAbove(); SetAllDrawingAbove();
} else { } else {
mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleAboveRegion); mVisibleAboveRegion.Or(mVisibleAboveRegion, aOther->mVisibleAboveRegion);
@ -386,7 +396,8 @@ public:
bool IsSubjectToAsyncTransforms() bool IsSubjectToAsyncTransforms()
{ {
return mFixedPosFrameForLayerData != nullptr; return mFixedPosFrameForLayerData != nullptr
|| mIsAsyncScrollable;
} }
/** /**
@ -425,6 +436,12 @@ public:
* active scrolled root. * active scrolled root.
*/ */
const nsIFrame* mAnimatedGeometryRoot; const nsIFrame* mAnimatedGeometryRoot;
/**
* Whether or not this layer is async scrollable. If it is, that means display
* items above this layer should not end up in a layer below this one, as they
* might be obscured when they shouldn't be.
*/
bool mIsAsyncScrollable;
/** /**
* If non-null, the frame from which we'll extract "fixed positioning" * If non-null, the frame from which we'll extract "fixed positioning"
* metadata for this layer. This can be a position:fixed frame or a viewport * metadata for this layer. This can be a position:fixed frame or a viewport
@ -815,6 +832,13 @@ protected:
* flag, and pop it off the stack. * flag, and pop it off the stack.
*/ */
void PopPaintedLayerData(); void PopPaintedLayerData();
/**
* Check if any of the animated geometry roots from aAnimatedGeometryRoot up
* to and including mContainerAnimatedGeometryRoot are async scrollable. If
* so, return true. This is used to flag a particular PaintedLayer as being
* subject to async transforms.
*/
bool HasAsyncScrollableGeometryInContainer(const nsIFrame* aAnimatedGeometryRoot);
/** /**
* Find the PaintedLayer to which we should assign the next display item. * Find the PaintedLayer to which we should assign the next display item.
* We scan the PaintedLayerData stack to find the topmost PaintedLayer * We scan the PaintedLayerData stack to find the topmost PaintedLayer
@ -2482,6 +2506,28 @@ PaintedLayerData::Accumulate(ContainerState* aState,
} }
} }
bool
ContainerState::HasAsyncScrollableGeometryInContainer(const nsIFrame* aAnimatedGeometryRoot)
{
const nsIFrame* f = aAnimatedGeometryRoot;
while (f) {
if (nsLayoutUtils::GetScrollableFrameFor(f) &&
nsLayoutUtils::GetDisplayPort(f->GetContent(), nullptr)) {
return true;
}
if (f == mContainerAnimatedGeometryRoot) {
break;
}
nsIFrame* fParent = nsLayoutUtils::GetCrossDocParentFrame(f);
if (!fParent) {
break;
}
f = nsLayoutUtils::GetAnimatedGeometryRootForFrame(
this->mBuilder, fParent, mContainerAnimatedGeometryRoot);
}
return false;
}
PaintedLayerData* PaintedLayerData*
ContainerState::FindPaintedLayerFor(nsDisplayItem* aItem, ContainerState::FindPaintedLayerFor(nsDisplayItem* aItem,
const nsIntRect& aVisibleRect, const nsIntRect& aVisibleRect,
@ -2549,6 +2595,8 @@ ContainerState::FindPaintedLayerFor(nsDisplayItem* aItem,
paintedLayerData->mAnimatedGeometryRoot = aAnimatedGeometryRoot; paintedLayerData->mAnimatedGeometryRoot = aAnimatedGeometryRoot;
paintedLayerData->mFixedPosFrameForLayerData = paintedLayerData->mFixedPosFrameForLayerData =
FindFixedPosFrameForLayerData(aAnimatedGeometryRoot, aShouldFixToViewport); FindFixedPosFrameForLayerData(aAnimatedGeometryRoot, aShouldFixToViewport);
paintedLayerData->mIsAsyncScrollable =
HasAsyncScrollableGeometryInContainer(aAnimatedGeometryRoot);
paintedLayerData->mReferenceFrame = aItem->ReferenceFrame(); paintedLayerData->mReferenceFrame = aItem->ReferenceFrame();
paintedLayerData->mSingleItemFixedToViewport = aShouldFixToViewport; paintedLayerData->mSingleItemFixedToViewport = aShouldFixToViewport;

View File

@ -1182,12 +1182,28 @@ nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParen
return false; return false;
} }
bool
nsDisplayListBuilder::GetCachedAnimatedGeometryRoot(const nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor,
nsIFrame** aOutResult)
{
AnimatedGeometryRootLookup lookup(aFrame, aStopAtAncestor);
return mAnimatedGeometryRootCache.Get(lookup, aOutResult);
}
static nsIFrame* static nsIFrame*
ComputeAnimatedGeometryRootFor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, ComputeAnimatedGeometryRootFor(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor = nullptr) const nsIFrame* aStopAtAncestor = nullptr,
bool aUseCache = false)
{ {
nsIFrame* cursor = aFrame; nsIFrame* cursor = aFrame;
while (cursor != aStopAtAncestor) { while (cursor != aStopAtAncestor) {
if (aUseCache) {
nsIFrame* result;
if (aBuilder->GetCachedAnimatedGeometryRoot(cursor, aStopAtAncestor, &result)) {
return result;
}
}
nsIFrame* next; nsIFrame* next;
if (aBuilder->IsAnimatedGeometryRoot(cursor, &next)) if (aBuilder->IsAnimatedGeometryRoot(cursor, &next))
return cursor; return cursor;
@ -1202,13 +1218,19 @@ nsDisplayListBuilder::FindAnimatedGeometryRootFor(nsIFrame* aFrame, const nsIFra
if (aFrame == mCurrentFrame) { if (aFrame == mCurrentFrame) {
return mCurrentAnimatedGeometryRoot; return mCurrentAnimatedGeometryRoot;
} }
return ComputeAnimatedGeometryRootFor(this, aFrame, aStopAtAncestor);
nsIFrame* result = ComputeAnimatedGeometryRootFor(this, aFrame, aStopAtAncestor, true);
AnimatedGeometryRootLookup lookup(aFrame, aStopAtAncestor);
mAnimatedGeometryRootCache.Put(lookup, result);
return result;
} }
void void
nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot() nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot()
{ {
mCurrentAnimatedGeometryRoot = ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame *>(mCurrentFrame)); mCurrentAnimatedGeometryRoot = ComputeAnimatedGeometryRootFor(this, const_cast<nsIFrame *>(mCurrentFrame));
AnimatedGeometryRootLookup lookup(mCurrentFrame, nullptr);
mAnimatedGeometryRootCache.Put(lookup, mCurrentAnimatedGeometryRoot);
} }
void void

View File

@ -795,6 +795,15 @@ public:
bool IsInWillChangeBudget(nsIFrame* aFrame) const; bool IsInWillChangeBudget(nsIFrame* aFrame) const;
/**
* Look up the cached animated geometry root for aFrame subject to
* aStopAtAncestor. Store the nsIFrame* result into *aOutResult, and return
* true if the cache was hit. Return false if the cache was not hit.
*/
bool GetCachedAnimatedGeometryRoot(const nsIFrame* aFrame,
const nsIFrame* aStopAtAncestor,
nsIFrame** aOutResult);
private: private:
void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame, void MarkOutOfFlowFrameForDisplay(nsIFrame* aDirtyFrame, nsIFrame* aFrame,
const nsRect& aDirtyRect); const nsRect& aDirtyRect);
@ -840,6 +849,28 @@ private:
nsPoint mCurrentOffsetToReferenceFrame; nsPoint mCurrentOffsetToReferenceFrame;
// The animated geometry root for mCurrentFrame. // The animated geometry root for mCurrentFrame.
nsIFrame* mCurrentAnimatedGeometryRoot; nsIFrame* mCurrentAnimatedGeometryRoot;
struct AnimatedGeometryRootLookup {
const nsIFrame* mFrame;
const nsIFrame* mStopAtFrame;
AnimatedGeometryRootLookup(const nsIFrame* aFrame, const nsIFrame* aStopAtFrame)
: mFrame(aFrame)
, mStopAtFrame(aStopAtFrame)
{
}
PLDHashNumber Hash() const {
return mozilla::HashBytes(this, sizeof(this));
}
bool operator==(const AnimatedGeometryRootLookup& aOther) const {
return mFrame == aOther.mFrame && mStopAtFrame == aOther.mStopAtFrame;
}
};
// Cache for storing animated geometry roots for arbitrary frames
nsDataHashtable<nsGenericHashKey<AnimatedGeometryRootLookup>, nsIFrame*>
mAnimatedGeometryRootCache;
// will-change budget tracker // will-change budget tracker
nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget> nsDataHashtable<nsPtrHashKey<nsPresContext>, DocumentWillChangeBudget>
mWillChangeBudget; mWillChangeBudget;

View File

@ -1802,7 +1802,7 @@ fuzzy-if(B2G,1,7) == 942672-1.html 942672-1-ref.html
== 950436-1.html 950436-1-ref.html == 950436-1.html 950436-1-ref.html
== 957770-1.svg 957770-1-ref.svg == 957770-1.svg 957770-1-ref.svg
== 960277-1.html 960277-1-ref.html == 960277-1.html 960277-1-ref.html
pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,31) == 966992-1.html 966992-1-ref.html pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,145) == 966992-1.html 966992-1-ref.html
skip-if(Android) == 966510-1.html 966510-1-ref.html # scrollable elements other than the root probably won't work well on android until bug 776030 is fixed skip-if(Android) == 966510-1.html 966510-1-ref.html # scrollable elements other than the root probably won't work well on android until bug 776030 is fixed
skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above
== 978911-1.svg 978911-1-ref.svg == 978911-1.svg 978911-1-ref.svg

View File

@ -8,6 +8,7 @@ package org.mozilla.gecko;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.lang.Override; import java.lang.Override;
import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.EnumSet; import java.util.EnumSet;
@ -16,6 +17,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Vector; import java.util.Vector;
import android.support.v4.app.Fragment;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -651,16 +653,6 @@ public class BrowserApp extends GeckoApp
// Set the maximum bits-per-pixel the favicon system cares about. // Set the maximum bits-per-pixel the favicon system cares about.
IconDirectoryEntry.setMaxBPP(GeckoAppShell.getScreenDepth()); IconDirectoryEntry.setMaxBPP(GeckoAppShell.getScreenDepth());
Class<?> mediaManagerClass = getMediaPlayerManager();
if (mediaManagerClass != null) {
try {
Method init = mediaManagerClass.getMethod("init", Context.class);
init.invoke(null, this);
} catch(Exception ex) {
Log.e(LOGTAG, "Error initializing media manager", ex);
}
}
mTilesRecorder = new TilesRecorder(); mTilesRecorder = new TilesRecorder();
} }
@ -1163,16 +1155,6 @@ public class BrowserApp extends GeckoApp
} }
} }
Class<?> mediaManagerClass = getMediaPlayerManager();
if (mediaManagerClass != null) {
try {
Method destroy = mediaManagerClass.getMethod("onDestroy", (Class[]) null);
destroy.invoke(null);
} catch(Exception ex) {
Log.e(LOGTAG, "Error destroying media manager", ex);
}
}
super.onDestroy(); super.onDestroy();
} }
@ -1599,6 +1581,29 @@ public class BrowserApp extends GeckoApp
} }
}); });
if (AppConstants.MOZ_MEDIA_PLAYER) {
// Check if the fragment is already added. This should never be true here, but this is
// a nice safety check.
// If casting is disabled, these classes aren't built. We use reflection to initialize them.
final Class<?> mediaManagerClass = getMediaPlayerManager();
if (mediaManagerClass != null) {
try {
final String tag = "";
mediaManagerClass.getDeclaredField("MEDIA_PLAYER_TAG").get(tag);
Log.i(LOGTAG, "Found tag " + tag);
final Fragment frag = getSupportFragmentManager().findFragmentByTag(tag);
if (frag == null) {
final Method getInstance = mediaManagerClass.getMethod("newInstance", (Class[]) null);
final Fragment mpm = (Fragment) getInstance.invoke(null);
getSupportFragmentManager().beginTransaction().disallowAddToBackStack().add(mpm, tag).commit();
}
} catch (Exception ex) {
Log.e(LOGTAG, "Error initializing media manager", ex);
}
}
}
if (AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED) { if (AppConstants.MOZ_STUMBLER_BUILD_TIME_ENABLED) {
// Start (this acts as ping if started already) the stumbler lib; if the stumbler has queued data it will upload it. // Start (this acts as ping if started already) the stumbler lib; if the stumbler has queued data it will upload it.
// Stumbler operates on its own thread, and startup impact is further minimized by delaying work (such as upload) a few seconds. // Stumbler operates on its own thread, and startup impact is further minimized by delaying work (such as upload) a few seconds.
@ -1611,6 +1616,7 @@ public class BrowserApp extends GeckoApp
} }
}, oneSecondInMillis); }, oneSecondInMillis);
} }
super.handleMessage(event, message); super.handleMessage(event, message);
} else if (event.equals("Gecko:Ready")) { } else if (event.equals("Gecko:Ready")) {
// Handle this message in GeckoApp, but also enable the Settings // Handle this message in GeckoApp, but also enable the Settings

View File

@ -161,7 +161,7 @@ class ChromeCast implements GeckoMediaPlayer {
public ChromeCast(Context context, RouteInfo route) { public ChromeCast(Context context, RouteInfo route) {
int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context); int status = GooglePlayServicesUtil.isGooglePlayServicesAvailable(context);
if (status != ConnectionResult.SUCCESS) { if (status != ConnectionResult.SUCCESS) {
throw new IllegalStateException("Play services are required for Chromecast support (go status code " + status + ")"); throw new IllegalStateException("Play services are required for Chromecast support (got status code " + status + ")");
} }
this.context = context; this.context = context;

View File

@ -1914,7 +1914,7 @@ public abstract class GeckoApp
} }
if (mAppStateListeners != null) { if (mAppStateListeners != null) {
for (GeckoAppShell.AppStateListener listener: mAppStateListeners) { for (GeckoAppShell.AppStateListener listener : mAppStateListeners) {
listener.onResume(); listener.onResume();
} }
} }
@ -1996,7 +1996,7 @@ public abstract class GeckoApp
}); });
if (mAppStateListeners != null) { if (mAppStateListeners != null) {
for(GeckoAppShell.AppStateListener listener: mAppStateListeners) { for (GeckoAppShell.AppStateListener listener : mAppStateListeners) {
listener.onPause(); listener.onPause();
} }
} }

View File

@ -1175,7 +1175,7 @@ public class GeckoAppShell
} }
final Uri uri = normalizeUriScheme(targetURI.indexOf(':') >= 0 ? Uri.parse(targetURI) : new Uri.Builder().scheme(targetURI).build()); final Uri uri = normalizeUriScheme(targetURI.indexOf(':') >= 0 ? Uri.parse(targetURI) : new Uri.Builder().scheme(targetURI).build());
if (mimeType.length() > 0) { if (!TextUtils.isEmpty(mimeType)) {
Intent intent = getIntentForActionString(action); Intent intent = getIntentForActionString(action);
intent.setDataAndType(uri, mimeType); intent.setDataAndType(uri, mimeType);
return intent; return intent;
@ -1191,8 +1191,10 @@ public class GeckoAppShell
// custom handlers that would apply. // custom handlers that would apply.
// Start with the original URI. If we end up modifying it, we'll // Start with the original URI. If we end up modifying it, we'll
// overwrite it. // overwrite it.
final String extension = MimeTypeMap.getFileExtensionFromUrl(targetURI);
final String mimeType2 = getMimeTypeFromExtension(extension);
final Intent intent = getIntentForActionString(action); final Intent intent = getIntentForActionString(action);
intent.setData(uri); intent.setDataAndType(uri, mimeType2);
if ("vnd.youtube".equals(scheme) && if ("vnd.youtube".equals(scheme) &&
!hasHandlersForIntent(intent) && !hasHandlersForIntent(intent) &&

View File

@ -5,35 +5,44 @@
package org.mozilla.gecko; package org.mozilla.gecko;
import org.mozilla.gecko.util.EventCallback; import android.os.Bundle;
import org.mozilla.gecko.mozglue.JNITarget; import android.support.v4.app.Fragment;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONException;
import android.content.Context;
import android.support.v7.media.MediaControlIntent; import android.support.v7.media.MediaControlIntent;
import android.support.v7.media.MediaRouteSelector; import android.support.v7.media.MediaRouteSelector;
import android.support.v7.media.MediaRouter; import android.support.v7.media.MediaRouter;
import android.support.v7.media.MediaRouter.RouteInfo; import android.support.v7.media.MediaRouter.RouteInfo;
import android.util.Log; import android.util.Log;
import com.google.android.gms.cast.CastMediaControlIntent; import com.google.android.gms.cast.CastMediaControlIntent;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.mozilla.gecko.mozglue.JNITarget;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.NativeEventListener;
import org.mozilla.gecko.util.NativeJSObject;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
/* Manages a list of GeckoMediaPlayers methods (i.e. Chromecast/Miracast). Routes messages /* Manages a list of GeckoMediaPlayers methods (i.e. Chromecast/Miracast). Routes messages
* from Gecko to the correct caster based on the id of the display * from Gecko to the correct caster based on the id of the display
*/ */
class MediaPlayerManager implements NativeEventListener, public class MediaPlayerManager extends Fragment implements NativeEventListener {
GeckoAppShell.AppStateListener { /**
* Create a new instance of DetailsFragment, initialized to
* show the text at 'index'.
*/
@JNITarget
public static MediaPlayerManager newInstance() {
return new MediaPlayerManager();
}
private static final String LOGTAG = "GeckoMediaPlayerManager"; private static final String LOGTAG = "GeckoMediaPlayerManager";
@JNITarget
public static final String MEDIA_PLAYER_TAG = "MPManagerFragment";
private static final boolean SHOW_DEBUG = false; private static final boolean SHOW_DEBUG = false;
// Simplified debugging interfaces // Simplified debugging interfaces
private static void debug(String msg, Exception e) { private static void debug(String msg, Exception e) {
@ -48,62 +57,36 @@ class MediaPlayerManager implements NativeEventListener,
} }
} }
private final Context context; private MediaRouter mediaRouter = null;
private final MediaRouter mediaRouter;
private final Map<String, GeckoMediaPlayer> displays = new HashMap<String, GeckoMediaPlayer>(); private final Map<String, GeckoMediaPlayer> displays = new HashMap<String, GeckoMediaPlayer>();
private static MediaPlayerManager instance;
@JNITarget @Override
public static void init(Context context) { public void onCreate(Bundle savedInstanceState) {
if (instance != null) { super.onCreate(savedInstanceState);
debug("MediaPlayerManager initialized twice");
return;
}
instance = new MediaPlayerManager(context);
}
private MediaPlayerManager(Context context) {
this.context = context;
if (context instanceof GeckoApp) {
GeckoApp app = (GeckoApp) context;
app.addAppStateListener(this);
}
mediaRouter = MediaRouter.getInstance(context);
EventDispatcher.getInstance().registerGeckoThreadListener(this, EventDispatcher.getInstance().registerGeckoThreadListener(this,
"MediaPlayer:Load", "MediaPlayer:Load",
"MediaPlayer:Start", "MediaPlayer:Start",
"MediaPlayer:Stop", "MediaPlayer:Stop",
"MediaPlayer:Play", "MediaPlayer:Play",
"MediaPlayer:Pause", "MediaPlayer:Pause",
"MediaPlayer:Get",
"MediaPlayer:End", "MediaPlayer:End",
"MediaPlayer:Mirror", "MediaPlayer:Mirror",
"MediaPlayer:Message"); "MediaPlayer:Message");
} }
@Override
@JNITarget @JNITarget
public static void onDestroy() { public void onDestroy() {
if (instance == null) { super.onDestroy();
return; EventDispatcher.getInstance().unregisterGeckoThreadListener(this,
}
EventDispatcher.getInstance().unregisterGeckoThreadListener(instance,
"MediaPlayer:Load", "MediaPlayer:Load",
"MediaPlayer:Start", "MediaPlayer:Start",
"MediaPlayer:Stop", "MediaPlayer:Stop",
"MediaPlayer:Play", "MediaPlayer:Play",
"MediaPlayer:Pause", "MediaPlayer:Pause",
"MediaPlayer:Get",
"MediaPlayer:End", "MediaPlayer:End",
"MediaPlayer:Mirror", "MediaPlayer:Mirror",
"MediaPlayer:Message"); "MediaPlayer:Message");
if (instance.context instanceof GeckoApp) {
GeckoApp app = (GeckoApp) instance.context;
app.removeAppStateListener(instance);
}
} }
// GeckoEventListener implementation // GeckoEventListener implementation
@ -111,37 +94,6 @@ class MediaPlayerManager implements NativeEventListener,
public void handleMessage(String event, final NativeJSObject message, final EventCallback callback) { public void handleMessage(String event, final NativeJSObject message, final EventCallback callback) {
debug(event); debug(event);
if ("MediaPlayer:Get".equals(event)) {
final JSONObject result = new JSONObject();
final JSONArray disps = new JSONArray();
final Iterator<GeckoMediaPlayer> items = displays.values().iterator();
while (items.hasNext()) {
GeckoMediaPlayer disp = items.next();
try {
JSONObject json = disp.toJSON();
if (json == null) {
items.remove();
} else {
disps.put(json);
}
} catch(Exception ex) {
// This may happen if the device isn't a real Chromecast,
// for example Matchstick casting devices.
Log.e(LOGTAG, "Couldn't create JSON for display", ex);
}
}
try {
result.put("displays", disps);
} catch(JSONException ex) {
Log.i(LOGTAG, "Error sending displays", ex);
}
callback.sendSuccess(result);
return;
}
final GeckoMediaPlayer display = displays.get(message.getString("id")); final GeckoMediaPlayer display = displays.get(message.getString("id"));
if (display == null) { if (display == null) {
Log.e(LOGTAG, "Couldn't find a display for this id: " + message.getString("id") + " for message: " + event); Log.e(LOGTAG, "Couldn't find a display for this id: " + message.getString("id") + " for message: " + event);
@ -179,6 +131,8 @@ class MediaPlayerManager implements NativeEventListener,
public void onRouteRemoved(MediaRouter router, RouteInfo route) { public void onRouteRemoved(MediaRouter router, RouteInfo route) {
debug("onRouteRemoved: route=" + route); debug("onRouteRemoved: route=" + route);
displays.remove(route.getId()); displays.remove(route.getId());
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
"MediaPlayer:Removed", route.getId()));
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -201,18 +155,22 @@ class MediaPlayerManager implements NativeEventListener,
@Override @Override
public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) { public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
debug("onRouteAdded: route=" + route); debug("onRouteAdded: route=" + route);
GeckoMediaPlayer display = getMediaPlayerForRoute(route); final GeckoMediaPlayer display = getMediaPlayerForRoute(route);
if (display != null) { if (display != null) {
displays.put(route.getId(), display); displays.put(route.getId(), display);
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
"MediaPlayer:Added", display.toJSON().toString()));
} }
} }
@Override @Override
public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) { public void onRouteChanged(MediaRouter router, MediaRouter.RouteInfo route) {
debug("onRouteChanged: route=" + route); debug("onRouteChanged: route=" + route);
GeckoMediaPlayer display = displays.get(route.getId()); final GeckoMediaPlayer display = displays.get(route.getId());
if (display != null) { if (display != null) {
displays.put(route.getId(), display); displays.put(route.getId(), display);
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(
"MediaPlayer:Changed", display.toJSON().toString()));
} }
} }
}; };
@ -220,7 +178,7 @@ class MediaPlayerManager implements NativeEventListener,
private GeckoMediaPlayer getMediaPlayerForRoute(MediaRouter.RouteInfo route) { private GeckoMediaPlayer getMediaPlayerForRoute(MediaRouter.RouteInfo route) {
try { try {
if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) { if (route.supportsControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)) {
return new ChromeCast(context, route); return new ChromeCast(getActivity(), route);
} }
} catch(Exception ex) { } catch(Exception ex) {
debug("Error handling presentation", ex); debug("Error handling presentation", ex);
@ -229,23 +187,28 @@ class MediaPlayerManager implements NativeEventListener,
return null; return null;
} }
/* Implementing GeckoAppShell.AppStateListener */
@Override @Override
public void onPause() { public void onPause() {
super.onPause();
mediaRouter.removeCallback(callback); mediaRouter.removeCallback(callback);
mediaRouter = null;
} }
@Override @Override
public void onResume() { public void onResume() {
MediaRouteSelector selectorBuilder = new MediaRouteSelector.Builder() super.onResume();
// The mediaRouter shouldn't exist here, but this is a nice safety check.
if (mediaRouter != null) {
return;
}
mediaRouter = MediaRouter.getInstance(getActivity());
final MediaRouteSelector selectorBuilder = new MediaRouteSelector.Builder()
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO) .addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK) .addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
.addControlCategory(CastMediaControlIntent.categoryForCast(ChromeCast.MIRROR_RECEIVER_APP_ID)) .addControlCategory(CastMediaControlIntent.categoryForCast(ChromeCast.MIRROR_RECEIVER_APP_ID))
.build(); .build();
mediaRouter.addCallback(selectorBuilder, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY); mediaRouter.addCallback(selectorBuilder, callback, MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
} }
@Override
public void onOrientationChanged() { }
} }

View File

@ -43,7 +43,35 @@ var mediaPlayerDevice = {
return new MediaPlayerApp(aService); return new MediaPlayerApp(aService);
}, },
types: ["video/mp4", "video/webm", "application/x-mpegurl"], types: ["video/mp4", "video/webm", "application/x-mpegurl"],
extensions: ["mp4", "webm", "m3u", "m3u8"] extensions: ["mp4", "webm", "m3u", "m3u8"],
init: function() {
Services.obs.addObserver(this, "MediaPlayer:Added", false);
Services.obs.addObserver(this, "MediaPlayer:Changed", false);
Services.obs.addObserver(this, "MediaPlayer:Removed", false);
},
observe: function(subject, topic, data) {
if (topic === "MediaPlayer:Added") {
let service = this.toService(JSON.parse(data));
SimpleServiceDiscovery.addService(service);
} else if (topic === "MediaPlayer:Changed") {
let service = this.toService(JSON.parse(data));
SimpleServiceDiscovery.updateService(service);
} else if (topic === "MediaPlayer:Removed") {
SimpleServiceDiscovery.removeService(data);
}
},
toService: function(display) {
// Convert the native data into something matching what is created in _processService()
return {
location: display.location,
target: "media:router",
friendlyName: display.friendlyName,
uuid: display.uuid,
manufacturer: display.manufacturer,
modelName: display.modelName,
mirror: display.mirror
};
}
}; };
var CastingApps = { var CastingApps = {
@ -59,6 +87,9 @@ var CastingApps = {
// Register targets // Register targets
SimpleServiceDiscovery.registerDevice(rokuDevice); SimpleServiceDiscovery.registerDevice(rokuDevice);
SimpleServiceDiscovery.registerDevice(matchstickDevice); SimpleServiceDiscovery.registerDevice(matchstickDevice);
// MediaPlayerDevice will notify us any time the native device list changes.
mediaPlayerDevice.init();
SimpleServiceDiscovery.registerDevice(mediaPlayerDevice); SimpleServiceDiscovery.registerDevice(mediaPlayerDevice);
// Search for devices continuously every 120 seconds // Search for devices continuously every 120 seconds

View File

@ -339,6 +339,7 @@ var BrowserApp = {
Services.tm.mainThread.dispatch(function() { Services.tm.mainThread.dispatch(function() {
// Init LoginManager // Init LoginManager
Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager); Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
CastingApps.init();
}, Ci.nsIThread.DISPATCH_NORMAL); }, Ci.nsIThread.DISPATCH_NORMAL);
#ifdef MOZ_SAFE_BROWSING #ifdef MOZ_SAFE_BROWSING
@ -440,7 +441,6 @@ var BrowserApp = {
RemoteDebugger.init(); RemoteDebugger.init();
UserAgentOverrides.init(); UserAgentOverrides.init();
DesktopUserAgent.init(); DesktopUserAgent.init();
CastingApps.init();
Distribution.init(); Distribution.init();
Tabs.init(); Tabs.init();
#ifdef ACCESSIBILITY #ifdef ACCESSIBILITY

View File

@ -9,6 +9,6 @@
# project structure. # project structure.
# Project target. # Project target.
target=android-@ANDROID_TARGET_SDK@ target=android-L
@IDE_PROJECT_LIBRARY_SETTING@ @IDE_PROJECT_LIBRARY_SETTING@
@IDE_PROJECT_LIBRARY_REFERENCES@ @IDE_PROJECT_LIBRARY_REFERENCES@

View File

@ -285,7 +285,8 @@ BrowserTabList.prototype._getBrowsers = function*() {
}; };
BrowserTabList.prototype._getChildren = function(aWindow) { BrowserTabList.prototype._getChildren = function(aWindow) {
return aWindow.gBrowser ? aWindow.gBrowser.browsers : []; let children = aWindow.gBrowser ? aWindow.gBrowser.browsers : [];
return children ? children : [];
}; };
BrowserTabList.prototype._isRemoteBrowser = function(browser) { BrowserTabList.prototype._isRemoteBrowser = function(browser) {

View File

@ -43,6 +43,7 @@ EXTRA_JS_MODULES += [
'RemoteSecurityUI.jsm', 'RemoteSecurityUI.jsm',
'RemoteWebNavigation.jsm', 'RemoteWebNavigation.jsm',
'RemoteWebProgress.jsm', 'RemoteWebProgress.jsm',
'secondscreen/SimpleServiceDiscovery.jsm',
'SelectContentHelper.jsm', 'SelectContentHelper.jsm',
'SelectParentHelper.jsm', 'SelectParentHelper.jsm',
'sessionstore/FormData.jsm', 'sessionstore/FormData.jsm',
@ -63,7 +64,6 @@ EXTRA_PP_JS_MODULES += [
'CertUtils.jsm', 'CertUtils.jsm',
'ResetProfile.jsm', 'ResetProfile.jsm',
'secondscreen/RokuApp.jsm', 'secondscreen/RokuApp.jsm',
'secondscreen/SimpleServiceDiscovery.jsm',
'Services.jsm', 'Services.jsm',
'Troubleshoot.jsm', 'Troubleshoot.jsm',
'UpdateChannel.jsm', 'UpdateChannel.jsm',

View File

@ -12,17 +12,8 @@ const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Timer.jsm"); Cu.import("resource://gre/modules/Timer.jsm");
#ifdef ANDROID
Cu.import("resource://gre/modules/Messaging.jsm");
#endif
// Define the "log" function as a binding of the Log.d function so it specifies
// the "debug" priority and a log tag.
#ifdef ANDROID
let log = Cu.import("resource://gre/modules/AndroidLog.jsm",{}).AndroidLog.d.bind(null, "SSDP");
#else
let log = Cu.reportError; let log = Cu.reportError;
#endif
XPCOMUtils.defineLazyGetter(this, "converter", function () { XPCOMUtils.defineLazyGetter(this, "converter", function () {
let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter); let conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
@ -188,36 +179,8 @@ var SimpleServiceDiscovery = {
timeout += SSDP_TRANSMISSION_INTERVAL; timeout += SSDP_TRANSMISSION_INTERVAL;
} }
} }
#ifdef ANDROID
// We also query Java directly here for any devices that Android might support natively (i.e. Chromecast or Miracast)
this.getAndroidDevices();
#endif
}, },
#ifdef ANDROID
getAndroidDevices: function() {
Messaging.sendRequestForResult({ type: "MediaPlayer:Get" }).then((result) => {
for (let id in result.displays) {
let display = result.displays[id];
// Convert the native data into something matching what is created in _processService()
let service = {
location: display.location,
target: "media:router",
friendlyName: display.friendlyName,
uuid: display.uuid,
manufacturer: display.manufacturer,
modelName: display.modelName,
mirror: display.mirror
};
this._addService(service);
}
});
},
#endif
_searchFixedDevices: function _searchFixedDevices() { _searchFixedDevices: function _searchFixedDevices() {
let fixedDevices = null; let fixedDevices = null;
try { try {
@ -259,8 +222,7 @@ var SimpleServiceDiscovery = {
// Clean out any stale services // Clean out any stale services
for (let [key, service] of this._services) { for (let [key, service] of this._services) {
if (service.lastPing != this._searchTimestamp) { if (service.lastPing != this._searchTimestamp) {
Services.obs.notifyObservers(null, EVENT_SERVICE_LOST, service.uuid); this.removeService(service.uuid);
this._services.delete(service.uuid);
} }
} }
} }
@ -399,29 +361,52 @@ var SimpleServiceDiscovery = {
aService.manufacturer = doc.querySelector("manufacturer").textContent; aService.manufacturer = doc.querySelector("manufacturer").textContent;
aService.modelName = doc.querySelector("modelName").textContent; aService.modelName = doc.querySelector("modelName").textContent;
this._addService(aService); this.addService(aService);
} }
}).bind(this), false); }).bind(this), false);
xhr.send(null); xhr.send(null);
}, },
// Add a service to the WeakMap, even if one already exists with this id.
// Returns true if this succeeded or false if it failed
_addService: function(service) { _addService: function(service) {
// Filter out services that do not match the device filter // Filter out services that do not match the device filter
if (!this._filterService(service)) { if (!this._filterService(service)) {
return; return false;
} }
// Only add and notify if we don't already know about this service
if (!this._services.has(service.uuid)) {
let device = this._devices.get(service.target); let device = this._devices.get(service.target);
if (device && device.mirror) { if (device && device.mirror) {
service.mirror = true; service.mirror = true;
} }
this._services.set(service.uuid, service); this._services.set(service.uuid, service);
return true;
},
addService: function(service) {
// Only add and notify if we don't already know about this service
if (!this._services.has(service.uuid)) {
if (!this._addService(service)) {
return;
}
Services.obs.notifyObservers(null, EVENT_SERVICE_FOUND, service.uuid); Services.obs.notifyObservers(null, EVENT_SERVICE_FOUND, service.uuid);
} }
// Make sure we remember this service is not stale
this._services.get(service.uuid).lastPing = this._searchTimestamp;
},
removeService: function(uuid) {
Services.obs.notifyObservers(null, EVENT_SERVICE_LOST, uuid);
this._services.delete(uuid);
},
updateService: function(service) {
if (!this._addService(service)) {
return;
}
// Make sure we remember this service is not stale // Make sure we remember this service is not stale
this._services.get(service.uuid).lastPing = this._searchTimestamp; this._services.get(service.uuid).lastPing = this._searchTimestamp;
} }