Reader mode NFC API: move to callback model.
Using intents for reader mode doesn't work well for 2 reasons: 1) Intents are used to resolve, but in reader mode we already know where to resolve to. Additionally, dispatching an intent causes additional latency. 2) Using intents with foreground dispatch was tricky; for every call to onNewIntent() with a new tag, there was a call to onPause(), which effectively disabled reader mode again, causing a discovery loop. Instead, let the app register a callback, and call that when we discover a new tag. Also, add new flag to disable platform sounds, and to change the presence check delay. Bug: 10360259 Change-Id: I8373543d6cf2f7ca73c9b3e42bb8b51e3ac48cac
This commit is contained in:
@@ -142,7 +142,7 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/net/INetworkStatsService.aidl \
|
||||
core/java/android/net/INetworkStatsSession.aidl \
|
||||
core/java/android/net/nsd/INsdManager.aidl \
|
||||
core/java/android/nfc/INdefPushCallback.aidl \
|
||||
core/java/android/nfc/IAppCallback.aidl \
|
||||
core/java/android/nfc/INfcAdapter.aidl \
|
||||
core/java/android/nfc/INfcAdapterExtras.aidl \
|
||||
core/java/android/nfc/INfcTag.aidl \
|
||||
|
||||
@@ -15182,7 +15182,7 @@ package android.nfc {
|
||||
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 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 isEnabled();
|
||||
method public boolean isNdefPushEnabled();
|
||||
@@ -15198,12 +15198,14 @@ package android.nfc {
|
||||
field public static final java.lang.String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
|
||||
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_READER_PRESENCE_CHECK_DELAY = "presence";
|
||||
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_NO_PLATFORM_SOUNDS = 256; // 0x100
|
||||
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
|
||||
@@ -15223,6 +15225,10 @@ package android.nfc {
|
||||
method public abstract void onNdefPushComplete(android.nfc.NfcEvent);
|
||||
}
|
||||
|
||||
public static abstract interface NfcAdapter.ReaderCallback {
|
||||
method public abstract void onTagDiscovered(android.nfc.Tag);
|
||||
}
|
||||
|
||||
public final class NfcEvent {
|
||||
field public final android.nfc.NfcAdapter nfcAdapter;
|
||||
}
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
package android.nfc;
|
||||
|
||||
import android.nfc.BeamShareData;
|
||||
import android.nfc.Tag;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
interface INdefPushCallback
|
||||
interface IAppCallback
|
||||
{
|
||||
BeamShareData createBeamShareData();
|
||||
void onNdefPushComplete();
|
||||
void onTagDiscovered(in Tag tag);
|
||||
}
|
||||
@@ -21,10 +21,11 @@ import android.content.IntentFilter;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.Tag;
|
||||
import android.nfc.TechListParcel;
|
||||
import android.nfc.INdefPushCallback;
|
||||
import android.nfc.IAppCallback;
|
||||
import android.nfc.INfcAdapterExtras;
|
||||
import android.nfc.INfcTag;
|
||||
import android.nfc.INfcCardEmulation;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -44,10 +45,10 @@ interface INfcAdapter
|
||||
|
||||
void setForegroundDispatch(in PendingIntent intent,
|
||||
in IntentFilter[] filters, in TechListParcel techLists);
|
||||
void setNdefPushCallback(in INdefPushCallback callback);
|
||||
void setAppCallback(in IAppCallback callback);
|
||||
|
||||
void dispatch(in Tag tag);
|
||||
|
||||
void setReaderMode (IBinder b, int flags);
|
||||
void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras);
|
||||
void setP2pModes(int initatorModes, int targetModes);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package android.nfc;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NfcAdapter.ReaderCallback;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
@@ -36,7 +37,7 @@ import java.util.List;
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
public final class NfcActivityManager extends IAppCallback.Stub
|
||||
implements Application.ActivityLifecycleCallbacks {
|
||||
static final String TAG = NfcAdapter.TAG;
|
||||
static final Boolean DBG = false;
|
||||
@@ -113,6 +114,8 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
Uri[] uris = null;
|
||||
int flags = 0;
|
||||
int readerModeFlags = 0;
|
||||
NfcAdapter.ReaderCallback readerCallback = null;
|
||||
Bundle readerModeExtras = null;
|
||||
Binder token;
|
||||
|
||||
public NfcActivityState(Activity activity) {
|
||||
@@ -197,17 +200,20 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
mDefaultEvent = new NfcEvent(mAdapter);
|
||||
}
|
||||
|
||||
public void enableReaderMode(Activity activity, int flags) {
|
||||
public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
|
||||
Bundle extras) {
|
||||
boolean isResumed;
|
||||
Binder token;
|
||||
synchronized (NfcActivityManager.this) {
|
||||
NfcActivityState state = getActivityState(activity);
|
||||
state.readerCallback = callback;
|
||||
state.readerModeFlags = flags;
|
||||
state.readerModeExtras = extras;
|
||||
token = state.token;
|
||||
isResumed = state.resumed;
|
||||
}
|
||||
if (isResumed) {
|
||||
setReaderMode(token, flags);
|
||||
setReaderMode(token, flags, extras);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,20 +222,22 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
Binder token;
|
||||
synchronized (NfcActivityManager.this) {
|
||||
NfcActivityState state = getActivityState(activity);
|
||||
state.readerCallback = null;
|
||||
state.readerModeFlags = 0;
|
||||
state.readerModeExtras = null;
|
||||
token = state.token;
|
||||
isResumed = state.resumed;
|
||||
}
|
||||
if (isResumed) {
|
||||
setReaderMode(token, 0);
|
||||
setReaderMode(token, 0, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setReaderMode(Binder token, int flags) {
|
||||
public void setReaderMode(Binder token, int flags, Bundle extras) {
|
||||
if (DBG) Log.d(TAG, "Setting reader mode");
|
||||
try {
|
||||
NfcAdapter.sService.setReaderMode(token, flags);
|
||||
NfcAdapter.sService.setReaderMode(token, this, flags, extras);
|
||||
} catch (RemoteException e) {
|
||||
mAdapter.attemptDeadServiceRecovery(e);
|
||||
}
|
||||
@@ -302,12 +310,12 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Request or unrequest NFC service callbacks for NDEF push.
|
||||
* Request or unrequest NFC service callbacks.
|
||||
* Makes IPC call - do not hold lock.
|
||||
*/
|
||||
void requestNfcServiceCallback() {
|
||||
try {
|
||||
NfcAdapter.sService.setNdefPushCallback(this);
|
||||
NfcAdapter.sService.setAppCallback(this);
|
||||
} catch (RemoteException e) {
|
||||
mAdapter.attemptDeadServiceRecovery(e);
|
||||
}
|
||||
@@ -375,6 +383,22 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTagDiscovered(Tag tag) throws RemoteException {
|
||||
NfcAdapter.ReaderCallback callback;
|
||||
synchronized (NfcActivityManager.this) {
|
||||
NfcActivityState state = findResumedActivityState();
|
||||
if (state == null) return;
|
||||
|
||||
callback = state.readerCallback;
|
||||
}
|
||||
|
||||
// Make callback without lock
|
||||
if (callback != null) {
|
||||
callback.onTagDiscovered(tag);
|
||||
}
|
||||
|
||||
}
|
||||
/** Callback from Activity life-cycle, on main thread */
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { /* NO-OP */ }
|
||||
@@ -387,6 +411,7 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
int readerModeFlags = 0;
|
||||
Bundle readerModeExtras = null;
|
||||
Binder token;
|
||||
synchronized (NfcActivityManager.this) {
|
||||
NfcActivityState state = findActivityState(activity);
|
||||
@@ -395,9 +420,10 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
state.resumed = true;
|
||||
token = state.token;
|
||||
readerModeFlags = state.readerModeFlags;
|
||||
readerModeExtras = state.readerModeExtras;
|
||||
}
|
||||
if (readerModeFlags != 0) {
|
||||
setReaderMode(token, readerModeFlags);
|
||||
setReaderMode(token, readerModeFlags, readerModeExtras);
|
||||
}
|
||||
requestNfcServiceCallback();
|
||||
}
|
||||
@@ -417,7 +443,7 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
}
|
||||
if (readerModeFlagsSet) {
|
||||
// Restore default p2p modes
|
||||
setReaderMode(token, 0);
|
||||
setReaderMode(token, 0, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,4 +467,5 @@ public final class NfcActivityManager extends INdefPushCallback.Stub
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.nfc.tech.MifareClassic;
|
||||
import android.nfc.tech.Ndef;
|
||||
import android.nfc.tech.NfcA;
|
||||
import android.nfc.tech.NfcF;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
@@ -196,42 +197,42 @@ public final class NfcAdapter {
|
||||
public static final int STATE_TURNING_OFF = 4;
|
||||
|
||||
/**
|
||||
* Flag for use with {@link #enableReaderMode(Activity, int)}.
|
||||
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
|
||||
* <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)}.
|
||||
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
|
||||
* <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)}.
|
||||
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
|
||||
* <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)}.
|
||||
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
|
||||
* <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)}.
|
||||
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
|
||||
* <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)}.
|
||||
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
|
||||
* <p>
|
||||
* Setting this flag allows the caller to prevent the
|
||||
* platform from performing an NDEF check on the tags it
|
||||
@@ -239,6 +240,23 @@ public final class NfcAdapter {
|
||||
*/
|
||||
public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80;
|
||||
|
||||
/**
|
||||
* Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
|
||||
* <p>
|
||||
* Setting this flag allows the caller to prevent the
|
||||
* platform from playing sounds when it discovers a tag.
|
||||
*/
|
||||
public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100;
|
||||
|
||||
/**
|
||||
* Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
|
||||
* <p>
|
||||
* Setting this integer extra allows the calling application to specify
|
||||
* the delay that the platform will use for performing presence checks
|
||||
* on any discovered tag.
|
||||
*/
|
||||
public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
|
||||
|
||||
/** @hide */
|
||||
public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
|
||||
|
||||
@@ -290,6 +308,14 @@ public final class NfcAdapter {
|
||||
final NfcActivityManager mNfcActivityManager;
|
||||
final Context mContext;
|
||||
|
||||
/**
|
||||
* A callback to be invoked when the system has found a tag in
|
||||
* reader mode.
|
||||
*/
|
||||
public interface ReaderCallback {
|
||||
public void onTagDiscovered(Tag tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback to be invoked when the system successfully delivers your {@link NdefMessage}
|
||||
* to another device.
|
||||
@@ -1167,19 +1193,18 @@ public final class NfcAdapter {
|
||||
* {@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 callback the callback to be called when a tag is discovered
|
||||
* @param flags Flags indicating poll technologies and other optional parameters
|
||||
* @param extras Additional extras for configuring reader mode.
|
||||
*/
|
||||
public void enableReaderMode(Activity activity, int flags) {
|
||||
mNfcActivityManager.enableReaderMode(activity, flags);
|
||||
public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
|
||||
Bundle extras) {
|
||||
mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user