diff options
-rw-r--r-- | core/java/android/nfc/INfcAdapter.aidl | 2 | ||||
-rw-r--r-- | core/java/android/nfc/INfcAdapterExtras.aidl | 12 | ||||
-rw-r--r-- | core/java/android/nfc/NfcAdapter.java | 78 | ||||
-rw-r--r-- | core/java/android/nfc/NfcManager.java | 3 | ||||
-rw-r--r-- | nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java | 69 | ||||
-rw-r--r-- | nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java | 16 |
6 files changed, 107 insertions, 73 deletions
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl index 016af58..0b93ad0 100644 --- a/core/java/android/nfc/INfcAdapter.aidl +++ b/core/java/android/nfc/INfcAdapter.aidl @@ -32,7 +32,7 @@ import android.nfc.INfcTag; interface INfcAdapter { INfcTag getNfcTagInterface(); - INfcAdapterExtras getNfcAdapterExtrasInterface(); + INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg); int getState(); boolean disable(); diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl index 0c2a2fd..2b9d4f0 100644 --- a/core/java/android/nfc/INfcAdapterExtras.aidl +++ b/core/java/android/nfc/INfcAdapterExtras.aidl @@ -23,10 +23,10 @@ import android.os.Bundle; * {@hide} */ interface INfcAdapterExtras { - Bundle open(IBinder b); - Bundle close(); - Bundle transceive(in byte[] data_in); - int getCardEmulationRoute(); - void setCardEmulationRoute(int route); - void authenticate(in byte[] token); + Bundle open(in String pkg, IBinder b); + Bundle close(in String pkg, IBinder b); + Bundle transceive(in String pkg, in byte[] data_in); + int getCardEmulationRoute(in String pkg); + void setCardEmulationRoute(in String pkg, int route); + void authenticate(in String pkg, in byte[] token); } diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java index fe0106d..a9f1685 100644 --- a/core/java/android/nfc/NfcAdapter.java +++ b/core/java/android/nfc/NfcAdapter.java @@ -16,6 +16,8 @@ package android.nfc; +import java.util.HashMap; + import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Activity; @@ -197,15 +199,21 @@ public final class NfcAdapter { static INfcTag sTagService; /** - * NfcAdapter is currently a singleton, and does not require a context. - * However all the public API's are future-proofed to require a context. - * If we start using that then we'll need to keep a HashMap of - * Context.getApplicationContext() -> NfcAdapter, such that NfcAdapter - * is a singleton within each application context. + * The NfcAdapter object for each application context. + * There is a 1-1 relationship between application context and + * NfcAdapter object. + */ + static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class + + /** + * NfcAdapter used with a null context. This ctor was deprecated but we have + * to support it for backwards compatibility. New methods that require context + * might throw when called on the null-context NfcAdapter. */ - static NfcAdapter sSingleton; // protected by NfcAdapter.class + static NfcAdapter sNullContextNfcAdapter; // protected by NfcAdapter.class final NfcActivityManager mNfcActivityManager; + final Context mContext; /** * A callback to be invoked when the system successfully delivers your {@link NdefMessage} @@ -280,12 +288,12 @@ public final class NfcAdapter { } /** - * Returns the singleton, or throws if NFC is not available. + * Returns the NfcAdapter for application context, + * or throws if NFC is not available. + * @hide */ - static synchronized NfcAdapter getSingleton() { + public static synchronized NfcAdapter getNfcAdapter(Context context) { if (!sIsInitialized) { - sIsInitialized = true; - /* is this device meant to have NFC */ if (!hasNfcFeature()) { Log.v(TAG, "this device does not have NFC support"); @@ -303,12 +311,21 @@ public final class NfcAdapter { Log.e(TAG, "could not retrieve NFC Tag service"); throw new UnsupportedOperationException(); } - sSingleton = new NfcAdapter(); + + sIsInitialized = true; + } + if (context == null) { + if (sNullContextNfcAdapter == null) { + sNullContextNfcAdapter = new NfcAdapter(null); + } + return sNullContextNfcAdapter; } - if (sSingleton == null) { - throw new UnsupportedOperationException(); + NfcAdapter adapter = sNfcAdapters.get(context); + if (adapter == null) { + adapter = new NfcAdapter(context); + sNfcAdapters.put(context, adapter); } - return sSingleton; + return adapter; } /** get handle to NFC service interface */ @@ -336,6 +353,10 @@ public final class NfcAdapter { * @return the default NFC adapter, or null if no NFC adapter exists */ public static NfcAdapter getDefaultAdapter(Context context) { + if (context == null) { + throw new IllegalArgumentException("context cannot be null"); + } + context = context.getApplicationContext(); /* use getSystemService() instead of just instantiating to take * advantage of the context's cached NfcManager & NfcAdapter */ NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); @@ -343,25 +364,30 @@ public final class NfcAdapter { } /** - * Get a handle to the default NFC Adapter on this Android device. - * <p> - * Most Android devices will only have one NFC Adapter (NFC Controller). - * - * @return the default NFC adapter, or null if no NFC adapter exists + * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p> + * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required + * for many NFC API methods. Those methods will fail when called on an NfcAdapter + * object created from this method.<p> * @deprecated use {@link #getDefaultAdapter(Context)} */ @Deprecated public static NfcAdapter getDefaultAdapter() { Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " + "NfcAdapter.getDefaultAdapter(Context) instead", new Exception()); - return getSingleton(); + + return NfcAdapter.getNfcAdapter(null); + } + + NfcAdapter(Context context) { + mContext = context; + mNfcActivityManager = new NfcActivityManager(this); } /** - * Does not currently need a context. + * @hide */ - NfcAdapter() { - mNfcActivityManager = new NfcActivityManager(this); + public Context getContext() { + return mContext; } /** @@ -875,8 +901,12 @@ public final class NfcAdapter { * @hide */ public INfcAdapterExtras getNfcAdapterExtrasInterface() { + if (mContext == null) { + throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " + + " NFC extras APIs"); + } try { - return sService.getNfcAdapterExtrasInterface(); + return sService.getNfcAdapterExtrasInterface(mContext.getPackageName()); } catch (RemoteException e) { attemptDeadServiceRecovery(e); return null; diff --git a/core/java/android/nfc/NfcManager.java b/core/java/android/nfc/NfcManager.java index 300ab45..6ec2e21 100644 --- a/core/java/android/nfc/NfcManager.java +++ b/core/java/android/nfc/NfcManager.java @@ -39,8 +39,9 @@ public final class NfcManager { */ public NfcManager(Context context) { NfcAdapter adapter; + context = context.getApplicationContext(); try { - adapter = NfcAdapter.getSingleton(); + adapter = NfcAdapter.getNfcAdapter(context); } catch (UnsupportedOperationException e) { adapter = null; } diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java index 99cbb86..62213de 100644 --- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java +++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java @@ -16,8 +16,7 @@ package com.android.nfc_extras; -import android.annotation.SdkConstant; -import android.annotation.SdkConstant.SdkConstantType; +import android.content.Context; import android.nfc.INfcAdapterExtras; import android.nfc.NfcAdapter; import android.os.RemoteException; @@ -60,10 +59,14 @@ public final class NfcAdapterExtras { // best effort recovery private static NfcAdapter sAdapter; private static INfcAdapterExtras sService; - private static NfcAdapterExtras sSingleton; - private static NfcExecutionEnvironment sEmbeddedEe; - private static CardEmulationRoute sRouteOff; - private static CardEmulationRoute sRouteOnWhenScreenOn; + private static final CardEmulationRoute ROUTE_OFF = + new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null); + + private final NfcExecutionEnvironment mEmbeddedEe; + private final CardEmulationRoute mRouteOnWhenScreenOn; + + final Context mContext; + final String mPackageName; /** get service handles */ private static void initService() { @@ -84,31 +87,35 @@ public final class NfcAdapterExtras { * @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter} */ public static NfcAdapterExtras get(NfcAdapter adapter) { - synchronized(NfcAdapterExtras.class) { - if (sSingleton == null) { + Context context = adapter.getContext(); + if (context == null) { + throw new UnsupportedOperationException( + "You must pass a context to your NfcAdapter to use the NFC extras APIs"); + } + + synchronized (NfcAdapterExtras.class) { + if (sService == null) { try { sAdapter = adapter; - sSingleton = new NfcAdapterExtras(); - sEmbeddedEe = new NfcExecutionEnvironment(sSingleton); - sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null); - sRouteOnWhenScreenOn = new CardEmulationRoute( - CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe); initService(); } finally { if (sService == null) { - sRouteOnWhenScreenOn = null; - sRouteOff = null; - sEmbeddedEe = null; - sSingleton = null; sAdapter = null; } } } - return sSingleton; } + + return new NfcAdapterExtras(context); } - private NfcAdapterExtras() {} + private NfcAdapterExtras(Context context) { + mContext = context.getApplicationContext(); + mPackageName = context.getPackageName(); + mEmbeddedEe = new NfcExecutionEnvironment(this); + mRouteOnWhenScreenOn = new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, + mEmbeddedEe); + } /** * Immutable data class that describes a card emulation route. @@ -166,18 +173,16 @@ public final class NfcAdapterExtras { * * <p class="note"> * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. - * - * @return */ public CardEmulationRoute getCardEmulationRoute() { try { - int route = sService.getCardEmulationRoute(); + int route = sService.getCardEmulationRoute(mPackageName); return route == CardEmulationRoute.ROUTE_OFF ? - sRouteOff : - sRouteOnWhenScreenOn; + ROUTE_OFF : + mRouteOnWhenScreenOn; } catch (RemoteException e) { attemptDeadServiceRecovery(e); - return sRouteOff; + return ROUTE_OFF; } } @@ -189,11 +194,11 @@ public final class NfcAdapterExtras { * <p class="note"> * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. * - * @param route a {@link #CardEmulationRoute} + * @param route a {@link CardEmulationRoute} */ public void setCardEmulationRoute(CardEmulationRoute route) { try { - sService.setCardEmulationRoute(route.route); + sService.setCardEmulationRoute(mPackageName, route.route); } catch (RemoteException e) { attemptDeadServiceRecovery(e); } @@ -201,7 +206,7 @@ public final class NfcAdapterExtras { /** * Get the {@link NfcExecutionEnvironment} that is embedded with the - * {@link NFcAdapter}. + * {@link NfcAdapter}. * * <p class="note"> * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. @@ -209,7 +214,7 @@ public final class NfcAdapterExtras { * @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE */ public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() { - return sEmbeddedEe; + return mEmbeddedEe; } /** @@ -218,12 +223,12 @@ public final class NfcAdapterExtras { * Some implementations of NFC Adapter Extras may require applications * to authenticate with a token, before using other methods. * - * @param a implementation specific token - * @throws a {@link java.lang.SecurityException} if authentication failed + * @param token a implementation specific token + * @throws java.lang.SecurityException if authentication failed */ public void authenticate(byte[] token) { try { - sService.authenticate(token); + sService.authenticate(mPackageName, token); } catch (RemoteException e) { attemptDeadServiceRecovery(e); } diff --git a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java index 63c2de2..f47327a 100644 --- a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java +++ b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java @@ -16,20 +16,17 @@ package com.android.nfc_extras; -import java.io.IOException; - import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.content.Context; -import android.nfc.INfcAdapterExtras; -import android.nfc.NfcAdapter; import android.os.Binder; import android.os.Bundle; -import android.os.IBinder; import android.os.RemoteException; +import java.io.IOException; + public class NfcExecutionEnvironment { private final NfcAdapterExtras mExtras; + private final Binder mToken; /** * Broadcast Action: An ISO-DEP AID was selected. @@ -115,6 +112,7 @@ public class NfcExecutionEnvironment { NfcExecutionEnvironment(NfcAdapterExtras extras) { mExtras = extras; + mToken = new Binder(); } /** @@ -133,7 +131,7 @@ public class NfcExecutionEnvironment { */ public void open() throws IOException { try { - Bundle b = mExtras.getService().open(new Binder()); + Bundle b = mExtras.getService().open(mExtras.mPackageName, mToken); throwBundle(b); } catch (RemoteException e) { mExtras.attemptDeadServiceRecovery(e); @@ -151,7 +149,7 @@ public class NfcExecutionEnvironment { */ public void close() throws IOException { try { - throwBundle(mExtras.getService().close()); + throwBundle(mExtras.getService().close(mExtras.mPackageName, mToken)); } catch (RemoteException e) { mExtras.attemptDeadServiceRecovery(e); throw new IOException("NFC Service was dead"); @@ -169,7 +167,7 @@ public class NfcExecutionEnvironment { public byte[] transceive(byte[] in) throws IOException { Bundle b; try { - b = mExtras.getService().transceive(in); + b = mExtras.getService().transceive(mExtras.mPackageName, in); } catch (RemoteException e) { mExtras.attemptDeadServiceRecovery(e); throw new IOException("NFC Service was dead, need to re-open"); |