NFC Unlock api changes

Bug: 16401635
Change-Id: I994bd80be40052c2f894199bb44ebbde40077f27
diff --git a/Android.mk b/Android.mk
index 4376ed6..8309301 100644
--- a/Android.mk
+++ b/Android.mk
@@ -186,6 +186,7 @@
 	core/java/android/nfc/INfcTag.aidl \
 	core/java/android/nfc/INfcCardEmulation.aidl \
 	core/java/android/nfc/INfcLockscreenDispatch.aidl \
+	core/java/android/nfc/INfcUnlockHandler.aidl \
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 541b700..ee4d45e 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -27,6 +27,7 @@
 import android.nfc.INfcTag;
 import android.nfc.INfcCardEmulation;
 import android.nfc.INfcLockscreenDispatch;
+import android.nfc.INfcUnlockHandler;
 import android.os.Bundle;
 
 /**
@@ -57,4 +58,6 @@
     void setP2pModes(int initatorModes, int targetModes);
 
     void registerLockscreenDispatch(INfcLockscreenDispatch lockscreenDispatch, in int[] techList);
+    void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
+    void removeNfcUnlockHandler(IBinder b);
 }
diff --git a/core/java/android/nfc/INfcUnlockHandler.aidl b/core/java/android/nfc/INfcUnlockHandler.aidl
new file mode 100644
index 0000000..e1cace9
--- /dev/null
+++ b/core/java/android/nfc/INfcUnlockHandler.aidl
@@ -0,0 +1,12 @@
+package android.nfc;
+
+import android.nfc.Tag;
+
+/**
+ * @hide
+ */
+interface INfcUnlockHandler {
+
+    boolean onUnlockAttempted(in Tag tag);
+
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index ad785ed..dde2cf1 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -30,7 +30,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.net.Uri;
-import android.nfc.BeamShareData;
 import android.nfc.tech.MifareClassic;
 import android.nfc.tech.Ndef;
 import android.nfc.tech.NfcA;
@@ -312,6 +311,8 @@
 
     final NfcActivityManager mNfcActivityManager;
     final Context mContext;
+    final HashMap<NfcUnlockHandler, IBinder> mNfcUnlockHandlers;
+    final Object mLock;
 
     /**
      * A callback to be invoked when the system finds a tag while the foreground activity is
@@ -394,6 +395,22 @@
 
 
     /**
+     * A callback to be invoked when an application has registered as a
+     * handler to unlock the device given an NFC tag at the lockscreen.
+     * @hide
+     */
+    @SystemApi
+    public interface NfcUnlockHandler {
+        /**
+         * Called at the lock screen to attempt to unlock the device with the given tag.
+         * @param tag the detected tag, to be used to unlock the device
+         * @return true if the device was successfully unlocked
+         */
+        public boolean onUnlockAttempted(Tag tag);
+    }
+
+
+    /**
      * Helper to check if this device has FEATURE_NFC, but without using
      * a context.
      * Equivalent to
@@ -525,6 +542,8 @@
     NfcAdapter(Context context) {
         mContext = context;
         mNfcActivityManager = new NfcActivityManager(this);
+        mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, IBinder>();
+        mLock = new Object();
     }
 
     /**
@@ -1457,7 +1476,7 @@
                 public boolean onTagDetected(Tag tag) throws RemoteException {
                     return lockscreenDispatch.onTagDetected(tag);
                 }
-            }, Tag.techListFromStrings(techList));
+            }, Tag.getTechCodesFromStrings(techList));
         } catch (RemoteException e) {
             attemptDeadServiceRecovery(e);
             return false;
@@ -1470,6 +1489,72 @@
     }
 
     /**
+     * Registers a new NFC unlock handler with the NFC service.
+     *
+     * <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted
+     * NFC device. The handler should return true if it successfully authenticates the user and
+     * unlocks the keyguard.
+     *
+     * <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for
+     * at the lockscreen. Polling for less tag technologies reduces latency, and so it is
+     * strongly recommended to only provide the Tag technologies that the handler is expected to
+     * receive.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
+                                       String[] tagTechnologies) {
+        try {
+            INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
+                @Override
+                public boolean onUnlockAttempted(Tag tag) throws RemoteException {
+                    return unlockHandler.onUnlockAttempted(tag);
+                }
+            };
+
+            synchronized (mLock) {
+                if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
+                    return true;
+                }
+                sService.addNfcUnlockHandler(iHandler, Tag.getTechCodesFromStrings(tagTechnologies));
+                mNfcUnlockHandlers.put(unlockHandler, iHandler.asBinder());
+            }
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        } catch (IllegalArgumentException e) {
+            Log.e(TAG, "Unable to register LockscreenDispatch", e);
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * Removes a previously registered unlock handler. Also removes the tag technologies
+     * associated with the removed unlock handler.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) {
+        try {
+            synchronized (mLock) {
+                if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
+                    sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
+                    mNfcUnlockHandlers.remove(unlockHandler);
+                }
+
+                return true;
+            }
+        } catch (RemoteException e) {
+            attemptDeadServiceRecovery(e);
+            return false;
+        }
+    }
+
+    /**
      * @hide
      */
     public INfcAdapterExtras getNfcAdapterExtrasInterface() {
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 43be702..154d5a1 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -196,7 +196,7 @@
         return strings;
     }
 
-    static int[] techListFromStrings(String[] techStringList) throws IllegalArgumentException {
+    static int[] getTechCodesFromStrings(String[] techStringList) throws IllegalArgumentException {
         if (techStringList == null) {
             throw new IllegalArgumentException("List cannot be null");
         }