Bug 916428 - [NFC] APIs for ISO 14443-4 tags (IsoDep Support). r=smaug, yoshi
☠☠ backed out by 0797aa48a780 ☠ ☠
authorDimi Lee <dlee@mozilla.com>
Tue, 13 Jan 2015 11:43:49 +0800
changeset 223423 c9a4574f58b5dbffdd8de168b9e48d756fb3ad75
parent 223422 3071d166347a15ea11b72c00fef77a171e1d13b8
child 223424 0797aa48a7804f006573912a0ae8008f936b610c
push id28094
push usercbook@mozilla.com
push dateTue, 13 Jan 2015 13:13:07 +0000
treeherdermozilla-central@60558300fd6a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, yoshi
bugs916428, 14443
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 916428 - [NFC] APIs for ISO 14443-4 tags (IsoDep Support). r=smaug, yoshi
dom/nfc/MozIsoDepTech.cpp
dom/nfc/MozIsoDepTech.h
dom/nfc/moz.build
dom/nfc/nsNfc.js
dom/webidl/MozIsoDepTech.webidl
dom/webidl/MozNFCTag.webidl
dom/webidl/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/nfc/MozIsoDepTech.cpp
@@ -0,0 +1,101 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=80:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "MozIsoDepTech.h"
+#include "mozilla/dom/Promise.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(MozIsoDepTech)
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(MozIsoDepTech)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MozIsoDepTech)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTag)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MozIsoDepTech)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mTag)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(MozIsoDepTech)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(MozIsoDepTech)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MozIsoDepTech)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+/* static */
+already_AddRefed<MozIsoDepTech>
+MozIsoDepTech::Constructor(const GlobalObject& aGlobal,
+                           MozNFCTag& aNFCTag,
+                           ErrorResult& aRv)
+{
+  ErrorResult rv;
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  Nullable<nsTArray<NFCTechType>> techList;
+  aNFCTag.GetTechList(techList, rv);
+  if (rv.Failed()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  if (techList.IsNull() || !(techList.Value().Contains(mTechnology))) {
+    aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
+    return nullptr;
+  }
+
+  nsRefPtr<MozIsoDepTech> isoDep = new MozIsoDepTech(win, aNFCTag);
+
+  return isoDep.forget();
+}
+
+MozIsoDepTech::MozIsoDepTech(nsPIDOMWindow* aWindow, MozNFCTag& aNFCTag)
+ : mWindow(aWindow)
+ , mTag(&aNFCTag)
+{
+}
+
+MozIsoDepTech::~MozIsoDepTech()
+{
+}
+
+already_AddRefed<Promise>
+MozIsoDepTech::Transceive(const Uint8Array& aCommand, ErrorResult& aRv)
+{
+  ErrorResult rv;
+
+  aCommand.ComputeLengthAndData();
+  nsRefPtr<Promise> promise = mTag->Transceive(mTechnology, aCommand, rv);
+  if (rv.Failed()) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  return promise.forget();
+}
+
+JSObject*
+MozIsoDepTech::WrapObject(JSContext* aCx)
+{
+  return MozIsoDepTechBinding::Wrap(aCx, this);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/nfc/MozIsoDepTech.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=4 sw=4 et tw=80:
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_nfc_MozIsoDepTech_h__
+#define mozilla_dom_nfc_MozIsoDepTech_h__
+
+#include "mozilla/dom/MozNFCTagBinding.h"
+#include "mozilla/dom/MozIsoDepTechBinding.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
+#include "nsISupportsImpl.h"
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+
+class Promise;
+
+class MozIsoDepTech : public nsISupports,
+                      public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MozIsoDepTech)
+
+  already_AddRefed<Promise> Transceive(const Uint8Array& aCommand,
+                                       ErrorResult& aRv);
+
+  nsPIDOMWindow* GetParentObject() const { return mWindow; }
+
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  static already_AddRefed<MozIsoDepTech>
+  Constructor(const GlobalObject& aGlobal, MozNFCTag& aNFCTag,
+              ErrorResult& aRv);
+
+private:
+  MozIsoDepTech(nsPIDOMWindow* aWindow, MozNFCTag& aNFCTag);
+  virtual ~MozIsoDepTech();
+
+  nsRefPtr<nsPIDOMWindow> mWindow;
+  nsRefPtr<MozNFCTag> mTag;
+
+  static const NFCTechType mTechnology = NFCTechType::ISO_DEP;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif  // mozilla_dom_nfc_MozIsoDepTech_h__
--- a/dom/nfc/moz.build
+++ b/dom/nfc/moz.build
@@ -7,19 +7,21 @@
 
 XPIDL_MODULE = 'dom_nfc'
 
 if CONFIG['MOZ_NFC']:
     XPIDL_SOURCES += [
         'nsINfcContentHelper.idl',
     ]
     EXPORTS.mozilla.dom += [
+        'MozIsoDepTech.h',
         'MozNDEFRecord.h',
     ]
     UNIFIED_SOURCES += [
+        'MozIsoDepTech.cpp',
         'MozNDEFRecord.cpp',
     ]
     EXTRA_COMPONENTS += [
         'NfcContentHelper.js',
         'NfcContentHelper.manifest',
         'nsNfc.js',
         'nsNfc.manifest',
     ]
--- a/dom/nfc/nsNfc.js
+++ b/dom/nfc/nsNfc.js
@@ -132,16 +132,19 @@ MozNFCTagImpl.prototype = {
   id: null,
   type: null,
   maxNDEFSize: null,
   isReadOnly: null,
   isFormatable: null,
   canBeMadeReadOnly: null,
   isLost: false,
 
+  createTech: { "ISO-DEP": (win, tag) => { return new win.MozIsoDepTech(tag); }
+              },
+
   // NFCTag interface:
   readNDEF: function readNDEF() {
     if (this.isLost) {
       throw new this._window.DOMError("InvalidStateError", "NFCTag object is invalid");
     }
 
     let callback = new NfcCallback(this._window);
     this._nfcContentHelper.readNDEF(this.session, callback);
@@ -196,16 +199,34 @@ MozNFCTagImpl.prototype = {
                                       "NFCTag object is not formatable");
     }
 
     let callback = new NfcCallback(this._window);
     this._nfcContentHelper.format(this.session, callback);
     return callback.promise;
   },
 
+  selectTech: function selectTech(tech) {
+    if (this.isLost) {
+      throw new this._window.DOMError("InvalidStateError", "NFCTag object is invalid");
+    }
+
+    if (this.techList.indexOf(tech) == -1) {
+      throw new this._window.DOMError("InvalidAccessError",
+        "NFCTag does not contain selected tag technology");
+    }
+
+    if (this.createTech[tech] === undefined) {
+      throw new this._window.DOMError("InvalidAccessError",
+        "Technology is not supported now");
+    }
+
+    return this.createTech[tech](this._window, this._contentObj);
+  },
+
   transceive: function transceive(tech, cmd) {
     if (this.isLost) {
       throw new this._window.DOMError("InvalidStateError", "NFCTag object is invalid");
     }
 
     let callback = new NfcCallback(this._window);
     this._nfcContentHelper.transceive(this.session, tech, cmd, callback);
     return callback.promise;
@@ -288,27 +309,28 @@ let RFState = {
  * Implementation of navigator NFC object.
  */
 function MozNFCImpl() {
   debug("In MozNFCImpl Constructor");
   try {
     this._nfcContentHelper = Cc["@mozilla.org/nfc/content-helper;1"]
                                .getService(Ci.nsINfcContentHelper);
   } catch(e) {
-    debug("No NFC support.")
+    debug("No NFC support.");
   }
 
   this.eventService = Cc["@mozilla.org/eventlistenerservice;1"]
                         .getService(Ci.nsIEventListenerService);
   this._nfcContentHelper.addEventListener(this);
 }
 MozNFCImpl.prototype = {
   _nfcContentHelper: null,
   _window: null,
   _rfState: null,
+  _contentObj: null,
   nfcPeer: null,
   nfcTag: null,
   eventService: null,
 
   init: function init(aWindow) {
     debug("MozNFCImpl init called");
     this._window = aWindow;
     this.defineEventHandlerGetterSetter("ontagfound");
@@ -411,16 +433,18 @@ MozNFCImpl.prototype = {
       return;
     }
 
     this.eventService.addSystemEventListener(this._window, "visibilitychange",
       this, /* useCapture */false);
 
     let tagImpl = new MozNFCTagImpl(this._window, sessionToken, tagInfo, ndefInfo);
     let tag = this._window.MozNFCTag._create(this._window, tagImpl);
+
+    tagImpl._contentObj = tag;
     this.nfcTag = tag;
 
     let length = records ? records.length : 0;
     let ndefRecords = records ? [] : null;
     for (let i = 0; i < length; i++) {
       let record = records[i];
       ndefRecords.push(new this._window.MozNDEFRecord({tnf: record.tnf,
                                                        type: record.type,
@@ -483,17 +507,17 @@ MozNFCImpl.prototype = {
     if (!this.checkPermissions(perm)) {
       return;
     }
 
     this.eventService.addSystemEventListener(this._window, "visibilitychange",
       this, /* useCapture */false);
 
     let peerImpl = new MozNFCPeerImpl(this._window, sessionToken);
-    this.nfcPeer = this._window.MozNFCPeer._create(this._window, peerImpl)
+    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);
     this.__DOM_IMPL__.dispatchEvent(event);
   },
 
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozIsoDepTech.webidl
@@ -0,0 +1,13 @@
+/* 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/. */
+
+[Func="Navigator::HasNFCSupport", AvailableIn="PrivilegedApps",
+ ChromeConstructor(MozNFCTag tag)]
+interface MozIsoDepTech {
+  /**
+   * Send raw command to tag and receive the response.
+   */
+  [Throws]
+  Promise<Uint8Array> transceive(Uint8Array command);
+};
--- a/dom/webidl/MozNFCTag.webidl
+++ b/dom/webidl/MozNFCTag.webidl
@@ -30,16 +30,18 @@ enum NFCTechType {
 enum NFCTagType {
   "Type1",
   "Type2",
   "Type3",
   "Type4",
   "MIFARE-Classic"
 };
 
+typedef MozIsoDepTech MozTagTech;
+
 [JSImplementation="@mozilla.org/nfc/tag;1", AvailableIn="PrivilegedApps"]
 interface MozNFCTag {
   /**
    * The supported technologies of this tag, null if unknown.
    */
   [Cached, Pure] readonly attribute sequence<NFCTechType>? techList;
 
   /**
@@ -95,24 +97,24 @@ interface MozNFCTag {
   [Throws]
   Promise<void> makeReadOnly();
 
   /**
    * Format a tag as NDEF.
    */
   [Throws]
   Promise<void> format();
+
+  [NewObject, Throws]
+  MozTagTech selectTech(NFCTechType tech);
 };
 
 // Mozilla Only
 partial interface MozNFCTag {
   [ChromeOnly]
   attribute DOMString session;
 
   [ChromeOnly]
   void notifyLost();
 
-  /**
-   * Send raw command to tag and receive the response.
-   */
   [ChromeOnly, Throws]
   Promise<Uint8Array> transceive(NFCTechType tech, Uint8Array command);
 };
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -643,16 +643,17 @@ if CONFIG['MOZ_B2G_RIL']:
         'IccCardLockError.webidl',
         'MozIcc.webidl',
         'MozIccInfo.webidl',
         'MozIccManager.webidl',
     ]
 
 if CONFIG['MOZ_NFC']:
     WEBIDL_FILES += [
+         'MozIsoDepTech.webidl',
          'MozNDEFRecord.webidl',
          'MozNFC.webidl',
          'MozNFCPeer.webidl',
          'MozNFCTag.webidl',
          'NfcOptions.webidl',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':