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/api/current.txt b/api/current.txt
index 42ba6b8..d1fc562 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15042,8 +15042,10 @@
public final class NfcAdapter {
method public void disableForegroundDispatch(android.app.Activity);
method public deprecated void disableForegroundNdefPush(android.app.Activity);
+ method public void disableReaderMode(android.app.Activity);
method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], java.lang.String[][]);
method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
+ method public void enableReaderMode(android.app.Activity, int);
method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
method public boolean isEnabled();
method public boolean isNdefPushEnabled();
@@ -15060,6 +15062,12 @@
field public static final java.lang.String EXTRA_ID = "android.nfc.extra.ID";
field public static final java.lang.String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
field public static final java.lang.String EXTRA_TAG = "android.nfc.extra.TAG";
+ field public static final int FLAG_READER_KOVIO = 16; // 0x10
+ field public static final int FLAG_READER_NFC_A = 1; // 0x1
+ field public static final int FLAG_READER_NFC_B = 2; // 0x2
+ field public static final int FLAG_READER_NFC_F = 4; // 0x4
+ field public static final int FLAG_READER_NFC_V = 8; // 0x8
+ field public static final int FLAG_READER_SKIP_NDEF_CHECK = 128; // 0x80
field public static final int STATE_OFF = 1; // 0x1
field public static final int STATE_ON = 3; // 0x3
field public static final int STATE_TURNING_OFF = 4; // 0x4
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