Bug 1082443 - B2G NFC: event fallback to System app if the foreground app cannot handle it. r=smaug, dimi

This commit is contained in:
Yoshi Huang 2014-12-11 17:42:35 +08:00
Родитель accb13c8fc
Коммит 9f90a20a21
5 изменённых файлов: 125 добавлений и 19 удалений

Просмотреть файл

@ -147,6 +147,10 @@ NfcContentHelper.prototype = {
},
encodeNDEFRecords: function encodeNDEFRecords(records) {
if (!Array.isArray(records)) {
return null;
}
let encodedRecords = [];
for (let i = 0; i < records.length; i++) {
let record = records[i];
@ -278,6 +282,16 @@ NfcContentHelper.prototype = {
rfState: rfState});
},
callDefaultFoundHandler: function callDefaultFoundHandler(sessionToken,
isP2P,
records) {
let encodedRecords = this.encodeNDEFRecords(records);
cpmm.sendAsyncMessage("NFC:CallDefaultFoundHandler",
{sessionToken: sessionToken,
isP2P: isP2P,
records: encodedRecords});
},
// nsIObserver
observe: function observe(subject, topic, data) {
if (topic == "xpcom-shutdown") {

Просмотреть файл

@ -57,7 +57,8 @@ const NFC_CID =
const NFC_IPC_MSG_ENTRIES = [
{ permission: null,
messages: ["NFC:AddEventListener",
"NFC:QueryInfo"] },
"NFC:QueryInfo",
"NFC:CallDefaultFoundHandler"] },
{ permission: "nfc",
messages: ["NFC:ReadNDEF",
@ -227,6 +228,13 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
sessionToken: sessionToken});
},
callDefaultFoundHandler: function callDefaultFoundHandler(message) {
let sysMsg = new NfcTechDiscoveredSysMsg(message.sessionToken,
message.isP2P,
message.records || null);
gSystemMessenger.broadcastMessage("nfc-manager-tech-discovered", sysMsg);
},
onTagFound: function onTagFound(message) {
let target = this.eventListeners[this.focusApp] ||
this.eventListeners[NFC.SYSTEM_APP_ID];
@ -317,6 +325,9 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function () {
}
this.nfc.sendNfcResponse(message.data);
return null;
case "NFC:CallDefaultFoundHandler":
this.callDefaultFoundHandler(message.data);
return null;
default:
return this.nfc.receiveMessage(message);
}
@ -502,11 +513,6 @@ Nfc.prototype = {
} else {
gMessageManager.onTagFound(message);
}
let sysMsg = new NfcTechDiscoveredSysMsg(message.sessionToken,
message.isP2P,
message.records || null);
gSystemMessenger.broadcastMessage("nfc-manager-tech-discovered", sysMsg);
break;
case "TechLostNotification":
message.type = "techLost";

Просмотреть файл

@ -111,7 +111,7 @@ interface nsINfcBrowserAPI : nsISupports
in boolean isFocus);
};
[scriptable, uuid(b5194ae8-d5d5-482f-a73f-dd0d755a1972)]
[scriptable, uuid(b35f4bf5-e1b8-45f4-b5d3-2ae9b6d5871e)]
interface nsINfcContentHelper : nsISupports
{
void init(in nsIDOMWindow window);
@ -278,4 +278,19 @@ interface nsINfcContentHelper : nsISupports
*/
void changeRFState(in DOMString rfState,
in nsINfcRequestCallback callback);
/**
* Notify parent process to call the default tagfound or peerfound event
* handler.
*
* @param sessionToken
* Session token of this event.
* @param isP2P
* Is this a P2P Session.
* @param records
* NDEF Records.
*/
void callDefaultFoundHandler(in DOMString sessionToken,
in boolean isP2P,
in nsIVariant records);
};

Просмотреть файл

@ -431,18 +431,29 @@ MozNFCImpl.prototype = {
},
notifyTagFound: function notifyTagFound(sessionToken, tagInfo, ndefInfo, records) {
if (!this.handleTagFound(sessionToken, tagInfo, ndefInfo, records)) {
this._nfcContentHelper.callDefaultFoundHandler(sessionToken, false, records);
};
},
/**
* Handles Tag Found event.
*
* returns true if the app could process this event, false otherwise.
*/
handleTagFound: function handleTagFound(sessionToken, tagInfo, ndefInfo, records) {
if (this.hasDeadWrapper()) {
dump("this._window or this.__DOM_IMPL__ is a dead wrapper.");
return;
return false;
}
if (!this.eventService.hasListenersFor(this.__DOM_IMPL__, "tagfound")) {
debug("ontagfound is not registered.");
return;
return false;
}
if (!this.checkPermissions(["nfc"])) {
return;
return false;
}
this.eventService.addSystemEventListener(this._window, "visibilitychange",
@ -465,6 +476,7 @@ MozNFCImpl.prototype = {
}
let eventData = {
"cancelable": true,
"tag": tag,
"ndefRecords": ndefRecords
};
@ -472,6 +484,15 @@ MozNFCImpl.prototype = {
debug("fire ontagfound " + sessionToken);
let tagEvent = new this._window.MozNFCTagEvent("tagfound", eventData);
this.__DOM_IMPL__.dispatchEvent(tagEvent);
// If defaultPrevented is false, means we need to take the default action
// for this event - redirect this event to System app. Before redirecting to
// System app, we need revoke the tag object first.
if (!tagEvent.defaultPrevented) {
this.notifyTagLost(sessionToken);
}
return tagEvent.defaultPrevented;
},
notifyTagLost: function notifyTagLost(sessionToken) {
@ -504,20 +525,31 @@ MozNFCImpl.prototype = {
},
notifyPeerFound: function notifyPeerFound(sessionToken, isPeerReady) {
if (!this.handlePeerFound(sessionToken, isPeerReady)) {
this._nfcContentHelper.callDefaultFoundHandler(sessionToken, true, null);
}
},
/**
* Handles Peer Found/Peer Ready event.
*
* returns true if the app could process this event, false otherwise.
*/
handlePeerFound: function handlePeerFound(sessionToken, isPeerReady) {
if (this.hasDeadWrapper()) {
dump("this._window or this.__DOM_IMPL__ is a dead wrapper.");
return;
return false;
}
if (!isPeerReady &&
!this.eventService.hasListenersFor(this.__DOM_IMPL__, "peerfound")) {
debug("onpeerfound is not registered.");
return;
return false;
}
let perm = isPeerReady ? ["nfc-share"] : ["nfc"];
if (!this.checkPermissions(perm)) {
return;
return false;
}
this.eventService.addSystemEventListener(this._window, "visibilitychange",
@ -525,12 +557,36 @@ MozNFCImpl.prototype = {
let peerImpl = new MozNFCPeerImpl(this._window, sessionToken);
this.nfcPeer = this._window.MozNFCPeer._create(this._window, peerImpl);
let eventData = { "peer": this.nfcPeer };
let type = (isPeerReady) ? "peerready" : "peerfound";
debug("fire on" + type + " " + sessionToken);
let event = new this._window.MozNFCPeerEvent(type, eventData);
let eventType;
let eventData = {
"peer": this.nfcPeer
};
if (isPeerReady) {
eventType = "peerready";
} else {
eventData.cancelable = true;
eventType = "peerfound";
}
debug("fire on" + eventType + " " + sessionToken);
let event = new this._window.MozNFCPeerEvent(eventType, eventData);
this.__DOM_IMPL__.dispatchEvent(event);
// For peerready we don't take the default action.
if (isPeerReady) {
return true;
}
// If defaultPrevented is false, means we need to take the default action
// for this event - redirect this event to System app. Before redirecting to
// System app, we need revoke the peer object first.
if (!event.defaultPrevented) {
this.notifyPeerLost(sessionToken);
}
return event.defaultPrevented;
},
notifyPeerLost: function notifyPeerLost(sessionToken) {

Просмотреть файл

@ -90,7 +90,13 @@ interface MozNFC : EventTarget {
attribute EventHandler onpeerready;
/**
* This event will be fired when a NFCPeer is detected.
* This event will be fired when a NFCPeer is detected. The application has to
* be running on the foreground (decided by System app) to receive this event.
*
* The default action of this event is to dispatch the event in System app
* again, and System app will run the default UX behavior (like vibration).
* So if the application would like to cancel the event, the application
* should call event.preventDefault() or return false in this event handler.
*/
attribute EventHandler onpeerfound;
@ -101,7 +107,16 @@ interface MozNFC : EventTarget {
attribute EventHandler onpeerlost;
/**
* Ths event will be fired when a NFCTag is detected.
* This event will be fired when a NFCTag is detected. The application has to
* be running on the foreground (decided by System app) to receive this event.
*
* The default action of this event is to dispatch the event in System app
* again, and System app will run the default UX behavior (like vibration) and
* launch MozActivity to handle the content of the tag. (For example, System
* app will launch Browser if the tag contains URL). So if the application
* would like to cancel the event, i.e. in the above example, the application
* would process the URL by itself without launching Browser, the application
* should call event.preventDefault() or return false in this event handler.
*/
attribute EventHandler ontagfound;