1616
1717package android .nfc ;
1818
19+ import java .util .HashMap ;
20+
1921import android .annotation .SdkConstant ;
2022import android .annotation .SdkConstant .SdkConstantType ;
2123import android .app .Activity ;
@@ -197,15 +199,21 @@ public final class NfcAdapter {
197199 static INfcTag sTagService ;
198200
199201 /**
200- * NfcAdapter is currently a singleton, and does not require a context.
201- * However all the public API's are future-proofed to require a context.
202- * If we start using that then we'll need to keep a HashMap of
203- * Context.getApplicationContext() -> NfcAdapter, such that NfcAdapter
204- * is a singleton within each application context.
202+ * The NfcAdapter object for each application context.
203+ * There is a 1-1 relationship between application context and
204+ * NfcAdapter object.
205+ */
206+ static HashMap <Context , NfcAdapter > sNfcAdapters = new HashMap (); //guard by NfcAdapter.class
207+
208+ /**
209+ * NfcAdapter used with a null context. This ctor was deprecated but we have
210+ * to support it for backwards compatibility. New methods that require context
211+ * might throw when called on the null-context NfcAdapter.
205212 */
206- static NfcAdapter sSingleton ; // protected by NfcAdapter.class
213+ static NfcAdapter sNullContextNfcAdapter ; // protected by NfcAdapter.class
207214
208215 final NfcActivityManager mNfcActivityManager ;
216+ final Context mContext ;
209217
210218 /**
211219 * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
@@ -280,12 +288,12 @@ private static boolean hasNfcFeature() {
280288 }
281289
282290 /**
283- * Returns the singleton, or throws if NFC is not available.
291+ * Returns the NfcAdapter for application context,
292+ * or throws if NFC is not available.
293+ * @hide
284294 */
285- static synchronized NfcAdapter getSingleton ( ) {
295+ public static synchronized NfcAdapter getNfcAdapter ( Context context ) {
286296 if (!sIsInitialized ) {
287- sIsInitialized = true ;
288-
289297 /* is this device meant to have NFC */
290298 if (!hasNfcFeature ()) {
291299 Log .v (TAG , "this device does not have NFC support" );
@@ -303,12 +311,21 @@ static synchronized NfcAdapter getSingleton() {
303311 Log .e (TAG , "could not retrieve NFC Tag service" );
304312 throw new UnsupportedOperationException ();
305313 }
306- sSingleton = new NfcAdapter ();
314+
315+ sIsInitialized = true ;
316+ }
317+ if (context == null ) {
318+ if (sNullContextNfcAdapter == null ) {
319+ sNullContextNfcAdapter = new NfcAdapter (null );
320+ }
321+ return sNullContextNfcAdapter ;
307322 }
308- if (sSingleton == null ) {
309- throw new UnsupportedOperationException ();
323+ NfcAdapter adapter = sNfcAdapters .get (context );
324+ if (adapter == null ) {
325+ adapter = new NfcAdapter (context );
326+ sNfcAdapters .put (context , adapter );
310327 }
311- return sSingleton ;
328+ return adapter ;
312329 }
313330
314331 /** get handle to NFC service interface */
@@ -336,32 +353,41 @@ private static INfcAdapter getServiceInterface() {
336353 * @return the default NFC adapter, or null if no NFC adapter exists
337354 */
338355 public static NfcAdapter getDefaultAdapter (Context context ) {
356+ if (context == null ) {
357+ throw new IllegalArgumentException ("context cannot be null" );
358+ }
359+ context = context .getApplicationContext ();
339360 /* use getSystemService() instead of just instantiating to take
340361 * advantage of the context's cached NfcManager & NfcAdapter */
341362 NfcManager manager = (NfcManager ) context .getSystemService (Context .NFC_SERVICE );
342363 return manager .getDefaultAdapter ();
343364 }
344365
345366 /**
346- * Get a handle to the default NFC Adapter on this Android device.
347- * <p>
348- * Most Android devices will only have one NFC Adapter (NFC Controller).
349- *
350- * @return the default NFC adapter, or null if no NFC adapter exists
367+ * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
368+ * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
369+ * for many NFC API methods. Those methods will fail when called on an NfcAdapter
370+ * object created from this method.<p>
351371 * @deprecated use {@link #getDefaultAdapter(Context)}
352372 */
353373 @ Deprecated
354374 public static NfcAdapter getDefaultAdapter () {
355375 Log .w (TAG , "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
356376 "NfcAdapter.getDefaultAdapter(Context) instead" , new Exception ());
357- return getSingleton ();
377+
378+ return NfcAdapter .getNfcAdapter (null );
379+ }
380+
381+ NfcAdapter (Context context ) {
382+ mContext = context ;
383+ mNfcActivityManager = new NfcActivityManager (this );
358384 }
359385
360386 /**
361- * Does not currently need a context.
387+ * @hide
362388 */
363- NfcAdapter () {
364- mNfcActivityManager = new NfcActivityManager ( this ) ;
389+ public Context getContext () {
390+ return mContext ;
365391 }
366392
367393 /**
@@ -875,8 +901,12 @@ public boolean isNdefPushEnabled() {
875901 * @hide
876902 */
877903 public INfcAdapterExtras getNfcAdapterExtrasInterface () {
904+ if (mContext == null ) {
905+ throw new UnsupportedOperationException ("You need a context on NfcAdapter to use the "
906+ + " NFC extras APIs" );
907+ }
878908 try {
879- return sService .getNfcAdapterExtrasInterface ();
909+ return sService .getNfcAdapterExtrasInterface (mContext . getPackageName () );
880910 } catch (RemoteException e ) {
881911 attemptDeadServiceRecovery (e );
882912 return null ;
0 commit comments