• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.nfc;
18 
19 import java.util.HashMap;
20 
21 import android.annotation.SdkConstant;
22 import android.annotation.SdkConstant.SdkConstantType;
23 import android.annotation.SystemApi;
24 import android.app.Activity;
25 import android.app.ActivityThread;
26 import android.app.OnActivityPausedListener;
27 import android.app.PendingIntent;
28 import android.content.Context;
29 import android.content.IntentFilter;
30 import android.content.pm.IPackageManager;
31 import android.content.pm.PackageManager;
32 import android.net.Uri;
33 import android.nfc.tech.MifareClassic;
34 import android.nfc.tech.Ndef;
35 import android.nfc.tech.NfcA;
36 import android.nfc.tech.NfcF;
37 import android.os.Bundle;
38 import android.os.IBinder;
39 import android.os.RemoteException;
40 import android.os.ServiceManager;
41 import android.util.Log;
42 
43 /**
44  * Represents the local NFC adapter.
45  * <p>
46  * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC
47  * adapter for this Android device.
48  *
49  * <div class="special reference">
50  * <h3>Developer Guides</h3>
51  * <p>For more information about using NFC, read the
52  * <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p>
53  * <p>To perform basic file sharing between devices, read
54  * <a href="{@docRoot}training/beam-files/index.html">Sharing Files with NFC</a>.
55  * </div>
56  */
57 public final class NfcAdapter {
58     static final String TAG = "NFC";
59 
60     /**
61      * Intent to start an activity when a tag with NDEF payload is discovered.
62      *
63      * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and
64      * looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the
65      * intent will contain the URI in its data field. If a MIME record is found the intent will
66      * contain the MIME type in its type field. This allows activities to register
67      * {@link IntentFilter}s targeting specific content on tags. Activities should register the
68      * most specific intent filters possible to avoid the activity chooser dialog, which can
69      * disrupt the interaction with the tag as the user interacts with the screen.
70      *
71      * <p>If the tag has an NDEF payload this intent is started before
72      * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither
73      * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
74      *
75      * <p>The MIME type or data URI of this intent are normalized before dispatch -
76      * so that MIME, URI scheme and URI host are always lower-case.
77      */
78     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
79     public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
80 
81     /**
82      * Intent to start an activity when a tag is discovered and activities are registered for the
83      * specific technologies on the tag.
84      *
85      * <p>To receive this intent an activity must include an intent filter
86      * for this action and specify the desired tech types in a
87      * manifest <code>meta-data</code> entry. Here is an example manfiest entry:
88      * <pre>
89      * &lt;activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"&gt;
90      *     &lt;!-- Add a technology filter --&gt;
91      *     &lt;intent-filter&gt;
92      *         &lt;action android:name="android.nfc.action.TECH_DISCOVERED" /&gt;
93      *     &lt;/intent-filter&gt;
94      *
95      *     &lt;meta-data android:name="android.nfc.action.TECH_DISCOVERED"
96      *         android:resource="@xml/filter_nfc"
97      *     /&gt;
98      * &lt;/activity&gt;</pre>
99      *
100      * <p>The meta-data XML file should contain one or more <code>tech-list</code> entries
101      * each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer
102      * to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA".
103      *
104      * <p>A tag matches if any of the
105      * <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each
106      * of the <code>tech-list</code>s is considered independently and the
107      * activity is considered a match is any single <code>tech-list</code> matches the tag that was
108      * discovered. This provides AND and OR semantics for filtering desired techs. Here is an
109      * example that will match any tag using {@link NfcF} or any tag using {@link NfcA},
110      * {@link MifareClassic}, and {@link Ndef}:
111      *
112      * <pre>
113      * &lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
114      *     &lt;!-- capture anything using NfcF --&gt;
115      *     &lt;tech-list&gt;
116      *         &lt;tech&gt;android.nfc.tech.NfcF&lt;/tech&gt;
117      *     &lt;/tech-list&gt;
118      *
119      *     &lt;!-- OR --&gt;
120      *
121      *     &lt;!-- capture all MIFARE Classics with NDEF payloads --&gt;
122      *     &lt;tech-list&gt;
123      *         &lt;tech&gt;android.nfc.tech.NfcA&lt;/tech&gt;
124      *         &lt;tech&gt;android.nfc.tech.MifareClassic&lt;/tech&gt;
125      *         &lt;tech&gt;android.nfc.tech.Ndef&lt;/tech&gt;
126      *     &lt;/tech-list&gt;
127      * &lt;/resources&gt;</pre>
128      *
129      * <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before
130      * {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED}
131      * this intent will not be started. If any activities respond to this intent
132      * {@link #ACTION_TAG_DISCOVERED} will not be started.
133      */
134     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
135     public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
136 
137     /**
138      * Intent to start an activity when a tag is discovered.
139      *
140      * <p>This intent will not be started when a tag is discovered if any activities respond to
141      * {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag.
142      */
143     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
144     public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
145 
146     /**
147      * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED
148      * @hide
149      */
150     public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST";
151 
152     /**
153      * Mandatory extra containing the {@link Tag} that was discovered for the
154      * {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
155      * {@link #ACTION_TAG_DISCOVERED} intents.
156      */
157     public static final String EXTRA_TAG = "android.nfc.extra.TAG";
158 
159     /**
160      * Extra containing an array of {@link NdefMessage} present on the discovered tag.<p>
161      * This extra is mandatory for {@link #ACTION_NDEF_DISCOVERED} intents,
162      * and optional for {@link #ACTION_TECH_DISCOVERED}, and
163      * {@link #ACTION_TAG_DISCOVERED} intents.<p>
164      * When this extra is present there will always be at least one
165      * {@link NdefMessage} element. Most NDEF tags have only one NDEF message,
166      * but we use an array for future compatibility.
167      */
168     public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
169 
170     /**
171      * Optional extra containing a byte array containing the ID of the discovered tag for
172      * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
173      * {@link #ACTION_TAG_DISCOVERED} intents.
174      */
175     public static final String EXTRA_ID = "android.nfc.extra.ID";
176 
177     /**
178      * Broadcast Action: The state of the local NFC adapter has been
179      * changed.
180      * <p>For example, NFC has been turned on or off.
181      * <p>Always contains the extra field {@link #EXTRA_ADAPTER_STATE}
182      */
183     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
184     public static final String ACTION_ADAPTER_STATE_CHANGED =
185             "android.nfc.action.ADAPTER_STATE_CHANGED";
186 
187     /**
188      * Used as an int extra field in {@link #ACTION_ADAPTER_STATE_CHANGED}
189      * intents to request the current power state. Possible values are:
190      * {@link #STATE_OFF},
191      * {@link #STATE_TURNING_ON},
192      * {@link #STATE_ON},
193      * {@link #STATE_TURNING_OFF},
194      */
195     public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
196 
197     public static final int STATE_OFF = 1;
198     public static final int STATE_TURNING_ON = 2;
199     public static final int STATE_ON = 3;
200     public static final int STATE_TURNING_OFF = 4;
201 
202     /**
203      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
204      * <p>
205      * Setting this flag enables polling for Nfc-A technology.
206      */
207     public static final int FLAG_READER_NFC_A = 0x1;
208 
209     /**
210      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
211      * <p>
212      * Setting this flag enables polling for Nfc-B technology.
213      */
214     public static final int FLAG_READER_NFC_B = 0x2;
215 
216     /**
217      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
218      * <p>
219      * Setting this flag enables polling for Nfc-F technology.
220      */
221     public static final int FLAG_READER_NFC_F = 0x4;
222 
223     /**
224      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
225      * <p>
226      * Setting this flag enables polling for Nfc-V (ISO15693) technology.
227      */
228     public static final int FLAG_READER_NFC_V = 0x8;
229 
230     /**
231      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
232      * <p>
233      * Setting this flag enables polling for NfcBarcode technology.
234      */
235     public static final int FLAG_READER_NFC_BARCODE = 0x10;
236 
237     /**
238      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
239      * <p>
240      * Setting this flag allows the caller to prevent the
241      * platform from performing an NDEF check on the tags it
242      * finds.
243      */
244     public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80;
245 
246     /**
247      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
248      * <p>
249      * Setting this flag allows the caller to prevent the
250      * platform from playing sounds when it discovers a tag.
251      */
252     public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100;
253 
254     /**
255      * Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
256      * <p>
257      * Setting this integer extra allows the calling application to specify
258      * the delay that the platform will use for performing presence checks
259      * on any discovered tag.
260      */
261     public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
262 
263     /** @hide */
264     @SystemApi
265     public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
266 
267     /** @hide */
268     public static final String ACTION_HANDOVER_TRANSFER_STARTED =
269             "android.nfc.action.HANDOVER_TRANSFER_STARTED";
270 
271     /** @hide */
272     public static final String ACTION_HANDOVER_TRANSFER_DONE =
273             "android.nfc.action.HANDOVER_TRANSFER_DONE";
274 
275     /** @hide */
276     public static final String EXTRA_HANDOVER_TRANSFER_STATUS =
277             "android.nfc.extra.HANDOVER_TRANSFER_STATUS";
278 
279     /** @hide */
280     public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
281     /** @hide */
282     public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
283 
284     /** @hide */
285     public static final String EXTRA_HANDOVER_TRANSFER_URI =
286             "android.nfc.extra.HANDOVER_TRANSFER_URI";
287 
288     // Guarded by NfcAdapter.class
289     static boolean sIsInitialized = false;
290 
291     // Final after first constructor, except for
292     // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
293     // recovery
294     static INfcAdapter sService;
295     static INfcTag sTagService;
296     static INfcCardEmulation sCardEmulationService;
297 
298     /**
299      * The NfcAdapter object for each application context.
300      * There is a 1-1 relationship between application context and
301      * NfcAdapter object.
302      */
303     static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class
304 
305     /**
306      * NfcAdapter used with a null context. This ctor was deprecated but we have
307      * to support it for backwards compatibility. New methods that require context
308      * might throw when called on the null-context NfcAdapter.
309      */
310     static NfcAdapter sNullContextNfcAdapter;  // protected by NfcAdapter.class
311 
312     final NfcActivityManager mNfcActivityManager;
313     final Context mContext;
314     final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
315     final Object mLock;
316 
317     /**
318      * A callback to be invoked when the system finds a tag while the foreground activity is
319      * operating in reader mode.
320      * <p>Register your {@code ReaderCallback} implementation with {@link
321      * NfcAdapter#enableReaderMode} and disable it with {@link
322      * NfcAdapter#disableReaderMode}.
323      * @see NfcAdapter#enableReaderMode
324      */
325     public interface ReaderCallback {
onTagDiscovered(Tag tag)326         public void onTagDiscovered(Tag tag);
327     }
328 
329     /**
330      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
331      * to another device.
332      * @see #setOnNdefPushCompleteCallback
333      */
334     public interface OnNdefPushCompleteCallback {
335         /**
336          * Called on successful NDEF push.
337          *
338          * <p>This callback is usually made on a binder thread (not the UI thread).
339          *
340          * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
341          * @see #setNdefPushMessageCallback
342          */
onNdefPushComplete(NfcEvent event)343         public void onNdefPushComplete(NfcEvent event);
344     }
345 
346     /**
347      * A callback to be invoked when another NFC device capable of NDEF push (Android Beam)
348      * is within range.
349      * <p>Implement this interface and pass it to {@link
350      * NfcAdapter#setNdefPushMessageCallback setNdefPushMessageCallback()} in order to create an
351      * {@link NdefMessage} at the moment that another device is within range for NFC. Using this
352      * callback allows you to create a message with data that might vary based on the
353      * content currently visible to the user. Alternatively, you can call {@link
354      * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
355      * same data.
356      */
357     public interface CreateNdefMessageCallback {
358         /**
359          * Called to provide a {@link NdefMessage} to push.
360          *
361          * <p>This callback is usually made on a binder thread (not the UI thread).
362          *
363          * <p>Called when this device is in range of another device
364          * that might support NDEF push. It allows the application to
365          * create the NDEF message only when it is required.
366          *
367          * <p>NDEF push cannot occur until this method returns, so do not
368          * block for too long.
369          *
370          * <p>The Android operating system will usually show a system UI
371          * on top of your activity during this time, so do not try to request
372          * input from the user to complete the callback, or provide custom NDEF
373          * push UI. The user probably will not see it.
374          *
375          * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
376          * @return NDEF message to push, or null to not provide a message
377          */
createNdefMessage(NfcEvent event)378         public NdefMessage createNdefMessage(NfcEvent event);
379     }
380 
381 
382     // TODO javadoc
383     public interface CreateBeamUrisCallback {
createBeamUris(NfcEvent event)384         public Uri[] createBeamUris(NfcEvent event);
385     }
386 
387     /**
388      * A callback to be invoked when an application has registered as a
389      * handler to unlock the device given an NFC tag at the lockscreen.
390      * @hide
391      */
392     @SystemApi
393     public interface NfcUnlockHandler {
394         /**
395          * Called at the lock screen to attempt to unlock the device with the given tag.
396          * @param tag the detected tag, to be used to unlock the device
397          * @return true if the device was successfully unlocked
398          */
onUnlockAttempted(Tag tag)399         public boolean onUnlockAttempted(Tag tag);
400     }
401 
402 
403     /**
404      * Helper to check if this device has FEATURE_NFC, but without using
405      * a context.
406      * Equivalent to
407      * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)
408      */
hasNfcFeature()409     private static boolean hasNfcFeature() {
410         IPackageManager pm = ActivityThread.getPackageManager();
411         if (pm == null) {
412             Log.e(TAG, "Cannot get package manager, assuming no NFC feature");
413             return false;
414         }
415         try {
416             return pm.hasSystemFeature(PackageManager.FEATURE_NFC);
417         } catch (RemoteException e) {
418             Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
419             return false;
420         }
421     }
422 
423     /**
424      * Returns the NfcAdapter for application context,
425      * or throws if NFC is not available.
426      * @hide
427      */
getNfcAdapter(Context context)428     public static synchronized NfcAdapter getNfcAdapter(Context context) {
429         if (!sIsInitialized) {
430             /* is this device meant to have NFC */
431             if (!hasNfcFeature()) {
432                 Log.v(TAG, "this device does not have NFC support");
433                 throw new UnsupportedOperationException();
434             }
435 
436             sService = getServiceInterface();
437             if (sService == null) {
438                 Log.e(TAG, "could not retrieve NFC service");
439                 throw new UnsupportedOperationException();
440             }
441             try {
442                 sTagService = sService.getNfcTagInterface();
443             } catch (RemoteException e) {
444                 Log.e(TAG, "could not retrieve NFC Tag service");
445                 throw new UnsupportedOperationException();
446             }
447 
448             try {
449                 sCardEmulationService = sService.getNfcCardEmulationInterface();
450             } catch (RemoteException e) {
451                 Log.e(TAG, "could not retrieve card emulation service");
452                 throw new UnsupportedOperationException();
453             }
454 
455             sIsInitialized = true;
456         }
457         if (context == null) {
458             if (sNullContextNfcAdapter == null) {
459                 sNullContextNfcAdapter = new NfcAdapter(null);
460             }
461             return sNullContextNfcAdapter;
462         }
463         NfcAdapter adapter = sNfcAdapters.get(context);
464         if (adapter == null) {
465             adapter = new NfcAdapter(context);
466             sNfcAdapters.put(context, adapter);
467         }
468         return adapter;
469     }
470 
471     /** get handle to NFC service interface */
getServiceInterface()472     private static INfcAdapter getServiceInterface() {
473         /* get a handle to NFC service */
474         IBinder b = ServiceManager.getService("nfc");
475         if (b == null) {
476             return null;
477         }
478         return INfcAdapter.Stub.asInterface(b);
479     }
480 
481     /**
482      * Helper to get the default NFC Adapter.
483      * <p>
484      * Most Android devices will only have one NFC Adapter (NFC Controller).
485      * <p>
486      * This helper is the equivalent of:
487      * <pre>
488      * NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
489      * NfcAdapter adapter = manager.getDefaultAdapter();</pre>
490      * @param context the calling application's context
491      *
492      * @return the default NFC adapter, or null if no NFC adapter exists
493      */
getDefaultAdapter(Context context)494     public static NfcAdapter getDefaultAdapter(Context context) {
495         if (context == null) {
496             throw new IllegalArgumentException("context cannot be null");
497         }
498         context = context.getApplicationContext();
499         if (context == null) {
500             throw new IllegalArgumentException(
501                     "context not associated with any application (using a mock context?)");
502         }
503         /* use getSystemService() for consistency */
504         NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
505         if (manager == null) {
506             // NFC not available
507             return null;
508         }
509         return manager.getDefaultAdapter();
510     }
511 
512     /**
513      * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
514      * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
515      * for many NFC API methods. Those methods will fail when called on an NfcAdapter
516      * object created from this method.<p>
517      * @deprecated use {@link #getDefaultAdapter(Context)}
518      * @hide
519      */
520     @Deprecated
getDefaultAdapter()521     public static NfcAdapter getDefaultAdapter() {
522         // introduced in API version 9 (GB 2.3)
523         // deprecated in API version 10 (GB 2.3.3)
524         // removed from public API in version 16 (ICS MR2)
525         // should maintain as a hidden API for binary compatibility for a little longer
526         Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
527                 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
528 
529         return NfcAdapter.getNfcAdapter(null);
530     }
531 
NfcAdapter(Context context)532     NfcAdapter(Context context) {
533         mContext = context;
534         mNfcActivityManager = new NfcActivityManager(this);
535         mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
536         mLock = new Object();
537     }
538 
539     /**
540      * @hide
541      */
getContext()542     public Context getContext() {
543         return mContext;
544     }
545 
546     /**
547      * Returns the binder interface to the service.
548      * @hide
549      */
getService()550     public INfcAdapter getService() {
551         isEnabled();  // NOP call to recover sService if it is stale
552         return sService;
553     }
554 
555     /**
556      * Returns the binder interface to the tag service.
557      * @hide
558      */
getTagService()559     public INfcTag getTagService() {
560         isEnabled();  // NOP call to recover sTagService if it is stale
561         return sTagService;
562     }
563 
564     /**
565      * Returns the binder interface to the card emulation service.
566      * @hide
567      */
getCardEmulationService()568     public INfcCardEmulation getCardEmulationService() {
569         isEnabled();
570         return sCardEmulationService;
571     }
572 
573     /**
574      * NFC service dead - attempt best effort recovery
575      * @hide
576      */
attemptDeadServiceRecovery(Exception e)577     public void attemptDeadServiceRecovery(Exception e) {
578         Log.e(TAG, "NFC service dead - attempting to recover", e);
579         INfcAdapter service = getServiceInterface();
580         if (service == null) {
581             Log.e(TAG, "could not retrieve NFC service during service recovery");
582             // nothing more can be done now, sService is still stale, we'll hit
583             // this recovery path again later
584             return;
585         }
586         // assigning to sService is not thread-safe, but this is best-effort code
587         // and on a well-behaved system should never happen
588         sService = service;
589         try {
590             sTagService = service.getNfcTagInterface();
591         } catch (RemoteException ee) {
592             Log.e(TAG, "could not retrieve NFC tag service during service recovery");
593             // nothing more can be done now, sService is still stale, we'll hit
594             // this recovery path again later
595             return;
596         }
597 
598         try {
599             sCardEmulationService = service.getNfcCardEmulationInterface();
600         } catch (RemoteException ee) {
601             Log.e(TAG, "could not retrieve NFC card emulation service during service recovery");
602         }
603 
604         return;
605     }
606 
607     /**
608      * Return true if this NFC Adapter has any features enabled.
609      *
610      * <p>If this method returns false, the NFC hardware is guaranteed not to
611      * generate or respond to any NFC communication over its NFC radio.
612      * <p>Applications can use this to check if NFC is enabled. Applications
613      * can request Settings UI allowing the user to toggle NFC using:
614      * <p><pre>startActivity(new Intent(Settings.ACTION_NFC_SETTINGS))</pre>
615      *
616      * @see android.provider.Settings#ACTION_NFC_SETTINGS
617      * @return true if this NFC Adapter has any features enabled
618      */
isEnabled()619     public boolean isEnabled() {
620         try {
621             return sService.getState() == STATE_ON;
622         } catch (RemoteException e) {
623             attemptDeadServiceRecovery(e);
624             return false;
625         }
626     }
627 
628     /**
629      * Return the state of this NFC Adapter.
630      *
631      * <p>Returns one of {@link #STATE_ON}, {@link #STATE_TURNING_ON},
632      * {@link #STATE_OFF}, {@link #STATE_TURNING_OFF}.
633      *
634      * <p>{@link #isEnabled()} is equivalent to
635      * <code>{@link #getAdapterState()} == {@link #STATE_ON}</code>
636      *
637      * @return the current state of this NFC adapter
638      *
639      * @hide
640      */
getAdapterState()641     public int getAdapterState() {
642         try {
643             return sService.getState();
644         } catch (RemoteException e) {
645             attemptDeadServiceRecovery(e);
646             return NfcAdapter.STATE_OFF;
647         }
648     }
649 
650     /**
651      * Enable NFC hardware.
652      *
653      * <p>This call is asynchronous. Listen for
654      * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
655      * operation is complete.
656      *
657      * <p>If this returns true, then either NFC is already on, or
658      * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
659      * to indicate a state transition. If this returns false, then
660      * there is some problem that prevents an attempt to turn
661      * NFC on (for example we are in airplane mode and NFC is not
662      * toggleable in airplane mode on this platform).
663      *
664      * @hide
665      */
666     @SystemApi
enable()667     public boolean enable() {
668         try {
669             return sService.enable();
670         } catch (RemoteException e) {
671             attemptDeadServiceRecovery(e);
672             return false;
673         }
674     }
675 
676     /**
677      * Disable NFC hardware.
678      *
679      * <p>No NFC features will work after this call, and the hardware
680      * will not perform or respond to any NFC communication.
681      *
682      * <p>This call is asynchronous. Listen for
683      * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
684      * operation is complete.
685      *
686      * <p>If this returns true, then either NFC is already off, or
687      * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
688      * to indicate a state transition. If this returns false, then
689      * there is some problem that prevents an attempt to turn
690      * NFC off.
691      *
692      * @hide
693      */
694     @SystemApi
disable()695     public boolean disable() {
696         try {
697             return sService.disable(true);
698         } catch (RemoteException e) {
699             attemptDeadServiceRecovery(e);
700             return false;
701         }
702     }
703 
704     /**
705      * Disable NFC hardware.
706      * @hide
707     */
708     @SystemApi
disable(boolean persist)709     public boolean disable(boolean persist) {
710         try {
711             return sService.disable(persist);
712         } catch (RemoteException e) {
713             attemptDeadServiceRecovery(e);
714             return false;
715         }
716     }
717 
718     /**
719      * Pauses polling for a {@code timeoutInMs} millis. If polling must be resumed before timeout,
720      * use {@link #resumePolling()}.
721      * @hide
722      */
pausePolling(int timeoutInMs)723     public void pausePolling(int timeoutInMs) {
724         try {
725             sService.pausePolling(timeoutInMs);
726         } catch (RemoteException e) {
727             attemptDeadServiceRecovery(e);
728         }
729     }
730 
731     /**
732      * Resumes default polling for the current device state if polling is paused. Calling
733      * this while polling is not paused is a no-op.
734      *
735      * @hide
736      */
resumePolling()737     public void resumePolling() {
738         try {
739             sService.resumePolling();
740         } catch (RemoteException e) {
741             attemptDeadServiceRecovery(e);
742         }
743     }
744 
745     /**
746      * Set one or more {@link Uri}s to send using Android Beam (TM). Every
747      * Uri you provide must have either scheme 'file' or scheme 'content'.
748      *
749      * <p>For the data provided through this method, Android Beam tries to
750      * switch to alternate transports such as Bluetooth to achieve a fast
751      * transfer speed. Hence this method is very suitable
752      * for transferring large files such as pictures or songs.
753      *
754      * <p>The receiving side will store the content of each Uri in
755      * a file and present a notification to the user to open the file
756      * with a {@link android.content.Intent} with action
757      * {@link android.content.Intent#ACTION_VIEW}.
758      * If multiple URIs are sent, the {@link android.content.Intent} will refer
759      * to the first of the stored files.
760      *
761      * <p>This method may be called at any time before {@link Activity#onDestroy},
762      * but the URI(s) are only made available for Android Beam when the
763      * specified activity(s) are in resumed (foreground) state. The recommended
764      * approach is to call this method during your Activity's
765      * {@link Activity#onCreate} - see sample
766      * code below. This method does not immediately perform any I/O or blocking work,
767      * so is safe to call on your main thread.
768      *
769      * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
770      * have priority over both {@link #setNdefPushMessage} and
771      * {@link #setNdefPushMessageCallback}.
772      *
773      * <p>If {@link #setBeamPushUris} is called with a null Uri array,
774      * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
775      * then the Uri push will be completely disabled for the specified activity(s).
776      *
777      * <p>Code example:
778      * <pre>
779      * protected void onCreate(Bundle savedInstanceState) {
780      *     super.onCreate(savedInstanceState);
781      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
782      *     if (nfcAdapter == null) return;  // NFC not available on this device
783      *     nfcAdapter.setBeamPushUris(new Uri[] {uri1, uri2}, this);
784      * }</pre>
785      * And that is it. Only one call per activity is necessary. The Android
786      * OS will automatically release its references to the Uri(s) and the
787      * Activity object when it is destroyed if you follow this pattern.
788      *
789      * <p>If your Activity wants to dynamically supply Uri(s),
790      * then set a callback using {@link #setBeamPushUrisCallback} instead
791      * of using this method.
792      *
793      * <p class="note">Do not pass in an Activity that has already been through
794      * {@link Activity#onDestroy}. This is guaranteed if you call this API
795      * during {@link Activity#onCreate}.
796      *
797      * <p class="note">If this device does not support alternate transports
798      * such as Bluetooth or WiFI, calling this method does nothing.
799      *
800      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
801      *
802      * @param uris an array of Uri(s) to push over Android Beam
803      * @param activity activity for which the Uri(s) will be pushed
804      */
setBeamPushUris(Uri[] uris, Activity activity)805     public void setBeamPushUris(Uri[] uris, Activity activity) {
806         if (activity == null) {
807             throw new NullPointerException("activity cannot be null");
808         }
809         if (uris != null) {
810             for (Uri uri : uris) {
811                 if (uri == null) throw new NullPointerException("Uri not " +
812                         "allowed to be null");
813                 String scheme = uri.getScheme();
814                 if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
815                         !scheme.equalsIgnoreCase("content"))) {
816                     throw new IllegalArgumentException("URI needs to have " +
817                             "either scheme file or scheme content");
818                 }
819             }
820         }
821         mNfcActivityManager.setNdefPushContentUri(activity, uris);
822     }
823 
824     /**
825      * Set a callback that will dynamically generate one or more {@link Uri}s
826      * to send using Android Beam (TM). Every Uri the callback provides
827      * must have either scheme 'file' or scheme 'content'.
828      *
829      * <p>For the data provided through this callback, Android Beam tries to
830      * switch to alternate transports such as Bluetooth to achieve a fast
831      * transfer speed. Hence this method is very suitable
832      * for transferring large files such as pictures or songs.
833      *
834      * <p>The receiving side will store the content of each Uri in
835      * a file and present a notification to the user to open the file
836      * with a {@link android.content.Intent} with action
837      * {@link android.content.Intent#ACTION_VIEW}.
838      * If multiple URIs are sent, the {@link android.content.Intent} will refer
839      * to the first of the stored files.
840      *
841      * <p>This method may be called at any time before {@link Activity#onDestroy},
842      * but the URI(s) are only made available for Android Beam when the
843      * specified activity(s) are in resumed (foreground) state. The recommended
844      * approach is to call this method during your Activity's
845      * {@link Activity#onCreate} - see sample
846      * code below. This method does not immediately perform any I/O or blocking work,
847      * so is safe to call on your main thread.
848      *
849      * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
850      * have priority over both {@link #setNdefPushMessage} and
851      * {@link #setNdefPushMessageCallback}.
852      *
853      * <p>If {@link #setBeamPushUris} is called with a null Uri array,
854      * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
855      * then the Uri push will be completely disabled for the specified activity(s).
856      *
857      * <p>Code example:
858      * <pre>
859      * protected void onCreate(Bundle savedInstanceState) {
860      *     super.onCreate(savedInstanceState);
861      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
862      *     if (nfcAdapter == null) return;  // NFC not available on this device
863      *     nfcAdapter.setBeamPushUrisCallback(callback, this);
864      * }</pre>
865      * And that is it. Only one call per activity is necessary. The Android
866      * OS will automatically release its references to the Uri(s) and the
867      * Activity object when it is destroyed if you follow this pattern.
868      *
869      * <p class="note">Do not pass in an Activity that has already been through
870      * {@link Activity#onDestroy}. This is guaranteed if you call this API
871      * during {@link Activity#onCreate}.
872      *
873      * <p class="note">If this device does not support alternate transports
874      * such as Bluetooth or WiFI, calling this method does nothing.
875      *
876      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
877      *
878      * @param callback callback, or null to disable
879      * @param activity activity for which the Uri(s) will be pushed
880      */
setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity)881     public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
882         if (activity == null) {
883             throw new NullPointerException("activity cannot be null");
884         }
885         mNfcActivityManager.setNdefPushContentUriCallback(activity, callback);
886     }
887 
888     /**
889      * Set a static {@link NdefMessage} to send using Android Beam (TM).
890      *
891      * <p>This method may be called at any time before {@link Activity#onDestroy},
892      * but the NDEF message is only made available for NDEF push when the
893      * specified activity(s) are in resumed (foreground) state. The recommended
894      * approach is to call this method during your Activity's
895      * {@link Activity#onCreate} - see sample
896      * code below. This method does not immediately perform any I/O or blocking work,
897      * so is safe to call on your main thread.
898      *
899      * <p>Only one NDEF message can be pushed by the currently resumed activity.
900      * If both {@link #setNdefPushMessage} and
901      * {@link #setNdefPushMessageCallback} are set, then
902      * the callback will take priority.
903      *
904      * <p>If neither {@link #setNdefPushMessage} or
905      * {@link #setNdefPushMessageCallback} have been called for your activity, then
906      * the Android OS may choose to send a default NDEF message on your behalf,
907      * such as a URI for your application.
908      *
909      * <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
910      * and/or {@link #setNdefPushMessageCallback} is called with a null callback,
911      * then NDEF push will be completely disabled for the specified activity(s).
912      * This also disables any default NDEF message the Android OS would have
913      * otherwise sent on your behalf for those activity(s).
914      *
915      * <p>If you want to prevent the Android OS from sending default NDEF
916      * messages completely (for all activities), you can include a
917      * {@code &lt;meta-data>} element inside the {@code &lt;application>}
918      * element of your AndroidManifest.xml file, like this:
919      * <pre>
920      * &lt;application ...>
921      *     &lt;meta-data android:name="android.nfc.disable_beam_default"
922      *         android:value="true" />
923      * &lt;/application></pre>
924      *
925      * <p>The API allows for multiple activities to be specified at a time,
926      * but it is strongly recommended to just register one at a time,
927      * and to do so during the activity's {@link Activity#onCreate}. For example:
928      * <pre>
929      * protected void onCreate(Bundle savedInstanceState) {
930      *     super.onCreate(savedInstanceState);
931      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
932      *     if (nfcAdapter == null) return;  // NFC not available on this device
933      *     nfcAdapter.setNdefPushMessage(ndefMessage, this);
934      * }</pre>
935      * And that is it. Only one call per activity is necessary. The Android
936      * OS will automatically release its references to the NDEF message and the
937      * Activity object when it is destroyed if you follow this pattern.
938      *
939      * <p>If your Activity wants to dynamically generate an NDEF message,
940      * then set a callback using {@link #setNdefPushMessageCallback} instead
941      * of a static message.
942      *
943      * <p class="note">Do not pass in an Activity that has already been through
944      * {@link Activity#onDestroy}. This is guaranteed if you call this API
945      * during {@link Activity#onCreate}.
946      *
947      * <p class="note">For sending large content such as pictures and songs,
948      * consider using {@link #setBeamPushUris}, which switches to alternate transports
949      * such as Bluetooth to achieve a fast transfer rate.
950      *
951      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
952      *
953      * @param message NDEF message to push over NFC, or null to disable
954      * @param activity activity for which the NDEF message will be pushed
955      * @param activities optional additional activities, however we strongly recommend
956      *        to only register one at a time, and to do so in that activity's
957      *        {@link Activity#onCreate}
958      */
setNdefPushMessage(NdefMessage message, Activity activity, Activity ... activities)959     public void setNdefPushMessage(NdefMessage message, Activity activity,
960             Activity ... activities) {
961         int targetSdkVersion = getSdkVersion();
962         try {
963             if (activity == null) {
964                 throw new NullPointerException("activity cannot be null");
965             }
966             mNfcActivityManager.setNdefPushMessage(activity, message, 0);
967             for (Activity a : activities) {
968                 if (a == null) {
969                     throw new NullPointerException("activities cannot contain null");
970                 }
971                 mNfcActivityManager.setNdefPushMessage(a, message, 0);
972             }
973         } catch (IllegalStateException e) {
974             if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
975                 // Less strict on old applications - just log the error
976                 Log.e(TAG, "Cannot call API with Activity that has already " +
977                         "been destroyed", e);
978             } else {
979                 // Prevent new applications from making this mistake, re-throw
980                 throw(e);
981             }
982         }
983     }
984 
985     /**
986      * @hide
987      */
988     @SystemApi
setNdefPushMessage(NdefMessage message, Activity activity, int flags)989     public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
990         if (activity == null) {
991             throw new NullPointerException("activity cannot be null");
992         }
993         mNfcActivityManager.setNdefPushMessage(activity, message, flags);
994     }
995 
996     /**
997      * Set a callback that dynamically generates NDEF messages to send using Android Beam (TM).
998      *
999      * <p>This method may be called at any time before {@link Activity#onDestroy},
1000      * but the NDEF message callback can only occur when the
1001      * specified activity(s) are in resumed (foreground) state. The recommended
1002      * approach is to call this method during your Activity's
1003      * {@link Activity#onCreate} - see sample
1004      * code below. This method does not immediately perform any I/O or blocking work,
1005      * so is safe to call on your main thread.
1006      *
1007      * <p>Only one NDEF message can be pushed by the currently resumed activity.
1008      * If both {@link #setNdefPushMessage} and
1009      * {@link #setNdefPushMessageCallback} are set, then
1010      * the callback will take priority.
1011      *
1012      * <p>If neither {@link #setNdefPushMessage} or
1013      * {@link #setNdefPushMessageCallback} have been called for your activity, then
1014      * the Android OS may choose to send a default NDEF message on your behalf,
1015      * such as a URI for your application.
1016      *
1017      * <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
1018      * and/or {@link #setNdefPushMessageCallback} is called with a null callback,
1019      * then NDEF push will be completely disabled for the specified activity(s).
1020      * This also disables any default NDEF message the Android OS would have
1021      * otherwise sent on your behalf for those activity(s).
1022      *
1023      * <p>If you want to prevent the Android OS from sending default NDEF
1024      * messages completely (for all activities), you can include a
1025      * {@code &lt;meta-data>} element inside the {@code &lt;application>}
1026      * element of your AndroidManifest.xml file, like this:
1027      * <pre>
1028      * &lt;application ...>
1029      *     &lt;meta-data android:name="android.nfc.disable_beam_default"
1030      *         android:value="true" />
1031      * &lt;/application></pre>
1032      *
1033      * <p>The API allows for multiple activities to be specified at a time,
1034      * but it is strongly recommended to just register one at a time,
1035      * and to do so during the activity's {@link Activity#onCreate}. For example:
1036      * <pre>
1037      * protected void onCreate(Bundle savedInstanceState) {
1038      *     super.onCreate(savedInstanceState);
1039      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
1040      *     if (nfcAdapter == null) return;  // NFC not available on this device
1041      *     nfcAdapter.setNdefPushMessageCallback(callback, this);
1042      * }</pre>
1043      * And that is it. Only one call per activity is necessary. The Android
1044      * OS will automatically release its references to the callback and the
1045      * Activity object when it is destroyed if you follow this pattern.
1046      *
1047      * <p class="note">Do not pass in an Activity that has already been through
1048      * {@link Activity#onDestroy}. This is guaranteed if you call this API
1049      * during {@link Activity#onCreate}.
1050      * <p class="note">For sending large content such as pictures and songs,
1051      * consider using {@link #setBeamPushUris}, which switches to alternate transports
1052      * such as Bluetooth to achieve a fast transfer rate.
1053      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1054      *
1055      * @param callback callback, or null to disable
1056      * @param activity activity for which the NDEF message will be pushed
1057      * @param activities optional additional activities, however we strongly recommend
1058      *        to only register one at a time, and to do so in that activity's
1059      *        {@link Activity#onCreate}
1060      */
setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity, Activity ... activities)1061     public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
1062             Activity ... activities) {
1063         int targetSdkVersion = getSdkVersion();
1064         try {
1065             if (activity == null) {
1066                 throw new NullPointerException("activity cannot be null");
1067             }
1068             mNfcActivityManager.setNdefPushMessageCallback(activity, callback, 0);
1069             for (Activity a : activities) {
1070                 if (a == null) {
1071                     throw new NullPointerException("activities cannot contain null");
1072                 }
1073                 mNfcActivityManager.setNdefPushMessageCallback(a, callback, 0);
1074             }
1075         } catch (IllegalStateException e) {
1076             if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
1077                 // Less strict on old applications - just log the error
1078                 Log.e(TAG, "Cannot call API with Activity that has already " +
1079                         "been destroyed", e);
1080             } else {
1081                 // Prevent new applications from making this mistake, re-throw
1082                 throw(e);
1083             }
1084         }
1085     }
1086 
1087     /**
1088      * @hide
1089      */
setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity, int flags)1090     public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
1091             int flags) {
1092         if (activity == null) {
1093             throw new NullPointerException("activity cannot be null");
1094         }
1095         mNfcActivityManager.setNdefPushMessageCallback(activity, callback, flags);
1096     }
1097 
1098     /**
1099      * Set a callback on successful Android Beam (TM).
1100      *
1101      * <p>This method may be called at any time before {@link Activity#onDestroy},
1102      * but the callback can only occur when the
1103      * specified activity(s) are in resumed (foreground) state. The recommended
1104      * approach is to call this method during your Activity's
1105      * {@link Activity#onCreate} - see sample
1106      * code below. This method does not immediately perform any I/O or blocking work,
1107      * so is safe to call on your main thread.
1108      *
1109      * <p>The API allows for multiple activities to be specified at a time,
1110      * but it is strongly recommended to just register one at a time,
1111      * and to do so during the activity's {@link Activity#onCreate}. For example:
1112      * <pre>
1113      * protected void onCreate(Bundle savedInstanceState) {
1114      *     super.onCreate(savedInstanceState);
1115      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
1116      *     if (nfcAdapter == null) return;  // NFC not available on this device
1117      *     nfcAdapter.setOnNdefPushCompleteCallback(callback, this);
1118      * }</pre>
1119      * And that is it. Only one call per activity is necessary. The Android
1120      * OS will automatically release its references to the callback and the
1121      * Activity object when it is destroyed if you follow this pattern.
1122      *
1123      * <p class="note">Do not pass in an Activity that has already been through
1124      * {@link Activity#onDestroy}. This is guaranteed if you call this API
1125      * during {@link Activity#onCreate}.
1126      *
1127      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1128      *
1129      * @param callback callback, or null to disable
1130      * @param activity activity for which the NDEF message will be pushed
1131      * @param activities optional additional activities, however we strongly recommend
1132      *        to only register one at a time, and to do so in that activity's
1133      *        {@link Activity#onCreate}
1134      */
setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback, Activity activity, Activity ... activities)1135     public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
1136             Activity activity, Activity ... activities) {
1137         int targetSdkVersion = getSdkVersion();
1138         try {
1139             if (activity == null) {
1140                 throw new NullPointerException("activity cannot be null");
1141             }
1142             mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callback);
1143             for (Activity a : activities) {
1144                 if (a == null) {
1145                     throw new NullPointerException("activities cannot contain null");
1146                 }
1147                 mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback);
1148             }
1149         } catch (IllegalStateException e) {
1150             if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
1151                 // Less strict on old applications - just log the error
1152                 Log.e(TAG, "Cannot call API with Activity that has already " +
1153                         "been destroyed", e);
1154             } else {
1155                 // Prevent new applications from making this mistake, re-throw
1156                 throw(e);
1157             }
1158         }
1159     }
1160 
1161     /**
1162      * Enable foreground dispatch to the given Activity.
1163      *
1164      * <p>This will give give priority to the foreground activity when
1165      * dispatching a discovered {@link Tag} to an application.
1166      *
1167      * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents
1168      * for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and
1169      * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED}
1170      * relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled
1171      * by passing in the tech lists separately. Each first level entry in the tech list represents
1172      * an array of technologies that must all be present to match. If any of the first level sets
1173      * match then the dispatch is routed through the given PendingIntent. In other words, the second
1174      * level is ANDed together and the first level entries are ORed together.
1175      *
1176      * <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters
1177      * that acts a wild card and will cause the foreground activity to receive all tags via the
1178      * {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent.
1179      *
1180      * <p>This method must be called from the main thread, and only when the activity is in the
1181      * foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before
1182      * the completion of their {@link Activity#onPause} callback to disable foreground dispatch
1183      * after it has been enabled.
1184      *
1185      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1186      *
1187      * @param activity the Activity to dispatch to
1188      * @param intent the PendingIntent to start for the dispatch
1189      * @param filters the IntentFilters to override dispatching for, or null to always dispatch
1190      * @param techLists the tech lists used to perform matching for dispatching of the
1191      *      {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent
1192      * @throws IllegalStateException if the Activity is not currently in the foreground
1193      */
enableForegroundDispatch(Activity activity, PendingIntent intent, IntentFilter[] filters, String[][] techLists)1194     public void enableForegroundDispatch(Activity activity, PendingIntent intent,
1195             IntentFilter[] filters, String[][] techLists) {
1196         if (activity == null || intent == null) {
1197             throw new NullPointerException();
1198         }
1199         if (!activity.isResumed()) {
1200             throw new IllegalStateException("Foreground dispatch can only be enabled " +
1201                     "when your activity is resumed");
1202         }
1203         try {
1204             TechListParcel parcel = null;
1205             if (techLists != null && techLists.length > 0) {
1206                 parcel = new TechListParcel(techLists);
1207             }
1208             ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
1209                     mForegroundDispatchListener);
1210             sService.setForegroundDispatch(intent, filters, parcel);
1211         } catch (RemoteException e) {
1212             attemptDeadServiceRecovery(e);
1213         }
1214     }
1215 
1216     /**
1217      * Disable foreground dispatch to the given activity.
1218      *
1219      * <p>After calling {@link #enableForegroundDispatch}, an activity
1220      * must call this method before its {@link Activity#onPause} callback
1221      * completes.
1222      *
1223      * <p>This method must be called from the main thread.
1224      *
1225      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1226      *
1227      * @param activity the Activity to disable dispatch to
1228      * @throws IllegalStateException if the Activity has already been paused
1229      */
disableForegroundDispatch(Activity activity)1230     public void disableForegroundDispatch(Activity activity) {
1231         ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
1232                 mForegroundDispatchListener);
1233         disableForegroundDispatchInternal(activity, false);
1234     }
1235 
1236     OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() {
1237         @Override
1238         public void onPaused(Activity activity) {
1239             disableForegroundDispatchInternal(activity, true);
1240         }
1241     };
1242 
disableForegroundDispatchInternal(Activity activity, boolean force)1243     void disableForegroundDispatchInternal(Activity activity, boolean force) {
1244         try {
1245             sService.setForegroundDispatch(null, null, null);
1246             if (!force && !activity.isResumed()) {
1247                 throw new IllegalStateException("You must disable foreground dispatching " +
1248                         "while your activity is still resumed");
1249             }
1250         } catch (RemoteException e) {
1251             attemptDeadServiceRecovery(e);
1252         }
1253     }
1254 
1255     /**
1256      * Limit the NFC controller to reader mode while this Activity is in the foreground.
1257      *
1258      * <p>In this mode the NFC controller will only act as an NFC tag reader/writer,
1259      * thus disabling any peer-to-peer (Android Beam) and card-emulation modes of
1260      * the NFC adapter on this device.
1261      *
1262      * <p>Use {@link #FLAG_READER_SKIP_NDEF_CHECK} to prevent the platform from
1263      * performing any NDEF checks in reader mode. Note that this will prevent the
1264      * {@link Ndef} tag technology from being enumerated on the tag, and that
1265      * NDEF-based tag dispatch will not be functional.
1266      *
1267      * <p>For interacting with tags that are emulated on another Android device
1268      * using Android's host-based card-emulation, the recommended flags are
1269      * {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}.
1270      *
1271      * @param activity the Activity that requests the adapter to be in reader mode
1272      * @param callback the callback to be called when a tag is discovered
1273      * @param flags Flags indicating poll technologies and other optional parameters
1274      * @param extras Additional extras for configuring reader mode.
1275      */
enableReaderMode(Activity activity, ReaderCallback callback, int flags, Bundle extras)1276     public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
1277             Bundle extras) {
1278         mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
1279     }
1280 
1281     /**
1282      * Restore the NFC adapter to normal mode of operation: supporting
1283      * peer-to-peer (Android Beam), card emulation, and polling for
1284      * all supported tag technologies.
1285      *
1286      * @param activity the Activity that currently has reader mode enabled
1287      */
disableReaderMode(Activity activity)1288     public void disableReaderMode(Activity activity) {
1289         mNfcActivityManager.disableReaderMode(activity);
1290     }
1291 
1292     /**
1293      * Manually invoke Android Beam to share data.
1294      *
1295      * <p>The Android Beam animation is normally only shown when two NFC-capable
1296      * devices come into range.
1297      * By calling this method, an Activity can invoke the Beam animation directly
1298      * even if no other NFC device is in range yet. The Beam animation will then
1299      * prompt the user to tap another NFC-capable device to complete the data
1300      * transfer.
1301      *
1302      * <p>The main advantage of using this method is that it avoids the need for the
1303      * user to tap the screen to complete the transfer, as this method already
1304      * establishes the direction of the transfer and the consent of the user to
1305      * share data. Callers are responsible for making sure that the user has
1306      * consented to sharing data on NFC tap.
1307      *
1308      * <p>Note that to use this method, the passed in Activity must have already
1309      * set data to share over Beam by using method calls such as
1310      * {@link #setNdefPushMessageCallback} or
1311      * {@link #setBeamPushUrisCallback}.
1312      *
1313      * @param activity the current foreground Activity that has registered data to share
1314      * @return whether the Beam animation was successfully invoked
1315      */
invokeBeam(Activity activity)1316     public boolean invokeBeam(Activity activity) {
1317         if (activity == null) {
1318             throw new NullPointerException("activity may not be null.");
1319         }
1320         enforceResumed(activity);
1321         try {
1322             sService.invokeBeam();
1323             return true;
1324         } catch (RemoteException e) {
1325             Log.e(TAG, "invokeBeam: NFC process has died.");
1326             attemptDeadServiceRecovery(e);
1327             return false;
1328         }
1329     }
1330 
1331     /**
1332      * @hide
1333      */
invokeBeam(BeamShareData shareData)1334     public boolean invokeBeam(BeamShareData shareData) {
1335         try {
1336             Log.e(TAG, "invokeBeamInternal()");
1337             sService.invokeBeamInternal(shareData);
1338             return true;
1339         } catch (RemoteException e) {
1340             Log.e(TAG, "invokeBeam: NFC process has died.");
1341             attemptDeadServiceRecovery(e);
1342             return false;
1343         }
1344     }
1345 
1346     /**
1347      * Enable NDEF message push over NFC while this Activity is in the foreground.
1348      *
1349      * <p>You must explicitly call this method every time the activity is
1350      * resumed, and you must call {@link #disableForegroundNdefPush} before
1351      * your activity completes {@link Activity#onPause}.
1352      *
1353      * <p>Strongly recommend to use the new {@link #setNdefPushMessage}
1354      * instead: it automatically hooks into your activity life-cycle,
1355      * so you do not need to call enable/disable in your onResume/onPause.
1356      *
1357      * <p>For NDEF push to function properly the other NFC device must
1358      * support either NFC Forum's SNEP (Simple Ndef Exchange Protocol), or
1359      * Android's "com.android.npp" (Ndef Push Protocol). This was optional
1360      * on Gingerbread level Android NFC devices, but SNEP is mandatory on
1361      * Ice-Cream-Sandwich and beyond.
1362      *
1363      * <p>This method must be called from the main thread.
1364      *
1365      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1366      *
1367      * @param activity foreground activity
1368      * @param message a NDEF Message to push over NFC
1369      * @throws IllegalStateException if the activity is not currently in the foreground
1370      * @deprecated use {@link #setNdefPushMessage} instead
1371      */
1372     @Deprecated
enableForegroundNdefPush(Activity activity, NdefMessage message)1373     public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
1374         if (activity == null || message == null) {
1375             throw new NullPointerException();
1376         }
1377         enforceResumed(activity);
1378         mNfcActivityManager.setNdefPushMessage(activity, message, 0);
1379     }
1380 
1381     /**
1382      * Disable NDEF message push over P2P.
1383      *
1384      * <p>After calling {@link #enableForegroundNdefPush}, an activity
1385      * must call this method before its {@link Activity#onPause} callback
1386      * completes.
1387      *
1388      * <p>Strongly recommend to use the new {@link #setNdefPushMessage}
1389      * instead: it automatically hooks into your activity life-cycle,
1390      * so you do not need to call enable/disable in your onResume/onPause.
1391      *
1392      * <p>This method must be called from the main thread.
1393      *
1394      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1395      *
1396      * @param activity the Foreground activity
1397      * @throws IllegalStateException if the Activity has already been paused
1398      * @deprecated use {@link #setNdefPushMessage} instead
1399      */
1400     @Deprecated
disableForegroundNdefPush(Activity activity)1401     public void disableForegroundNdefPush(Activity activity) {
1402         if (activity == null) {
1403             throw new NullPointerException();
1404         }
1405         enforceResumed(activity);
1406         mNfcActivityManager.setNdefPushMessage(activity, null, 0);
1407         mNfcActivityManager.setNdefPushMessageCallback(activity, null, 0);
1408         mNfcActivityManager.setOnNdefPushCompleteCallback(activity, null);
1409     }
1410 
1411     /**
1412      * Enable NDEF Push feature.
1413      * <p>This API is for the Settings application.
1414      * @hide
1415      */
1416     @SystemApi
enableNdefPush()1417     public boolean enableNdefPush() {
1418         try {
1419             return sService.enableNdefPush();
1420         } catch (RemoteException e) {
1421             attemptDeadServiceRecovery(e);
1422             return false;
1423         }
1424     }
1425 
1426     /**
1427      * Disable NDEF Push feature.
1428      * <p>This API is for the Settings application.
1429      * @hide
1430      */
1431     @SystemApi
disableNdefPush()1432     public boolean disableNdefPush() {
1433         try {
1434             return sService.disableNdefPush();
1435         } catch (RemoteException e) {
1436             attemptDeadServiceRecovery(e);
1437             return false;
1438         }
1439     }
1440 
1441     /**
1442      * Return true if the NDEF Push (Android Beam) feature is enabled.
1443      * <p>This function will return true only if both NFC is enabled, and the
1444      * NDEF Push feature is enabled.
1445      * <p>Note that if NFC is enabled but NDEF Push is disabled then this
1446      * device can still <i>receive</i> NDEF messages, it just cannot send them.
1447      * <p>Applications cannot directly toggle the NDEF Push feature, but they
1448      * can request Settings UI allowing the user to toggle NDEF Push using
1449      * <code>startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS))</code>
1450      * <p>Example usage in an Activity that requires NDEF Push:
1451      * <p><pre>
1452      * protected void onResume() {
1453      *     super.onResume();
1454      *     if (!nfcAdapter.isEnabled()) {
1455      *         startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
1456      *     } else if (!nfcAdapter.isNdefPushEnabled()) {
1457      *         startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS));
1458      *     }
1459      * }</pre>
1460      *
1461      * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
1462      * @return true if NDEF Push feature is enabled
1463      */
isNdefPushEnabled()1464     public boolean isNdefPushEnabled() {
1465         try {
1466             return sService.isNdefPushEnabled();
1467         } catch (RemoteException e) {
1468             attemptDeadServiceRecovery(e);
1469             return false;
1470         }
1471     }
1472 
1473     /**
1474      * Inject a mock NFC tag.<p>
1475      * Used for testing purposes.
1476      * <p class="note">Requires the
1477      * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
1478      * @hide
1479      */
dispatch(Tag tag)1480     public void dispatch(Tag tag) {
1481         if (tag == null) {
1482             throw new NullPointerException("tag cannot be null");
1483         }
1484         try {
1485             sService.dispatch(tag);
1486         } catch (RemoteException e) {
1487             attemptDeadServiceRecovery(e);
1488         }
1489     }
1490 
1491     /**
1492      * @hide
1493      */
setP2pModes(int initiatorModes, int targetModes)1494     public void setP2pModes(int initiatorModes, int targetModes) {
1495         try {
1496             sService.setP2pModes(initiatorModes, targetModes);
1497         } catch (RemoteException e) {
1498             attemptDeadServiceRecovery(e);
1499         }
1500     }
1501 
1502     /**
1503      * Registers a new NFC unlock handler with the NFC service.
1504      *
1505      * <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted
1506      * NFC device. The handler should return true if it successfully authenticates the user and
1507      * unlocks the keyguard.
1508      *
1509      * <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for
1510      * at the lockscreen. Polling for less tag technologies reduces latency, and so it is
1511      * strongly recommended to only provide the Tag technologies that the handler is expected to
1512      * receive. There must be at least one tag technology provided, otherwise the unlock handler
1513      * is ignored.
1514      *
1515      * @hide
1516      */
1517     @SystemApi
addNfcUnlockHandler(final NfcUnlockHandler unlockHandler, String[] tagTechnologies)1518     public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
1519                                        String[] tagTechnologies) {
1520         // If there are no tag technologies, don't bother adding unlock handler
1521         if (tagTechnologies.length == 0) {
1522             return false;
1523         }
1524 
1525         try {
1526             synchronized (mLock) {
1527                 if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
1528                     // update the tag technologies
1529                     sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
1530                     mNfcUnlockHandlers.remove(unlockHandler);
1531                 }
1532 
1533                 INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
1534                     @Override
1535                     public boolean onUnlockAttempted(Tag tag) throws RemoteException {
1536                         return unlockHandler.onUnlockAttempted(tag);
1537                     }
1538                 };
1539 
1540                 sService.addNfcUnlockHandler(iHandler,
1541                         Tag.getTechCodesFromStrings(tagTechnologies));
1542                 mNfcUnlockHandlers.put(unlockHandler, iHandler);
1543             }
1544         } catch (RemoteException e) {
1545             attemptDeadServiceRecovery(e);
1546             return false;
1547         } catch (IllegalArgumentException e) {
1548             Log.e(TAG, "Unable to register LockscreenDispatch", e);
1549             return false;
1550         }
1551 
1552         return true;
1553     }
1554 
1555     /**
1556      * Removes a previously registered unlock handler. Also removes the tag technologies
1557      * associated with the removed unlock handler.
1558      *
1559      * @hide
1560      */
1561     @SystemApi
removeNfcUnlockHandler(NfcUnlockHandler unlockHandler)1562     public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) {
1563         try {
1564             synchronized (mLock) {
1565                 if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
1566                     sService.removeNfcUnlockHandler(mNfcUnlockHandlers.remove(unlockHandler));
1567                 }
1568 
1569                 return true;
1570             }
1571         } catch (RemoteException e) {
1572             attemptDeadServiceRecovery(e);
1573             return false;
1574         }
1575     }
1576 
1577     /**
1578      * @hide
1579      */
getNfcAdapterExtrasInterface()1580     public INfcAdapterExtras getNfcAdapterExtrasInterface() {
1581         if (mContext == null) {
1582             throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
1583                     + " NFC extras APIs");
1584         }
1585         try {
1586             return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
1587         } catch (RemoteException e) {
1588             attemptDeadServiceRecovery(e);
1589             return null;
1590         }
1591     }
1592 
enforceResumed(Activity activity)1593     void enforceResumed(Activity activity) {
1594         if (!activity.isResumed()) {
1595             throw new IllegalStateException("API cannot be called while activity is paused");
1596         }
1597     }
1598 
getSdkVersion()1599     int getSdkVersion() {
1600         if (mContext == null) {
1601             return android.os.Build.VERSION_CODES.GINGERBREAD; // best guess
1602         } else {
1603             return mContext.getApplicationInfo().targetSdkVersion;
1604         }
1605     }
1606 }
1607