Add NFC reader-mode API.
Allows applications to temporarily force the NFC controller
to only do tag discovery. This will allow Android applications
to read and interact with devices that employ HCE.
Bug: 10360259
Change-Id: I709ead9a26f8e6ae8582cc295d82bd896e7c5bba
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index 9c97659..15d0475 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -48,5 +48,6 @@
void dispatch(in Tag tag);
+ void setReaderMode (IBinder b, int flags);
void setP2pModes(int initatorModes, int targetModes);
}
diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java
index 10183c0..d0d943c 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/core/java/android/nfc/NfcActivityManager.java
@@ -19,6 +19,7 @@
import android.app.Activity;
import android.app.Application;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
@@ -111,6 +112,9 @@
NfcAdapter.CreateBeamUrisCallback uriCallback = null;
Uri[] uris = null;
int flags = 0;
+ int readerModeFlags = 0;
+ Binder token;
+
public NfcActivityState(Activity activity) {
if (activity.getWindow().isDestroyed()) {
throw new IllegalStateException("activity is already destroyed");
@@ -120,6 +124,7 @@
resumed = activity.isResumed();
this.activity = activity;
+ this.token = new Binder();
registerApplication(activity.getApplication());
}
public void destroy() {
@@ -131,6 +136,8 @@
onNdefPushCompleteCallback = null;
uriCallback = null;
uris = null;
+ readerModeFlags = 0;
+ token = null;
}
@Override
public String toString() {
@@ -190,6 +197,44 @@
mDefaultEvent = new NfcEvent(mAdapter);
}
+ public void enableReaderMode(Activity activity, int flags) {
+ boolean isResumed;
+ Binder token;
+ synchronized (NfcActivityManager.this) {
+ NfcActivityState state = getActivityState(activity);
+ state.readerModeFlags = flags;
+ token = state.token;
+ isResumed = state.resumed;
+ }
+ if (isResumed) {
+ setReaderMode(token, flags);
+ }
+ }
+
+ public void disableReaderMode(Activity activity) {
+ boolean isResumed;
+ Binder token;
+ synchronized (NfcActivityManager.this) {
+ NfcActivityState state = getActivityState(activity);
+ state.readerModeFlags = 0;
+ token = state.token;
+ isResumed = state.resumed;
+ }
+ if (isResumed) {
+ setReaderMode(token, 0);
+ }
+
+ }
+
+ public void setReaderMode(Binder token, int flags) {
+ if (DBG) Log.d(TAG, "Setting reader mode");
+ try {
+ NfcAdapter.sService.setReaderMode(token, flags);
+ } catch (RemoteException e) {
+ mAdapter.attemptDeadServiceRecovery(e);
+ }
+ }
+
public void setNdefPushContentUri(Activity activity, Uri[] uris) {
boolean isResumed;
synchronized (NfcActivityManager.this) {
@@ -341,11 +386,18 @@
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityResumed(Activity activity) {
+ int readerModeFlags = 0;
+ Binder token;
synchronized (NfcActivityManager.this) {
NfcActivityState state = findActivityState(activity);
if (DBG) Log.d(TAG, "onResume() for " + activity + " " + state);
if (state == null) return;
state.resumed = true;
+ token = state.token;
+ readerModeFlags = state.readerModeFlags;
+ }
+ if (readerModeFlags != 0) {
+ setReaderMode(token, readerModeFlags);
}
requestNfcServiceCallback();
}
@@ -353,11 +405,19 @@
/** Callback from Activity life-cycle, on main thread */
@Override
public void onActivityPaused(Activity activity) {
+ boolean readerModeFlagsSet;
+ Binder token;
synchronized (NfcActivityManager.this) {
NfcActivityState state = findActivityState(activity);
if (DBG) Log.d(TAG, "onPause() for " + activity + " " + state);
if (state == null) return;
state.resumed = false;
+ token = state.token;
+ readerModeFlagsSet = state.readerModeFlags != 0;
+ }
+ if (readerModeFlagsSet) {
+ // Restore default p2p modes
+ setReaderMode(token, 0);
}
}
@@ -381,5 +441,4 @@
}
}
}
-
}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 2a4f93c..fa0c1f6 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -195,6 +195,50 @@
public static final int STATE_ON = 3;
public static final int STATE_TURNING_OFF = 4;
+ /**
+ * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * <p>
+ * Setting this flag enables polling for Nfc-A technology.
+ */
+ public static final int FLAG_READER_NFC_A = 0x1;
+
+ /**
+ * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * <p>
+ * Setting this flag enables polling for Nfc-B technology.
+ */
+ public static final int FLAG_READER_NFC_B = 0x2;
+
+ /**
+ * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * <p>
+ * Setting this flag enables polling for Nfc-F technology.
+ */
+ public static final int FLAG_READER_NFC_F = 0x4;
+
+ /**
+ * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * <p>
+ * Setting this flag enables polling for Nfc-V (ISO15693) technology.
+ */
+ public static final int FLAG_READER_NFC_V = 0x8;
+
+ /**
+ * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * <p>
+ * Setting this flag enables polling for Kovio technology.
+ */
+ public static final int FLAG_READER_KOVIO = 0x10;
+
+ /**
+ * Flag for use with {@link #enableReaderMode(Activity, int)}.
+ * <p>
+ * Setting this flag allows the caller to prevent the
+ * platform from performing an NDEF check on the tags it
+ * finds.
+ */
+ public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80;
+
/** @hide */
public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
@@ -1112,6 +1156,44 @@
}
/**
+ * Limit the NFC controller to reader mode while this Activity is in the foreground.
+ *
+ * <p>In this mode the NFC controller will only act as an NFC tag reader/writer,
+ * thus disabling any peer-to-peer (Android Beam) and card-emulation modes of
+ * the NFC adapter on this device.
+ *
+ * <p>Use {@link #FLAG_READER_SKIP_NDEF_CHECK} to prevent the platform from
+ * performing any NDEF checks in reader mode. Note that this will prevent the
+ * {@link Ndef} tag technology from being enumerated on the tag, and that
+ * NDEF-based tag dispatch will not be functional.
+ *
+ * <p>It is recommended to combine this method with
+ * {@link #enableForegroundDispatch(Activity, PendingIntent, IntentFilter[], String[][])
+ * to ensure that tags are delivered to this activity.
+ *
+ * <p>For interacting with tags that are emulated on another Android device
+ * using Android's host-based card-emulation, the recommended flags are
+ * {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}.
+ *
+ * @param activity the Activity that requests the adapter to be in reader mode
+ * @param flags Flags indicating poll technologies and other optional parameters
+ */
+ public void enableReaderMode(Activity activity, int flags) {
+ mNfcActivityManager.enableReaderMode(activity, flags);
+ }
+
+ /**
+ * Restore the NFC adapter to normal mode of operation: supporting
+ * peer-to-peer (Android Beam), card emulation, and polling for
+ * all supported tag technologies.
+ *
+ * @param activity the Activity that currently has reader mode enabled
+ */
+ public void disableReaderMode(Activity activity) {
+ mNfcActivityManager.disableReaderMode(activity);
+ }
+
+ /**
* Enable NDEF message push over NFC while this Activity is in the foreground.
*
* <p>You must explicitly call this method every time the activity is