Merge "Fix API review comments, add remove callback." into nyc-dev
diff --git a/Android.mk b/Android.mk
index 2cfc9a2..b590761 100644
--- a/Android.mk
+++ b/Android.mk
@@ -215,6 +215,7 @@
 	core/java/android/nfc/INfcCardEmulation.aidl \
 	core/java/android/nfc/INfcFCardEmulation.aidl \
 	core/java/android/nfc/INfcUnlockHandler.aidl \
+	core/java/android/nfc/ITagRemovedCallback.aidl \
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
diff --git a/api/current.txt b/api/current.txt
index 6fdd1bc..f0657c0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25011,6 +25011,7 @@
     method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
+    method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
     method public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
     method public boolean isNdefPushEnabled();
@@ -25053,6 +25054,10 @@
     method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
   }
 
+  public static abstract interface NfcAdapter.OnTagRemovedListener {
+    method public abstract void onTagRemoved();
+  }
+
   public static abstract interface NfcAdapter.ReaderCallback {
     method public abstract void onTagDiscovered(android.nfc.Tag);
   }
@@ -25069,7 +25074,6 @@
 
   public final class Tag implements android.os.Parcelable {
     method public int describeContents();
-    method public boolean done(int);
     method public byte[] getId();
     method public java.lang.String[] getTechList();
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index ddd9ad6..ba43ee4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -27447,6 +27447,7 @@
     method public boolean enableNdefPush();
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
+    method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
     method public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
     method public boolean isNdefPushEnabled();
@@ -27496,6 +27497,10 @@
     method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
   }
 
+  public static abstract interface NfcAdapter.OnTagRemovedListener {
+    method public abstract void onTagRemoved();
+  }
+
   public static abstract interface NfcAdapter.ReaderCallback {
     method public abstract void onTagDiscovered(android.nfc.Tag);
   }
@@ -27512,7 +27517,6 @@
 
   public final class Tag implements android.os.Parcelable {
     method public int describeContents();
-    method public boolean done(int);
     method public byte[] getId();
     method public java.lang.String[] getTechList();
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index d40d0b8..2cbb566 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -25079,6 +25079,7 @@
     method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
     method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
     method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
+    method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
     method public boolean invokeBeam(android.app.Activity);
     method public boolean isEnabled();
     method public boolean isNdefPushEnabled();
@@ -25121,6 +25122,10 @@
     method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
   }
 
+  public static abstract interface NfcAdapter.OnTagRemovedListener {
+    method public abstract void onTagRemoved();
+  }
+
   public static abstract interface NfcAdapter.ReaderCallback {
     method public abstract void onTagDiscovered(android.nfc.Tag);
   }
@@ -25137,7 +25142,6 @@
 
   public final class Tag implements android.os.Parcelable {
     method public int describeContents();
-    method public boolean done(int);
     method public byte[] getId();
     method public java.lang.String[] getTechList();
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 940565f..f991efe 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -28,6 +28,7 @@
 import android.nfc.INfcCardEmulation;
 import android.nfc.INfcFCardEmulation;
 import android.nfc.INfcUnlockHandler;
+import android.nfc.ITagRemovedCallback;
 import android.os.Bundle;
 
 /**
@@ -55,6 +56,8 @@
     oneway void invokeBeam();
     oneway void invokeBeamInternal(in BeamShareData shareData);
 
+    boolean ignore(int nativeHandle, int debounceMs, ITagRemovedCallback callback);
+
     void dispatch(in Tag tag);
 
     void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
diff --git a/core/java/android/nfc/INfcTag.aidl b/core/java/android/nfc/INfcTag.aidl
index 26d2bec..539fd4a 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/core/java/android/nfc/INfcTag.aidl
@@ -31,7 +31,6 @@
     boolean isNdef(int nativeHandle);
     boolean isPresent(int nativeHandle);
     TransceiveResult transceive(int nativeHandle, in byte[] data, boolean raw);
-    boolean done(int nativeHandle, int debounceMs);
 
     NdefMessage ndefRead(int nativeHandle);
     int ndefWrite(int nativeHandle, in NdefMessage msg);
diff --git a/core/java/android/nfc/ITagRemovedCallback.aidl b/core/java/android/nfc/ITagRemovedCallback.aidl
new file mode 100644
index 0000000..2a06ff3
--- /dev/null
+++ b/core/java/android/nfc/ITagRemovedCallback.aidl
@@ -0,0 +1,8 @@
+package android.nfc;
+
+/**
+ * @hide
+ */
+oneway interface ITagRemovedCallback {
+    void onTagRemoved();
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 6f911ce..8406bcf 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -35,11 +35,14 @@
 import android.nfc.tech.NfcA;
 import android.nfc.tech.NfcF;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
 
+import java.io.IOException;
+
 /**
  * Represents the local NFC adapter.
  * <p>
@@ -315,6 +318,8 @@
     final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
     final Object mLock;
 
+    ITagRemovedCallback mTagRemovedListener; // protected by mLock
+
     /**
      * A callback to be invoked when the system finds a tag while the foreground activity is
      * operating in reader mode.
@@ -386,6 +391,13 @@
     }
 
     /**
+     * A callback that is invoked when a tag is removed from the field.
+     */
+    public interface OnTagRemovedListener {
+        void onTagRemoved();
+    }
+
+    /**
      * 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
@@ -541,6 +553,7 @@
         mContext = context;
         mNfcActivityManager = new NfcActivityManager(this);
         mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
+        mTagRemovedListener = null;
         mLock = new Object();
     }
 
@@ -1494,6 +1507,75 @@
     }
 
     /**
+     * Signals that you are no longer interested in communicating with an NFC tag
+     * for as long as it remains in range.
+     *
+     * All future attempted communication to this tag will fail with {@link IOException}.
+     * The NFC controller will be put in a low-power polling mode, allowing the device
+     * to save power in cases where it's "attached" to a tag all the time (e.g. a tag in
+     * car dock).
+     *
+     * Additionally the debounceMs parameter allows you to specify for how long the tag needs
+     * to have gone out of range, before it will be dispatched again.
+     *
+     * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms).
+     * This means that if the tag repeatedly goes in and out of range (for example, in
+     * case of a flaky connection), and the controller happens to poll every time the
+     * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag
+     * having been "in range" during the interval.
+     *
+     * Note 2: if a tag with another UID is detected after this API is called, its effect
+     * will be cancelled; if this tag shows up before the amount of time specified in
+     * debounceMs, it will be dispatched again.
+     *
+     * Note 3: some tags have a random UID, in which case this API won't work reliably.
+     *
+     * @param tag        the {@link android.nfc.Tag Tag} to ignore.
+     * @param debounceMs minimum amount of time the tag needs to be out of range before being
+     *                   dispatched again.
+     * @param tagRemovedListener listener to be called when the tag is removed from the field.
+     *                           Note that this will only be called if the tag has been out of range
+     *                           for at least debounceMs, or if another tag came into range before
+     *                           debounceMs. May be null in case you don't want a callback.
+     * @param handler the {@link android.os.Handler Handler} that will be used for delivering
+     *                the callback. if the handler is null, then the thread used for delivering
+     *                the callback is unspecified.
+     * @return false if the tag couldn't be found (or has already gone out of range), true otherwise
+     */
+    public boolean ignore(final Tag tag, int debounceMs,
+                          final OnTagRemovedListener tagRemovedListener, final Handler handler) {
+        ITagRemovedCallback.Stub iListener = null;
+        if (tagRemovedListener != null) {
+            iListener = new ITagRemovedCallback.Stub() {
+                @Override
+                public void onTagRemoved() throws RemoteException {
+                    if (handler != null) {
+                        handler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                tagRemovedListener.onTagRemoved();
+                            }
+                        });
+                    } else {
+                        tagRemovedListener.onTagRemoved();
+                    }
+                    synchronized (mLock) {
+                        mTagRemovedListener = null;
+                    }
+                }
+            };
+        }
+        synchronized (mLock) {
+            mTagRemovedListener = iListener;
+        }
+        try {
+            return sService.ignore(tag.getServiceHandle(), debounceMs, iListener);
+        } catch (RemoteException e) {
+            return false;
+        }
+    }
+
+    /**
      * Inject a mock NFC tag.<p>
      * Used for testing purposes.
      * <p class="note">Requires the
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 40d5a8db..154d5a1 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -214,42 +214,6 @@
         return techIntList;
     }
 
-    /**
-     * Signals that you are no longer interested in communicating with this tag
-     * for as long as it remains in range.
-     *
-     * All future attempted communication to this tag will fail with {@link IOException}.
-     * The NFC controller will be put in a low-power polling mode, allowing the device
-     * to save power in cases where it's "attached" to a tag all the time (eg a tag in
-     * car dock).
-     *
-     * Additionally the debounceMs parameter allows you to specify for how long the tag needs
-     * to have gone out of range, before it will be dispatched again.
-     *
-     * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms).
-     * This means that if the tag repeatedly goes in and out of range (for example, in
-     * case of a flaky connection), and the controller happens to poll every time the
-     * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag
-     * having been "in range" during the interval.
-     *
-     * Note 2: if a tag with another UID is detected after this API is called, its effect
-     * will be cancelled; if this tag shows up before the amount of time specified in
-     * debounceMs, it will be dispatched again.
-     *
-     * Note 3: some tags have a random UID, in which case this API won't work.
-     *
-     * @param debounceMs minimum amount of time the tag needs to be out of range before being
-     *                   dispatched again.
-     * @return false if the Tag couldn't be found (or has gone out of range), true otherwise
-     */
-    public boolean done(int debounceMs) {
-        try {
-            return mTagService.done(getServiceHandle(), debounceMs);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
     private static HashMap<String, Integer> getTechStringToCodeMap() {
         HashMap<String, Integer> techStringToCodeMap = new HashMap<String, Integer>();