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 android.Manifest;
20 import android.annotation.CallbackExecutor;
21 import android.annotation.FlaggedApi;
22 import android.annotation.IntDef;
23 import android.annotation.IntRange;
24 import android.annotation.NonNull;
25 import android.annotation.Nullable;
26 import android.annotation.RequiresPermission;
27 import android.annotation.SdkConstant;
28 import android.annotation.SdkConstant.SdkConstantType;
29 import android.annotation.SuppressLint;
30 import android.annotation.SystemApi;
31 import android.annotation.TestApi;
32 import android.annotation.UserIdInt;
33 import android.app.Activity;
34 import android.app.PendingIntent;
35 import android.compat.annotation.UnsupportedAppUsage;
36 import android.content.Context;
37 import android.content.IntentFilter;
38 import android.content.pm.PackageManager;
39 import android.content.pm.ResolveInfo;
40 import android.net.Uri;
41 import android.nfc.cardemulation.PollingFrame;
42 import android.nfc.tech.MifareClassic;
43 import android.nfc.tech.Ndef;
44 import android.nfc.tech.NfcA;
45 import android.nfc.tech.NfcF;
46 import android.os.Binder;
47 import android.os.Build;
48 import android.os.Bundle;
49 import android.os.Handler;
50 import android.os.IBinder;
51 import android.os.RemoteException;
52 import android.util.Log;
53 
54 import java.io.IOException;
55 import java.lang.annotation.Retention;
56 import java.lang.annotation.RetentionPolicy;
57 import java.util.ArrayList;
58 import java.util.Collections;
59 import java.util.HashMap;
60 import java.util.List;
61 import java.util.Map;
62 import java.util.Objects;
63 import java.util.concurrent.Executor;
64 
65 /**
66  * Represents the local NFC adapter.
67  * <p>
68  * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC
69  * adapter for this Android device.
70  *
71  * <div class="special reference">
72  * <h3>Developer Guides</h3>
73  * <p>For more information about using NFC, read the
74  * <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p>
75  * <p>To perform basic file sharing between devices, read
76  * <a href="{@docRoot}training/beam-files/index.html">Sharing Files with NFC</a>.
77  * </div>
78  */
79 public final class NfcAdapter {
80     static final String TAG = "NFC";
81 
82     private final NfcControllerAlwaysOnListener mControllerAlwaysOnListener;
83     private final NfcWlcStateListener mNfcWlcStateListener;
84     private final NfcVendorNciCallbackListener mNfcVendorNciCallbackListener;
85 
86     /**
87      * Intent to start an activity when a tag with NDEF payload is discovered.
88      *
89      * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and
90      * looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the
91      * intent will contain the URI in its data field. If a MIME record is found the intent will
92      * contain the MIME type in its type field. This allows activities to register
93      * {@link IntentFilter}s targeting specific content on tags. Activities should register the
94      * most specific intent filters possible to avoid the activity chooser dialog, which can
95      * disrupt the interaction with the tag as the user interacts with the screen.
96      *
97      * <p>If the tag has an NDEF payload this intent is started before
98      * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither
99      * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
100      *
101      * <p>The MIME type or data URI of this intent are normalized before dispatch -
102      * so that MIME, URI scheme and URI host are always lower-case.
103      */
104     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
105     public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
106 
107     /**
108      * Intent to start an activity when a tag is discovered and activities are registered for the
109      * specific technologies on the tag.
110      *
111      * <p>To receive this intent an activity must include an intent filter
112      * for this action and specify the desired tech types in a
113      * manifest <code>meta-data</code> entry. Here is an example manfiest entry:
114      * <pre>
115      * &lt;activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"&gt;
116      *     &lt;!-- Add a technology filter --&gt;
117      *     &lt;intent-filter&gt;
118      *         &lt;action android:name="android.nfc.action.TECH_DISCOVERED" /&gt;
119      *     &lt;/intent-filter&gt;
120      *
121      *     &lt;meta-data android:name="android.nfc.action.TECH_DISCOVERED"
122      *         android:resource="@xml/filter_nfc"
123      *     /&gt;
124      * &lt;/activity&gt;</pre>
125      *
126      * <p>The meta-data XML file should contain one or more <code>tech-list</code> entries
127      * each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer
128      * to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA".
129      *
130      * <p>A tag matches if any of the
131      * <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each
132      * of the <code>tech-list</code>s is considered independently and the
133      * activity is considered a match is any single <code>tech-list</code> matches the tag that was
134      * discovered. This provides AND and OR semantics for filtering desired techs. Here is an
135      * example that will match any tag using {@link NfcF} or any tag using {@link NfcA},
136      * {@link MifareClassic}, and {@link Ndef}:
137      *
138      * <pre>
139      * &lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
140      *     &lt;!-- capture anything using NfcF --&gt;
141      *     &lt;tech-list&gt;
142      *         &lt;tech&gt;android.nfc.tech.NfcF&lt;/tech&gt;
143      *     &lt;/tech-list&gt;
144      *
145      *     &lt;!-- OR --&gt;
146      *
147      *     &lt;!-- capture all MIFARE Classics with NDEF payloads --&gt;
148      *     &lt;tech-list&gt;
149      *         &lt;tech&gt;android.nfc.tech.NfcA&lt;/tech&gt;
150      *         &lt;tech&gt;android.nfc.tech.MifareClassic&lt;/tech&gt;
151      *         &lt;tech&gt;android.nfc.tech.Ndef&lt;/tech&gt;
152      *     &lt;/tech-list&gt;
153      * &lt;/resources&gt;</pre>
154      *
155      * <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before
156      * {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED}
157      * this intent will not be started. If any activities respond to this intent
158      * {@link #ACTION_TAG_DISCOVERED} will not be started.
159      */
160     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
161     public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
162 
163     /**
164      * Intent to start an activity when a tag is discovered.
165      *
166      * <p>This intent will not be started when a tag is discovered if any activities respond to
167      * {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag.
168      */
169     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
170     public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
171 
172     /**
173      * Broadcast Action: Intent to notify an application that a transaction event has occurred
174      * on the Secure Element.
175      *
176      * <p>This intent will only be sent if the application has requested permission for
177      * {@link android.Manifest.permission#NFC_TRANSACTION_EVENT} and if the application has the
178      * necessary access to Secure Element which witnessed the particular event.
179      */
180     @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT)
181     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
182     public static final String ACTION_TRANSACTION_DETECTED =
183             "android.nfc.action.TRANSACTION_DETECTED";
184 
185     /**
186      * Broadcast Action: Intent to notify if the preferred payment service changed.
187      *
188      * <p>This intent will only be sent to the application has requested permission for
189      * {@link android.Manifest.permission#NFC_PREFERRED_PAYMENT_INFO} and if the application
190      * has the necessary access to Secure Element which witnessed the particular event.
191      */
192     @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
193     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
194     public static final String ACTION_PREFERRED_PAYMENT_CHANGED =
195             "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
196 
197     /**
198      * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED
199      * @hide
200      */
201     public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST";
202 
203     /**
204      * Mandatory extra containing the {@link Tag} that was discovered for the
205      * {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
206      * {@link #ACTION_TAG_DISCOVERED} intents.
207      */
208     public static final String EXTRA_TAG = "android.nfc.extra.TAG";
209 
210     /**
211      * Extra containing an array of {@link NdefMessage} present on the discovered tag.<p>
212      * This extra is mandatory for {@link #ACTION_NDEF_DISCOVERED} intents,
213      * and optional for {@link #ACTION_TECH_DISCOVERED}, and
214      * {@link #ACTION_TAG_DISCOVERED} intents.<p>
215      * When this extra is present there will always be at least one
216      * {@link NdefMessage} element. Most NDEF tags have only one NDEF message,
217      * but we use an array for future compatibility.
218      */
219     public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
220 
221     /**
222      * Optional extra containing a byte array containing the ID of the discovered tag for
223      * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
224      * {@link #ACTION_TAG_DISCOVERED} intents.
225      */
226     public static final String EXTRA_ID = "android.nfc.extra.ID";
227 
228     /**
229      * Broadcast Action: The state of the local NFC adapter has been
230      * changed.
231      * <p>For example, NFC has been turned on or off.
232      * <p>Always contains the extra field {@link #EXTRA_ADAPTER_STATE}
233      */
234     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
235     public static final String ACTION_ADAPTER_STATE_CHANGED =
236             "android.nfc.action.ADAPTER_STATE_CHANGED";
237 
238     /**
239      * Used as an int extra field in {@link #ACTION_ADAPTER_STATE_CHANGED}
240      * intents to request the current power state. Possible values are:
241      * {@link #STATE_OFF},
242      * {@link #STATE_TURNING_ON},
243      * {@link #STATE_ON},
244      * {@link #STATE_TURNING_OFF},
245      */
246     public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
247 
248     /**
249      * Mandatory byte[] extra field in {@link #ACTION_TRANSACTION_DETECTED}
250      */
251     public static final String EXTRA_AID = "android.nfc.extra.AID";
252 
253     /**
254      * Optional byte[] extra field in {@link #ACTION_TRANSACTION_DETECTED}
255      */
256     public static final String EXTRA_DATA = "android.nfc.extra.DATA";
257 
258     /**
259      * Mandatory String extra field in {@link #ACTION_TRANSACTION_DETECTED}
260      * Indicates the Secure Element on which the transaction occurred.
261      * eSE1...eSEn for Embedded Secure Elements, SIM1...SIMn for UICC, etc.
262      */
263     public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
264 
265     /**
266      * Mandatory String extra field in {@link #ACTION_PREFERRED_PAYMENT_CHANGED}
267      * Indicates the condition when trigger this event. Possible values are:
268      * {@link #PREFERRED_PAYMENT_LOADED},
269      * {@link #PREFERRED_PAYMENT_CHANGED},
270      * {@link #PREFERRED_PAYMENT_UPDATED},
271      */
272     public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON =
273             "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON";
274     /**
275      * Nfc is enabled and the preferred payment aids are registered.
276      */
277     public static final int PREFERRED_PAYMENT_LOADED = 1;
278     /**
279      * User selected another payment application as the preferred payment.
280      */
281     public static final int PREFERRED_PAYMENT_CHANGED = 2;
282     /**
283      * Current preferred payment has issued an update (registered/unregistered new aids or has been
284      * updated itself).
285      */
286     public static final int PREFERRED_PAYMENT_UPDATED = 3;
287 
288     public static final int STATE_OFF = 1;
289     public static final int STATE_TURNING_ON = 2;
290     public static final int STATE_ON = 3;
291     public static final int STATE_TURNING_OFF = 4;
292 
293     /**
294      * Possible states from {@link #getAdapterState}.
295      *
296      * @hide
297      */
298     @IntDef(prefix = { "STATE_" }, value = {
299             STATE_OFF,
300             STATE_TURNING_ON,
301             STATE_ON,
302             STATE_TURNING_OFF
303     })
304     @Retention(RetentionPolicy.SOURCE)
305     public @interface AdapterState{}
306 
307     /**
308      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
309      * <p>
310      * Setting this flag enables polling for Nfc-A technology.
311      */
312     public static final int FLAG_READER_NFC_A = 0x1;
313 
314     /**
315      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
316      * <p>
317      * Setting this flag enables polling for Nfc-B technology.
318      */
319     public static final int FLAG_READER_NFC_B = 0x2;
320 
321     /**
322      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
323      * <p>
324      * Setting this flag enables polling for Nfc-F technology.
325      */
326     public static final int FLAG_READER_NFC_F = 0x4;
327 
328     /**
329      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
330      * <p>
331      * Setting this flag enables polling for Nfc-V (ISO15693) technology.
332      */
333     public static final int FLAG_READER_NFC_V = 0x8;
334 
335     /**
336      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
337      * <p>
338      * Setting this flag enables polling for NfcBarcode technology.
339      */
340     public static final int FLAG_READER_NFC_BARCODE = 0x10;
341 
342     /** @hide */
343     @IntDef(flag = true, value = {
344         FLAG_SET_DEFAULT_TECH,
345         FLAG_READER_KEEP,
346         FLAG_READER_DISABLE,
347         FLAG_READER_NFC_A,
348         FLAG_READER_NFC_B,
349         FLAG_READER_NFC_F,
350         FLAG_READER_NFC_V,
351         FLAG_READER_NFC_BARCODE
352     })
353     @Retention(RetentionPolicy.SOURCE)
354     public @interface PollTechnology {}
355 
356     /**
357      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
358      * <p>
359      * Setting this flag allows the caller to prevent the
360      * platform from performing an NDEF check on the tags it
361      * finds.
362      */
363     public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80;
364 
365     /**
366      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
367      * <p>
368      * Setting this flag allows the caller to prevent the
369      * platform from playing sounds when it discovers a tag.
370      */
371     public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100;
372 
373     /**
374      * Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
375      * <p>
376      * Setting this integer extra allows the calling application to specify
377      * the delay that the platform will use for performing presence checks
378      * on any discovered tag.
379      */
380     public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
381 
382     /**
383      * Flag for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
384      * <p>
385      * Setting this flag enables listening for Nfc-A technology.
386      */
387     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
388     public static final int FLAG_LISTEN_NFC_PASSIVE_A = 0x1;
389 
390     /**
391      * Flag for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
392      * <p>
393      * Setting this flag enables listening for Nfc-B technology.
394      */
395     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
396     public static final int FLAG_LISTEN_NFC_PASSIVE_B = 1 << 1;
397 
398     /**
399      * Flag for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
400      * <p>
401      * Setting this flag enables listening for Nfc-F technology.
402      */
403     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
404     public static final int FLAG_LISTEN_NFC_PASSIVE_F = 1 << 2;
405 
406     /**
407      * Flags for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
408      * <p>
409      * Setting this flag disables listening.
410      */
411     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
412     public static final int FLAG_LISTEN_DISABLE = 0x0;
413 
414     /**
415      * Flags for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
416      * <p>
417      * Setting this flag disables polling.
418      */
419     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
420     public static final int FLAG_READER_DISABLE = 0x0;
421 
422     /**
423      * Flags for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
424      * <p>
425      * Setting this flag makes listening to keep the current technology configuration.
426      */
427     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
428     public static final int FLAG_LISTEN_KEEP = 0x80000000;
429 
430     /**
431      * Flags for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
432      * <p>
433      * Setting this flag makes polling to keep the current technology configuration.
434      */
435     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
436     public static final int FLAG_READER_KEEP = 0x80000000;
437 
438     /** @hide */
439     public static final int FLAG_USE_ALL_TECH = 0xff;
440 
441     /** @hide */
442     @IntDef(flag = true, value = {
443         FLAG_SET_DEFAULT_TECH,
444         FLAG_LISTEN_KEEP,
445         FLAG_LISTEN_DISABLE,
446         FLAG_LISTEN_NFC_PASSIVE_A,
447         FLAG_LISTEN_NFC_PASSIVE_B,
448         FLAG_LISTEN_NFC_PASSIVE_F
449     })
450     @Retention(RetentionPolicy.SOURCE)
451     public @interface ListenTechnology {}
452 
453     /**
454      * Flag used in {@link #setDiscoveryTechnology(Activity, int, int)}.
455      * <p>
456      * Setting this flag changes the default listen or poll tech.
457      * Only available to privileged apps.
458      * @hide
459      */
460     @SystemApi
461     @FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH)
462     @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
463     public static final int FLAG_SET_DEFAULT_TECH = 0x40000000;
464 
465     /**
466      * @hide
467      * @removed
468      */
469     @SystemApi
470     @UnsupportedAppUsage
471     public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
472 
473     /** @hide */
474     public static final String ACTION_HANDOVER_TRANSFER_STARTED =
475             "android.nfc.action.HANDOVER_TRANSFER_STARTED";
476 
477     /** @hide */
478     public static final String ACTION_HANDOVER_TRANSFER_DONE =
479             "android.nfc.action.HANDOVER_TRANSFER_DONE";
480 
481     /** @hide */
482     public static final String EXTRA_HANDOVER_TRANSFER_STATUS =
483             "android.nfc.extra.HANDOVER_TRANSFER_STATUS";
484 
485     /** @hide */
486     public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
487     /** @hide */
488     public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
489 
490     /** @hide */
491     public static final String EXTRA_HANDOVER_TRANSFER_URI =
492             "android.nfc.extra.HANDOVER_TRANSFER_URI";
493 
494     /**
495      * Broadcast Action: Notify possible NFC transaction blocked because device is locked.
496      * <p>An external NFC field detected when device locked and SecureNfc enabled.
497      * @hide
498      */
499     @SystemApi
500     @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
501     public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC =
502             "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
503 
504     /**
505      * Intent action to start a NFC resolver activity in a customized share session with list of
506      * {@link ResolveInfo}.
507      * @hide
508      */
509     @SystemApi
510     @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
511     @RequiresPermission(Manifest.permission.SHOW_CUSTOMIZED_RESOLVER)
512     public static final String ACTION_SHOW_NFC_RESOLVER = "android.nfc.action.SHOW_NFC_RESOLVER";
513 
514     /**
515      * "Extras" key for an ArrayList of {@link ResolveInfo} records which are to be shown as the
516      * targets in the customized share session.
517      * @hide
518      */
519     @SystemApi
520     @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
521     public static final String EXTRA_RESOLVE_INFOS = "android.nfc.extra.RESOLVE_INFOS";
522 
523     /**
524      * The requested app is correctly added to the Tag intent app preference.
525      *
526      * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
527      * @hide
528      */
529     @SystemApi
530     public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0;
531 
532     /**
533      * The requested app is not installed on the device.
534      *
535      * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
536      * @hide
537      */
538     @SystemApi
539     public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1;
540 
541     /**
542      * The NfcService is not available.
543      *
544      * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
545      * @hide
546      */
547     @SystemApi
548     public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2;
549 
550     /**
551      * Possible response codes from {@link #setTagIntentAppPreferenceForUser}.
552      *
553      * @hide
554      */
555     @IntDef(prefix = { "TAG_INTENT_APP_PREF_RESULT" }, value = {
556             TAG_INTENT_APP_PREF_RESULT_SUCCESS,
557             TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND,
558             TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE})
559     @Retention(RetentionPolicy.SOURCE)
560     public @interface TagIntentAppPreferenceResult {}
561 
562     // Guarded by sLock
563     static boolean sIsInitialized = false;
564     static boolean sHasNfcFeature;
565     static boolean sHasCeFeature;
566     static boolean sHasNfcWlcFeature;
567 
568     static Object sLock = new Object();
569 
570     // Final after first constructor, except for
571     // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
572     // recovery
573     @UnsupportedAppUsage
574     static INfcAdapter sService;
575     static NfcServiceManager.ServiceRegisterer sServiceRegisterer;
576     static INfcTag sTagService;
577     static INfcCardEmulation sCardEmulationService;
578     static INfcFCardEmulation sNfcFCardEmulationService;
579 
580     /**
581      * The NfcAdapter object for each application context.
582      * There is a 1-1 relationship between application context and
583      * NfcAdapter object.
584      */
585     static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class
586 
587     /**
588      * NfcAdapter used with a null context. This ctor was deprecated but we have
589      * to support it for backwards compatibility. New methods that require context
590      * might throw when called on the null-context NfcAdapter.
591      */
592     static NfcAdapter sNullContextNfcAdapter;  // protected by NfcAdapter.class
593 
594     final NfcActivityManager mNfcActivityManager;
595     final Context mContext;
596     final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
597     final Object mLock;
598     final NfcOemExtension mNfcOemExtension;
599 
600     ITagRemovedCallback mTagRemovedListener; // protected by mLock
601 
602     /**
603      * A callback to be invoked when the system finds a tag while the foreground activity is
604      * operating in reader mode.
605      * <p>Register your {@code ReaderCallback} implementation with {@link
606      * NfcAdapter#enableReaderMode} and disable it with {@link
607      * NfcAdapter#disableReaderMode}.
608      * @see NfcAdapter#enableReaderMode
609      */
610     public interface ReaderCallback {
onTagDiscovered(Tag tag)611         public void onTagDiscovered(Tag tag);
612     }
613 
614     /**
615      * A listener to be invoked when NFC controller always on state changes.
616      * <p>Register your {@code ControllerAlwaysOnListener} implementation with {@link
617      * NfcAdapter#registerControllerAlwaysOnListener} and disable it with {@link
618      * NfcAdapter#unregisterControllerAlwaysOnListener}.
619      * @see #registerControllerAlwaysOnListener
620      * @hide
621      */
622     @SystemApi
623     public interface ControllerAlwaysOnListener {
624         /**
625          * Called on NFC controller always on state changes
626          */
onControllerAlwaysOnChanged(boolean isEnabled)627         void onControllerAlwaysOnChanged(boolean isEnabled);
628     }
629 
630     /**
631      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
632      * to another device.
633      * @deprecated this feature is removed. File sharing can work using other technology like
634      * Bluetooth.
635      */
636     @java.lang.Deprecated
637     public interface OnNdefPushCompleteCallback {
638         /**
639          * Called on successful NDEF push.
640          *
641          * <p>This callback is usually made on a binder thread (not the UI thread).
642          *
643          * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
644          */
onNdefPushComplete(NfcEvent event)645         public void onNdefPushComplete(NfcEvent event);
646     }
647 
648     /**
649      * A callback to be invoked when another NFC device capable of NDEF push (Android Beam)
650      * is within range.
651      * <p>Implement this interface and pass it to {@code
652      * NfcAdapter#setNdefPushMessageCallback setNdefPushMessageCallback()} in order to create an
653      * {@link NdefMessage} at the moment that another device is within range for NFC. Using this
654      * callback allows you to create a message with data that might vary based on the
655      * content currently visible to the user. Alternatively, you can call {@code
656      * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
657      * same data.
658      * @deprecated this feature is removed. File sharing can work using other technology like
659      * Bluetooth.
660      */
661     @java.lang.Deprecated
662     public interface CreateNdefMessageCallback {
663         /**
664          * Called to provide a {@link NdefMessage} to push.
665          *
666          * <p>This callback is usually made on a binder thread (not the UI thread).
667          *
668          * <p>Called when this device is in range of another device
669          * that might support NDEF push. It allows the application to
670          * create the NDEF message only when it is required.
671          *
672          * <p>NDEF push cannot occur until this method returns, so do not
673          * block for too long.
674          *
675          * <p>The Android operating system will usually show a system UI
676          * on top of your activity during this time, so do not try to request
677          * input from the user to complete the callback, or provide custom NDEF
678          * push UI. The user probably will not see it.
679          *
680          * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
681          * @return NDEF message to push, or null to not provide a message
682          */
createNdefMessage(NfcEvent event)683         public NdefMessage createNdefMessage(NfcEvent event);
684     }
685 
686 
687      /**
688      * @deprecated this feature is removed. File sharing can work using other technology like
689      * Bluetooth.
690      */
691     @java.lang.Deprecated
692     public interface CreateBeamUrisCallback {
createBeamUris(NfcEvent event)693         public Uri[] createBeamUris(NfcEvent event);
694     }
695 
696     /**
697      * A callback that is invoked when a tag is removed from the field.
698      * @see NfcAdapter#ignore
699      */
700     public interface OnTagRemovedListener {
onTagRemoved()701         void onTagRemoved();
702     }
703 
704     /**
705      * A callback to be invoked when an application has registered as a
706      * handler to unlock the device given an NFC tag at the lockscreen.
707      * @hide
708      */
709     @SystemApi
710     public interface NfcUnlockHandler {
711         /**
712          * Called at the lock screen to attempt to unlock the device with the given tag.
713          * @param tag the detected tag, to be used to unlock the device
714          * @return true if the device was successfully unlocked
715          */
onUnlockAttempted(Tag tag)716         public boolean onUnlockAttempted(Tag tag);
717     }
718 
719     /**
720      * Return list of Secure Elements which support off host card emulation.
721      *
722      * @return List<String> containing secure elements on the device which supports
723      *                      off host card emulation. eSE for Embedded secure element,
724      *                      SIM for UICC and so on.
725      * @hide
726      */
getSupportedOffHostSecureElements()727     public @NonNull List<String> getSupportedOffHostSecureElements() {
728         if (mContext == null) {
729             throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
730                     + " getSupportedOffHostSecureElements APIs");
731         }
732         List<String> offHostSE = new ArrayList<String>();
733         PackageManager pm = mContext.getPackageManager();
734         if (pm == null) {
735             Log.e(TAG, "Cannot get package manager, assuming no off-host CE feature");
736             return offHostSE;
737         }
738         if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)) {
739             offHostSE.add("SIM");
740         }
741         if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE)) {
742             offHostSE.add("eSE");
743         }
744         return offHostSE;
745     }
746 
retrieveServiceRegisterer()747     private static void retrieveServiceRegisterer() {
748         if (sServiceRegisterer == null) {
749             NfcServiceManager manager = NfcFrameworkInitializer.getNfcServiceManager();
750             if (manager == null) {
751                 Log.e(TAG, "NfcServiceManager is null");
752                 throw new UnsupportedOperationException();
753             }
754             sServiceRegisterer = manager.getNfcManagerServiceRegisterer();
755         }
756     }
757 
758     /**
759      * Returns the NfcAdapter for application context,
760      * or throws if NFC is not available.
761      * @hide
762      */
763     @UnsupportedAppUsage
getNfcAdapter(Context context)764     public static synchronized NfcAdapter getNfcAdapter(Context context) {
765         if (context == null) {
766             if (sNullContextNfcAdapter == null) {
767                 sNullContextNfcAdapter = new NfcAdapter(null);
768             }
769             return sNullContextNfcAdapter;
770         }
771         if (!sIsInitialized) {
772             PackageManager pm;
773             pm = context.getPackageManager();
774             sHasNfcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC);
775             sHasCeFeature =
776                     pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
777                     || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)
778                     || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)
779                     || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE);
780             sHasNfcWlcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC_CHARGING);
781             /* is this device meant to have NFC */
782             if (!sHasNfcFeature && !sHasCeFeature && !sHasNfcWlcFeature) {
783                 Log.v(TAG, "this device does not have NFC support");
784                 throw new UnsupportedOperationException();
785             }
786             retrieveServiceRegisterer();
787             sService = getServiceInterface();
788             if (sService == null) {
789                 Log.e(TAG, "could not retrieve NFC service");
790                 throw new UnsupportedOperationException();
791             }
792             if (sHasNfcFeature) {
793                 try {
794                     sTagService = sService.getNfcTagInterface();
795                 } catch (RemoteException e) {
796                     sTagService = null;
797                     Log.e(TAG, "could not retrieve NFC Tag service");
798                     throw new UnsupportedOperationException();
799                 }
800             }
801             if (sHasCeFeature) {
802                 try {
803                     sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
804                 } catch (RemoteException e) {
805                     sNfcFCardEmulationService = null;
806                     Log.e(TAG, "could not retrieve NFC-F card emulation service");
807                     throw new UnsupportedOperationException();
808                 }
809                 try {
810                     sCardEmulationService = sService.getNfcCardEmulationInterface();
811                 } catch (RemoteException e) {
812                     sCardEmulationService = null;
813                     Log.e(TAG, "could not retrieve card emulation service");
814                     throw new UnsupportedOperationException();
815                 }
816             }
817 
818             sIsInitialized = true;
819         }
820         NfcAdapter adapter = sNfcAdapters.get(context);
821         if (adapter == null) {
822             adapter = new NfcAdapter(context);
823             sNfcAdapters.put(context, adapter);
824         }
825         return adapter;
826     }
827 
828     /** get handle to NFC service interface */
getServiceInterface()829     private static INfcAdapter getServiceInterface() {
830         /* get a handle to NFC service */
831         IBinder b = sServiceRegisterer.get();
832         if (b == null) {
833             return null;
834         }
835         return INfcAdapter.Stub.asInterface(b);
836     }
837 
838     /**
839      * Helper to get the default NFC Adapter.
840      * <p>
841      * Most Android devices will only have one NFC Adapter (NFC Controller).
842      * <p>
843      * This helper is the equivalent of:
844      * <pre>
845      * NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
846      * NfcAdapter adapter = manager.getDefaultAdapter();</pre>
847      * @param context the calling application's context
848      *
849      * @return the default NFC adapter, or null if no NFC adapter exists
850      */
getDefaultAdapter(Context context)851     public static NfcAdapter getDefaultAdapter(Context context) {
852         if (context == null) {
853             throw new IllegalArgumentException("context cannot be null");
854         }
855         context = context.getApplicationContext();
856         if (context == null) {
857             throw new IllegalArgumentException(
858                     "context not associated with any application (using a mock context?)");
859         }
860         retrieveServiceRegisterer();
861         if (sServiceRegisterer.tryGet() == null) {
862             if (sIsInitialized) {
863                 synchronized (NfcAdapter.class) {
864                     /* Stale sService pointer */
865                     if (sIsInitialized) sIsInitialized = false;
866                 }
867             }
868             return null;
869         }
870         /* Try to initialize the service */
871         NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
872         if (manager == null) {
873             // NFC not available
874             return null;
875         }
876         return manager.getDefaultAdapter();
877     }
878 
879     /**
880      * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
881      * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
882      * for many NFC API methods. Those methods will fail when called on an NfcAdapter
883      * object created from this method.<p>
884      * @deprecated use {@link #getDefaultAdapter(Context)}
885      * @hide
886      */
887     @Deprecated
888     @UnsupportedAppUsage
getDefaultAdapter()889     public static NfcAdapter getDefaultAdapter() {
890         // introduced in API version 9 (GB 2.3)
891         // deprecated in API version 10 (GB 2.3.3)
892         // removed from public API in version 16 (ICS MR2)
893         // should maintain as a hidden API for binary compatibility for a little longer
894         Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
895                 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
896 
897         return NfcAdapter.getNfcAdapter(null);
898     }
899 
NfcAdapter(Context context)900     NfcAdapter(Context context) {
901         mContext = context;
902         mNfcActivityManager = new NfcActivityManager(this);
903         mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
904         mTagRemovedListener = null;
905         mLock = new Object();
906         mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService());
907         mNfcWlcStateListener = new NfcWlcStateListener(getService());
908         mNfcVendorNciCallbackListener = new NfcVendorNciCallbackListener(getService());
909         mNfcOemExtension = new NfcOemExtension(mContext, this);
910     }
911 
912     /**
913      * @hide
914      */
915     @UnsupportedAppUsage
getContext()916     public Context getContext() {
917         return mContext;
918     }
919 
920     /**
921      * Returns the binder interface to the service.
922      * @hide
923      */
924     @UnsupportedAppUsage
getService()925     public INfcAdapter getService() {
926         isEnabled();  // NOP call to recover sService if it is stale
927         return sService;
928     }
929 
930     /**
931      * Returns the binder interface to the tag service.
932      * @hide
933      */
getTagService()934     public INfcTag getTagService() {
935         isEnabled();  // NOP call to recover sTagService if it is stale
936         return sTagService;
937     }
938 
939     /**
940      * Returns the binder interface to the card emulation service.
941      * @hide
942      */
getCardEmulationService()943     public INfcCardEmulation getCardEmulationService() {
944         isEnabled();
945         return sCardEmulationService;
946     }
947 
948     /**
949      * Returns the binder interface to the NFC-F card emulation service.
950      * @hide
951      */
getNfcFCardEmulationService()952     public INfcFCardEmulation getNfcFCardEmulationService() {
953         isEnabled();
954         return sNfcFCardEmulationService;
955     }
956 
957     /**
958      * Returns the binder interface to the NFC-DTA test interface.
959      * @hide
960      */
getNfcDtaInterface()961     public INfcDta getNfcDtaInterface() {
962         if (mContext == null) {
963             throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
964                     + " NFC extras APIs");
965         }
966         try {
967             return sService.getNfcDtaInterface(mContext.getPackageName());
968         } catch (RemoteException e) {
969             attemptDeadServiceRecovery(e);
970             // Try one more time
971             if (sService == null) {
972                 Log.e(TAG, "Failed to recover NFC Service.");
973                 return null;
974             }
975             try {
976                 return sService.getNfcDtaInterface(mContext.getPackageName());
977             } catch (RemoteException ee) {
978                 Log.e(TAG, "Failed to recover NFC Service.");
979             }
980             return null;
981         }
982     }
983 
984     /**
985      * NFC service dead - attempt best effort recovery
986      * @hide
987      */
988     @UnsupportedAppUsage
attemptDeadServiceRecovery(Exception e)989     public void attemptDeadServiceRecovery(Exception e) {
990         Log.e(TAG, "NFC service dead - attempting to recover", e);
991         INfcAdapter service = getServiceInterface();
992         if (service == null) {
993             Log.e(TAG, "could not retrieve NFC service during service recovery");
994             // nothing more can be done now, sService is still stale, we'll hit
995             // this recovery path again later
996             return;
997         }
998         // assigning to sService is not thread-safe, but this is best-effort code
999         // and on a well-behaved system should never happen
1000         sService = service;
1001         if (sHasNfcFeature) {
1002             try {
1003                 sTagService = service.getNfcTagInterface();
1004             } catch (RemoteException ee) {
1005                 sTagService = null;
1006                 Log.e(TAG, "could not retrieve NFC tag service during service recovery");
1007                 // nothing more can be done now, sService is still stale, we'll hit
1008                 // this recovery path again later
1009                 return;
1010             }
1011         }
1012 
1013         if (sHasCeFeature) {
1014             try {
1015                 sCardEmulationService = service.getNfcCardEmulationInterface();
1016             } catch (RemoteException ee) {
1017                 sCardEmulationService = null;
1018                 Log.e(TAG,
1019                         "could not retrieve NFC card emulation service during service recovery");
1020             }
1021 
1022             try {
1023                 sNfcFCardEmulationService = service.getNfcFCardEmulationInterface();
1024             } catch (RemoteException ee) {
1025                 sNfcFCardEmulationService = null;
1026                 Log.e(TAG,
1027                         "could not retrieve NFC-F card emulation service during service recovery");
1028             }
1029         }
1030 
1031         return;
1032     }
1033 
isCardEmulationEnabled()1034     private boolean isCardEmulationEnabled() {
1035         if (sHasCeFeature) {
1036             return (sCardEmulationService != null || sNfcFCardEmulationService != null);
1037         }
1038         return false;
1039     }
1040 
isTagReadingEnabled()1041     private boolean isTagReadingEnabled() {
1042         if (sHasNfcFeature) {
1043             return sTagService != null;
1044         }
1045         return false;
1046     }
1047 
1048 
1049     /**
1050      * Return true if this NFC Adapter has any features enabled.
1051      *
1052      * <p>If this method returns false, the NFC hardware is guaranteed not to
1053      * generate or respond to any NFC communication over its NFC radio.
1054      * <p>Applications can use this to check if NFC is enabled. Applications
1055      * can request Settings UI allowing the user to toggle NFC using:
1056      * <p><pre>startActivity(new Intent(Settings.ACTION_NFC_SETTINGS))</pre>
1057      *
1058      * @see android.provider.Settings#ACTION_NFC_SETTINGS
1059      * @return true if this NFC Adapter has any features enabled
1060      */
isEnabled()1061     public boolean isEnabled() {
1062         boolean serviceState = false;
1063         try {
1064             serviceState = sService.getState() == STATE_ON;
1065         } catch (RemoteException e) {
1066             attemptDeadServiceRecovery(e);
1067             // Try one more time
1068             if (sService == null) {
1069                 Log.e(TAG, "Failed to recover NFC Service.");
1070                 return false;
1071             }
1072             try {
1073                 serviceState = sService.getState() == STATE_ON;
1074             } catch (RemoteException ee) {
1075                 Log.e(TAG, "Failed to recover NFC Service.");
1076             }
1077         }
1078         return serviceState
1079                 && (isTagReadingEnabled() || isCardEmulationEnabled() || sHasNfcWlcFeature);
1080     }
1081 
1082     /**
1083      * Return the state of this NFC Adapter.
1084      *
1085      * <p>Returns one of {@link #STATE_ON}, {@link #STATE_TURNING_ON},
1086      * {@link #STATE_OFF}, {@link #STATE_TURNING_OFF}.
1087      *
1088      * <p>{@link #isEnabled()} is equivalent to
1089      * <code>{@link #getAdapterState()} == {@link #STATE_ON}</code>
1090      *
1091      * @return the current state of this NFC adapter
1092      *
1093      * @hide
1094      */
1095     @SystemApi
1096     @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
getAdapterState()1097     public @AdapterState int getAdapterState() {
1098         try {
1099             return sService.getState();
1100         } catch (RemoteException e) {
1101             attemptDeadServiceRecovery(e);
1102             // Try one more time
1103             if (sService == null) {
1104                 Log.e(TAG, "Failed to recover NFC Service.");
1105                 return NfcAdapter.STATE_OFF;
1106             }
1107             try {
1108                 return sService.getState();
1109             } catch (RemoteException ee) {
1110                 Log.e(TAG, "Failed to recover NFC Service.");
1111             }
1112             return NfcAdapter.STATE_OFF;
1113         }
1114     }
1115 
1116     /**
1117      * Enable NFC hardware.
1118      *
1119      * <p>This call is asynchronous. Listen for
1120      * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
1121      * operation is complete.
1122      *
1123      * <p>This API is only allowed to be called by system apps
1124      * or apps which are Device Owner or Profile Owner.
1125      *
1126      * <p>If this returns true, then either NFC is already on, or
1127      * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
1128      * to indicate a state transition. If this returns false, then
1129      * there is some problem that prevents an attempt to turn
1130      * NFC on (for example we are in airplane mode and NFC is not
1131      * toggleable in airplane mode on this platform).
1132      *
1133      */
1134     @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE)
1135     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
enable()1136     public boolean enable() {
1137         try {
1138             return sService.enable(mContext.getPackageName());
1139         } catch (RemoteException e) {
1140             attemptDeadServiceRecovery(e);
1141             // Try one more time
1142             if (sService == null) {
1143                 Log.e(TAG, "Failed to recover NFC Service.");
1144                 return false;
1145             }
1146             try {
1147                 return sService.enable(mContext.getPackageName());
1148             } catch (RemoteException ee) {
1149                 Log.e(TAG, "Failed to recover NFC Service.");
1150             }
1151             return false;
1152         }
1153     }
1154 
1155     /**
1156      * Disable NFC hardware.
1157      *
1158      * <p>No NFC features will work after this call, and the hardware
1159      * will not perform or respond to any NFC communication.
1160      *
1161      * <p>This call is asynchronous. Listen for
1162      * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
1163      * operation is complete.
1164      *
1165      * <p>This API is only allowed to be called by system apps
1166      * or apps which are Device Owner or Profile Owner.
1167      *
1168      * <p>If this returns true, then either NFC is already off, or
1169      * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
1170      * to indicate a state transition. If this returns false, then
1171      * there is some problem that prevents an attempt to turn
1172      * NFC off.
1173      *
1174      */
1175     @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE)
1176     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
disable()1177     public boolean disable() {
1178         try {
1179             return sService.disable(true, mContext.getPackageName());
1180         } catch (RemoteException e) {
1181             attemptDeadServiceRecovery(e);
1182             // Try one more time
1183             if (sService == null) {
1184                 Log.e(TAG, "Failed to recover NFC Service.");
1185                 return false;
1186             }
1187             try {
1188                 return sService.disable(true, mContext.getPackageName());
1189             } catch (RemoteException ee) {
1190                 Log.e(TAG, "Failed to recover NFC Service.");
1191             }
1192             return false;
1193         }
1194     }
1195 
1196     /**
1197      * Disable NFC hardware.
1198      * @hide
1199     */
1200     @SystemApi
1201     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
disable(boolean persist)1202     public boolean disable(boolean persist) {
1203         try {
1204             return sService.disable(persist, mContext.getPackageName());
1205         } catch (RemoteException e) {
1206             attemptDeadServiceRecovery(e);
1207             // Try one more time
1208             if (sService == null) {
1209                 Log.e(TAG, "Failed to recover NFC Service.");
1210                 return false;
1211             }
1212             try {
1213                 return sService.disable(persist, mContext.getPackageName());
1214             } catch (RemoteException ee) {
1215                 Log.e(TAG, "Failed to recover NFC Service.");
1216             }
1217             return false;
1218         }
1219     }
1220 
1221     /**
1222      * Pauses polling for a {@code timeoutInMs} millis. If polling must be resumed before timeout,
1223      * use {@link #resumePolling()}.
1224      * @hide
1225      */
pausePolling(int timeoutInMs)1226     public void pausePolling(int timeoutInMs) {
1227         try {
1228             sService.pausePolling(timeoutInMs);
1229         } catch (RemoteException e) {
1230             attemptDeadServiceRecovery(e);
1231         }
1232     }
1233 
1234 
1235     /**
1236      * Returns whether the device supports observer mode or not. When observe
1237      * mode is enabled, the NFC hardware will listen for NFC readers, but not
1238      * respond to them. When observe mode is disabled, the NFC hardware will
1239      * resoond to the reader and proceed with the transaction.
1240      * @return true if the mode is supported, false otherwise.
1241      */
1242     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
isObserveModeSupported()1243     public boolean isObserveModeSupported() {
1244         try {
1245             return sService.isObserveModeSupported();
1246         } catch (RemoteException e) {
1247             attemptDeadServiceRecovery(e);
1248             return false;
1249         }
1250     }
1251 
1252     /**
1253      * Returns whether Observe Mode is currently enabled or not.
1254      *
1255      * @return true if observe mode is enabled, false otherwise.
1256      */
1257 
1258     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
isObserveModeEnabled()1259     public boolean isObserveModeEnabled() {
1260         try {
1261             return sService.isObserveModeEnabled();
1262         } catch (RemoteException e) {
1263             attemptDeadServiceRecovery(e);
1264             return false;
1265         }
1266     }
1267 
1268     /**
1269      * Controls whether the NFC adapter will allow transactions to proceed or be in observe mode
1270      * and simply observe and notify the APDU service of polling loop frames. See
1271      * {@link #isObserveModeSupported()} for a description of observe mode. Only the package of the
1272      * currently preferred service (the service set as preferred by the current foreground
1273      * application via {@link CardEmulation#setPreferredService(Activity, ComponentName)} or the
1274      * current Default Wallet Role Holder {@link android.app.role.RoleManager#ROLE_WALLET}),
1275      * otherwise a call to this method will fail and return false.
1276      *
1277      * @param enabled false disables observe mode to allow the transaction to proceed while true
1278      *                enables observe mode and does not allow transactions to proceed.
1279      *
1280      * @return boolean indicating success or failure.
1281      */
1282 
1283     @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
setObserveModeEnabled(boolean enabled)1284     public boolean setObserveModeEnabled(boolean enabled) {
1285         if (mContext == null) {
1286             throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
1287                     + " observe mode APIs");
1288         }
1289         try {
1290             return sService.setObserveMode(enabled, mContext.getPackageName());
1291         } catch (RemoteException e) {
1292             attemptDeadServiceRecovery(e);
1293             return false;
1294         }
1295     }
1296 
1297     /**
1298      * Resumes default polling for the current device state if polling is paused. Calling
1299      * this while polling is not paused is a no-op.
1300      *
1301      * @hide
1302      */
resumePolling()1303     public void resumePolling() {
1304         try {
1305             sService.resumePolling();
1306         } catch (RemoteException e) {
1307             attemptDeadServiceRecovery(e);
1308         }
1309     }
1310 
1311     /**
1312      * Set one or more {@link Uri}s to send using Android Beam (TM). Every
1313      * Uri you provide must have either scheme 'file' or scheme 'content'.
1314      *
1315      * <p>For the data provided through this method, Android Beam tries to
1316      * switch to alternate transports such as Bluetooth to achieve a fast
1317      * transfer speed. Hence this method is very suitable
1318      * for transferring large files such as pictures or songs.
1319      *
1320      * <p>The receiving side will store the content of each Uri in
1321      * a file and present a notification to the user to open the file
1322      * with a {@link android.content.Intent} with action
1323      * {@link android.content.Intent#ACTION_VIEW}.
1324      * If multiple URIs are sent, the {@link android.content.Intent} will refer
1325      * to the first of the stored files.
1326      *
1327      * <p>This method may be called at any time before {@link Activity#onDestroy},
1328      * but the URI(s) are only made available for Android Beam when the
1329      * specified activity(s) are in resumed (foreground) state. The recommended
1330      * approach is to call this method during your Activity's
1331      * {@link Activity#onCreate} - see sample
1332      * code below. This method does not immediately perform any I/O or blocking work,
1333      * so is safe to call on your main thread.
1334      *
1335      * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
1336      * have priority over both {@link #setNdefPushMessage} and
1337      * {@link #setNdefPushMessageCallback}.
1338      *
1339      * <p>If {@link #setBeamPushUris} is called with a null Uri array,
1340      * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
1341      * then the Uri push will be completely disabled for the specified activity(s).
1342      *
1343      * <p>Code example:
1344      * <pre>
1345      * protected void onCreate(Bundle savedInstanceState) {
1346      *     super.onCreate(savedInstanceState);
1347      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
1348      *     if (nfcAdapter == null) return;  // NFC not available on this device
1349      *     nfcAdapter.setBeamPushUris(new Uri[] {uri1, uri2}, this);
1350      * }</pre>
1351      * And that is it. Only one call per activity is necessary. The Android
1352      * OS will automatically release its references to the Uri(s) and the
1353      * Activity object when it is destroyed if you follow this pattern.
1354      *
1355      * <p>If your Activity wants to dynamically supply Uri(s),
1356      * then set a callback using {@link #setBeamPushUrisCallback} instead
1357      * of using this method.
1358      *
1359      * <p class="note">Do not pass in an Activity that has already been through
1360      * {@link Activity#onDestroy}. This is guaranteed if you call this API
1361      * during {@link Activity#onCreate}.
1362      *
1363      * <p class="note">If this device does not support alternate transports
1364      * such as Bluetooth or WiFI, calling this method does nothing.
1365      *
1366      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1367      *
1368      * @param uris an array of Uri(s) to push over Android Beam
1369      * @param activity activity for which the Uri(s) will be pushed
1370      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1371      * @removed this feature is removed. File sharing can work using other technology like
1372      * Bluetooth.
1373      */
1374     @java.lang.Deprecated
1375     @UnsupportedAppUsage
setBeamPushUris(Uri[] uris, Activity activity)1376     public void setBeamPushUris(Uri[] uris, Activity activity) {
1377         synchronized (sLock) {
1378             if (!sHasNfcFeature) {
1379                 throw new UnsupportedOperationException();
1380             }
1381         }
1382     }
1383 
1384     /**
1385      * Set a callback that will dynamically generate one or more {@link Uri}s
1386      * to send using Android Beam (TM). Every Uri the callback provides
1387      * must have either scheme 'file' or scheme 'content'.
1388      *
1389      * <p>For the data provided through this callback, Android Beam tries to
1390      * switch to alternate transports such as Bluetooth to achieve a fast
1391      * transfer speed. Hence this method is very suitable
1392      * for transferring large files such as pictures or songs.
1393      *
1394      * <p>The receiving side will store the content of each Uri in
1395      * a file and present a notification to the user to open the file
1396      * with a {@link android.content.Intent} with action
1397      * {@link android.content.Intent#ACTION_VIEW}.
1398      * If multiple URIs are sent, the {@link android.content.Intent} will refer
1399      * to the first of the stored files.
1400      *
1401      * <p>This method may be called at any time before {@link Activity#onDestroy},
1402      * but the URI(s) are only made available for Android Beam when the
1403      * specified activity(s) are in resumed (foreground) state. The recommended
1404      * approach is to call this method during your Activity's
1405      * {@link Activity#onCreate} - see sample
1406      * code below. This method does not immediately perform any I/O or blocking work,
1407      * so is safe to call on your main thread.
1408      *
1409      * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
1410      * have priority over both {@link #setNdefPushMessage} and
1411      * {@link #setNdefPushMessageCallback}.
1412      *
1413      * <p>If {@link #setBeamPushUris} is called with a null Uri array,
1414      * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
1415      * then the Uri push will be completely disabled for the specified activity(s).
1416      *
1417      * <p>Code example:
1418      * <pre>
1419      * protected void onCreate(Bundle savedInstanceState) {
1420      *     super.onCreate(savedInstanceState);
1421      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
1422      *     if (nfcAdapter == null) return;  // NFC not available on this device
1423      *     nfcAdapter.setBeamPushUrisCallback(callback, this);
1424      * }</pre>
1425      * And that is it. Only one call per activity is necessary. The Android
1426      * OS will automatically release its references to the Uri(s) and the
1427      * Activity object when it is destroyed if you follow this pattern.
1428      *
1429      * <p class="note">Do not pass in an Activity that has already been through
1430      * {@link Activity#onDestroy}. This is guaranteed if you call this API
1431      * during {@link Activity#onCreate}.
1432      *
1433      * <p class="note">If this device does not support alternate transports
1434      * such as Bluetooth or WiFI, calling this method does nothing.
1435      *
1436      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1437      *
1438      * @param callback callback, or null to disable
1439      * @param activity activity for which the Uri(s) will be pushed
1440      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1441      * @removed this feature is removed. File sharing can work using other technology like
1442      * Bluetooth.
1443      */
1444     @java.lang.Deprecated
1445     @UnsupportedAppUsage
setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity)1446     public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
1447         synchronized (sLock) {
1448             if (!sHasNfcFeature) {
1449                 throw new UnsupportedOperationException();
1450             }
1451         }
1452     }
1453 
1454     /**
1455      * Set a static {@link NdefMessage} to send using Android Beam (TM).
1456      *
1457      * <p>This method may be called at any time before {@link Activity#onDestroy},
1458      * but the NDEF message is only made available for NDEF push when the
1459      * specified activity(s) are in resumed (foreground) state. The recommended
1460      * approach is to call this method during your Activity's
1461      * {@link Activity#onCreate} - see sample
1462      * code below. This method does not immediately perform any I/O or blocking work,
1463      * so is safe to call on your main thread.
1464      *
1465      * <p>Only one NDEF message can be pushed by the currently resumed activity.
1466      * If both {@link #setNdefPushMessage} and
1467      * {@link #setNdefPushMessageCallback} are set, then
1468      * the callback will take priority.
1469      *
1470      * <p>If neither {@link #setNdefPushMessage} or
1471      * {@link #setNdefPushMessageCallback} have been called for your activity, then
1472      * the Android OS may choose to send a default NDEF message on your behalf,
1473      * such as a URI for your application.
1474      *
1475      * <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
1476      * and/or {@link #setNdefPushMessageCallback} is called with a null callback,
1477      * then NDEF push will be completely disabled for the specified activity(s).
1478      * This also disables any default NDEF message the Android OS would have
1479      * otherwise sent on your behalf for those activity(s).
1480      *
1481      * <p>If you want to prevent the Android OS from sending default NDEF
1482      * messages completely (for all activities), you can include a
1483      * {@code <meta-data>} element inside the {@code <application>}
1484      * element of your AndroidManifest.xml file, like this:
1485      * <pre>
1486      * &lt;application ...>
1487      *     &lt;meta-data android:name="android.nfc.disable_beam_default"
1488      *         android:value="true" />
1489      * &lt;/application></pre>
1490      *
1491      * <p>The API allows for multiple activities to be specified at a time,
1492      * but it is strongly recommended to just register one at a time,
1493      * and to do so during the activity's {@link Activity#onCreate}. For example:
1494      * <pre>
1495      * protected void onCreate(Bundle savedInstanceState) {
1496      *     super.onCreate(savedInstanceState);
1497      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
1498      *     if (nfcAdapter == null) return;  // NFC not available on this device
1499      *     nfcAdapter.setNdefPushMessage(ndefMessage, this);
1500      * }</pre>
1501      * And that is it. Only one call per activity is necessary. The Android
1502      * OS will automatically release its references to the NDEF message and the
1503      * Activity object when it is destroyed if you follow this pattern.
1504      *
1505      * <p>If your Activity wants to dynamically generate an NDEF message,
1506      * then set a callback using {@link #setNdefPushMessageCallback} instead
1507      * of a static message.
1508      *
1509      * <p class="note">Do not pass in an Activity that has already been through
1510      * {@link Activity#onDestroy}. This is guaranteed if you call this API
1511      * during {@link Activity#onCreate}.
1512      *
1513      * <p class="note">For sending large content such as pictures and songs,
1514      * consider using {@link #setBeamPushUris}, which switches to alternate transports
1515      * such as Bluetooth to achieve a fast transfer rate.
1516      *
1517      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1518      *
1519      * @param message NDEF message to push over NFC, or null to disable
1520      * @param activity activity for which the NDEF message will be pushed
1521      * @param activities optional additional activities, however we strongly recommend
1522      *        to only register one at a time, and to do so in that activity's
1523      *        {@link Activity#onCreate}
1524      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1525      * @removed this feature is removed. File sharing can work using other technology like
1526      * Bluetooth.
1527      */
1528     @java.lang.Deprecated
1529     @UnsupportedAppUsage
setNdefPushMessage(NdefMessage message, Activity activity, Activity ... activities)1530     public void setNdefPushMessage(NdefMessage message, Activity activity,
1531             Activity ... activities) {
1532         synchronized (sLock) {
1533             if (!sHasNfcFeature) {
1534                 throw new UnsupportedOperationException();
1535             }
1536         }
1537     }
1538 
1539     /**
1540      * @hide
1541      * @removed
1542      */
1543     @SystemApi
1544     @UnsupportedAppUsage
setNdefPushMessage(NdefMessage message, Activity activity, int flags)1545     public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
1546         synchronized (sLock) {
1547             if (!sHasNfcFeature) {
1548                 throw new UnsupportedOperationException();
1549             }
1550         }
1551     }
1552 
1553     /**
1554      * Set a callback that dynamically generates NDEF messages to send using Android Beam (TM).
1555      *
1556      * <p>This method may be called at any time before {@link Activity#onDestroy},
1557      * but the NDEF message callback can only occur when the
1558      * specified activity(s) are in resumed (foreground) state. The recommended
1559      * approach is to call this method during your Activity's
1560      * {@link Activity#onCreate} - see sample
1561      * code below. This method does not immediately perform any I/O or blocking work,
1562      * so is safe to call on your main thread.
1563      *
1564      * <p>Only one NDEF message can be pushed by the currently resumed activity.
1565      * If both {@link #setNdefPushMessage} and
1566      * {@link #setNdefPushMessageCallback} are set, then
1567      * the callback will take priority.
1568      *
1569      * <p>If neither {@link #setNdefPushMessage} or
1570      * {@link #setNdefPushMessageCallback} have been called for your activity, then
1571      * the Android OS may choose to send a default NDEF message on your behalf,
1572      * such as a URI for your application.
1573      *
1574      * <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
1575      * and/or {@link #setNdefPushMessageCallback} is called with a null callback,
1576      * then NDEF push will be completely disabled for the specified activity(s).
1577      * This also disables any default NDEF message the Android OS would have
1578      * otherwise sent on your behalf for those activity(s).
1579      *
1580      * <p>If you want to prevent the Android OS from sending default NDEF
1581      * messages completely (for all activities), you can include a
1582      * {@code <meta-data>} element inside the {@code <application>}
1583      * element of your AndroidManifest.xml file, like this:
1584      * <pre>
1585      * &lt;application ...>
1586      *     &lt;meta-data android:name="android.nfc.disable_beam_default"
1587      *         android:value="true" />
1588      * &lt;/application></pre>
1589      *
1590      * <p>The API allows for multiple activities to be specified at a time,
1591      * but it is strongly recommended to just register one at a time,
1592      * and to do so during the activity's {@link Activity#onCreate}. For example:
1593      * <pre>
1594      * protected void onCreate(Bundle savedInstanceState) {
1595      *     super.onCreate(savedInstanceState);
1596      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
1597      *     if (nfcAdapter == null) return;  // NFC not available on this device
1598      *     nfcAdapter.setNdefPushMessageCallback(callback, this);
1599      * }</pre>
1600      * And that is it. Only one call per activity is necessary. The Android
1601      * OS will automatically release its references to the callback and the
1602      * Activity object when it is destroyed if you follow this pattern.
1603      *
1604      * <p class="note">Do not pass in an Activity that has already been through
1605      * {@link Activity#onDestroy}. This is guaranteed if you call this API
1606      * during {@link Activity#onCreate}.
1607      * <p class="note">For sending large content such as pictures and songs,
1608      * consider using {@link #setBeamPushUris}, which switches to alternate transports
1609      * such as Bluetooth to achieve a fast transfer rate.
1610      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1611      *
1612      * @param callback callback, or null to disable
1613      * @param activity activity for which the NDEF message will be pushed
1614      * @param activities optional additional activities, however we strongly recommend
1615      *        to only register one at a time, and to do so in that activity's
1616      *        {@link Activity#onCreate}
1617      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1618      * @removed this feature is removed. File sharing can work using other technology like
1619      * Bluetooth.
1620      */
1621     @java.lang.Deprecated
1622     @UnsupportedAppUsage
setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity, Activity ... activities)1623     public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
1624             Activity ... activities) {
1625         synchronized (sLock) {
1626             if (!sHasNfcFeature) {
1627                 throw new UnsupportedOperationException();
1628             }
1629         }
1630     }
1631 
1632     /**
1633      * Set a callback on successful Android Beam (TM).
1634      *
1635      * <p>This method may be called at any time before {@link Activity#onDestroy},
1636      * but the callback can only occur when the
1637      * specified activity(s) are in resumed (foreground) state. The recommended
1638      * approach is to call this method during your Activity's
1639      * {@link Activity#onCreate} - see sample
1640      * code below. This method does not immediately perform any I/O or blocking work,
1641      * so is safe to call on your main thread.
1642      *
1643      * <p>The API allows for multiple activities to be specified at a time,
1644      * but it is strongly recommended to just register one at a time,
1645      * and to do so during the activity's {@link Activity#onCreate}. For example:
1646      * <pre>
1647      * protected void onCreate(Bundle savedInstanceState) {
1648      *     super.onCreate(savedInstanceState);
1649      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
1650      *     if (nfcAdapter == null) return;  // NFC not available on this device
1651      *     nfcAdapter.setOnNdefPushCompleteCallback(callback, this);
1652      * }</pre>
1653      * And that is it. Only one call per activity is necessary. The Android
1654      * OS will automatically release its references to the callback and the
1655      * Activity object when it is destroyed if you follow this pattern.
1656      *
1657      * <p class="note">Do not pass in an Activity that has already been through
1658      * {@link Activity#onDestroy}. This is guaranteed if you call this API
1659      * during {@link Activity#onCreate}.
1660      *
1661      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1662      *
1663      * @param callback callback, or null to disable
1664      * @param activity activity for which the NDEF message will be pushed
1665      * @param activities optional additional activities, however we strongly recommend
1666      *        to only register one at a time, and to do so in that activity's
1667      *        {@link Activity#onCreate}
1668      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1669      * @removed this feature is removed. File sharing can work using other technology like
1670      * Bluetooth.
1671      */
1672     @java.lang.Deprecated
1673     @UnsupportedAppUsage
setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback, Activity activity, Activity ... activities)1674     public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
1675             Activity activity, Activity ... activities) {
1676         synchronized (sLock) {
1677             if (!sHasNfcFeature) {
1678                 throw new UnsupportedOperationException();
1679             }
1680         }
1681     }
1682 
1683     /**
1684      * Enable foreground dispatch to the given Activity.
1685      *
1686      * <p>This will give priority to the foreground activity when
1687      * dispatching a discovered {@link Tag} to an application.
1688      *
1689      * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents
1690      * for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and
1691      * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED}
1692      * relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled
1693      * by passing in the tech lists separately. Each first level entry in the tech list represents
1694      * an array of technologies that must all be present to match. If any of the first level sets
1695      * match then the dispatch is routed through the given PendingIntent. In other words, the second
1696      * level is ANDed together and the first level entries are ORed together.
1697      *
1698      * <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters
1699      * that acts a wild card and will cause the foreground activity to receive all tags via the
1700      * {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent.
1701      *
1702      * <p>This method must be called from the main thread, and only when the activity is in the
1703      * foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before
1704      * the completion of their {@link Activity#onPause} callback to disable foreground dispatch
1705      * after it has been enabled.
1706      *
1707      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1708      *
1709      * @param activity the Activity to dispatch to
1710      * @param intent the PendingIntent to start for the dispatch
1711      * @param filters the IntentFilters to override dispatching for, or null to always dispatch
1712      * @param techLists the tech lists used to perform matching for dispatching of the
1713      *      {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent
1714      * @throws IllegalStateException if the Activity is not currently in the foreground
1715      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1716      */
enableForegroundDispatch(Activity activity, PendingIntent intent, IntentFilter[] filters, String[][] techLists)1717     public void enableForegroundDispatch(Activity activity, PendingIntent intent,
1718             IntentFilter[] filters, String[][] techLists) {
1719         synchronized (sLock) {
1720             if (!sHasNfcFeature) {
1721                 throw new UnsupportedOperationException();
1722             }
1723         }
1724         if (activity == null || intent == null) {
1725             throw new NullPointerException();
1726         }
1727         try {
1728             TechListParcel parcel = null;
1729             if (techLists != null && techLists.length > 0) {
1730                 parcel = new TechListParcel(techLists);
1731             }
1732             sService.setForegroundDispatch(intent, filters, parcel);
1733         } catch (RemoteException e) {
1734             attemptDeadServiceRecovery(e);
1735         }
1736     }
1737 
1738     /**
1739      * Disable foreground dispatch to the given activity.
1740      *
1741      * <p>After calling {@link #enableForegroundDispatch}, an activity
1742      * must call this method before its {@link Activity#onPause} callback
1743      * completes.
1744      *
1745      * <p>This method must be called from the main thread.
1746      *
1747      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
1748      *
1749      * @param activity the Activity to disable dispatch to
1750      * @throws IllegalStateException if the Activity has already been paused
1751      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1752      */
disableForegroundDispatch(Activity activity)1753     public void disableForegroundDispatch(Activity activity) {
1754         synchronized (sLock) {
1755             if (!sHasNfcFeature) {
1756                 throw new UnsupportedOperationException();
1757             }
1758         }
1759         try {
1760             sService.setForegroundDispatch(null, null, null);
1761         } catch (RemoteException e) {
1762             attemptDeadServiceRecovery(e);
1763         }
1764     }
1765 
1766     /**
1767      * Limit the NFC controller to reader mode while this Activity is in the foreground.
1768      *
1769      * <p>In this mode the NFC controller will only act as an NFC tag reader/writer,
1770      * thus disabling any peer-to-peer (Android Beam) and card-emulation modes of
1771      * the NFC adapter on this device.
1772      *
1773      * <p>Use {@link #FLAG_READER_SKIP_NDEF_CHECK} to prevent the platform from
1774      * performing any NDEF checks in reader mode. Note that this will prevent the
1775      * {@link Ndef} tag technology from being enumerated on the tag, and that
1776      * NDEF-based tag dispatch will not be functional.
1777      *
1778      * <p>For interacting with tags that are emulated on another Android device
1779      * using Android's host-based card-emulation, the recommended flags are
1780      * {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}.
1781      *
1782      * @param activity the Activity that requests the adapter to be in reader mode
1783      * @param callback the callback to be called when a tag is discovered
1784      * @param flags Flags indicating poll technologies and other optional parameters
1785      * @param extras Additional extras for configuring reader mode.
1786      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1787      */
enableReaderMode(Activity activity, ReaderCallback callback, int flags, Bundle extras)1788     public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
1789             Bundle extras) {
1790         synchronized (sLock) {
1791             if (!sHasNfcFeature) {
1792                 throw new UnsupportedOperationException();
1793             }
1794         }
1795         mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
1796     }
1797 
1798     /**
1799      * Restore the NFC adapter to normal mode of operation: supporting
1800      * peer-to-peer (Android Beam), card emulation, and polling for
1801      * all supported tag technologies.
1802      *
1803      * @param activity the Activity that currently has reader mode enabled
1804      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1805      */
disableReaderMode(Activity activity)1806     public void disableReaderMode(Activity activity) {
1807         synchronized (sLock) {
1808             if (!sHasNfcFeature) {
1809                 throw new UnsupportedOperationException();
1810             }
1811         }
1812         mNfcActivityManager.disableReaderMode(activity);
1813     }
1814 
1815     // Flags arguments to NFC adapter to enable/disable NFC
1816     private static final int DISABLE_POLLING_FLAGS = 0x1000;
1817     private static final int ENABLE_POLLING_FLAGS = 0x0000;
1818 
1819     /**
1820      * Privileged API to enable or disable reader polling.
1821      * Unlike {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}, this API does not
1822      * need a foreground activity to control reader mode parameters
1823      * Note: Use with caution! The app is responsible for ensuring that the polling state is
1824      * returned to normal.
1825      *
1826      * @see #enableReaderMode(Activity, ReaderCallback, int, Bundle)  for more detailed
1827      * documentation.
1828      *
1829      * @param enablePolling whether to enable or disable polling.
1830      * @hide
1831      */
1832     @SystemApi
1833     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
1834     @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
1835     @SuppressLint("VisiblySynchronized")
setReaderModePollingEnabled(boolean enable)1836     public void setReaderModePollingEnabled(boolean enable) {
1837         synchronized (sLock) {
1838             if (!sHasNfcFeature) {
1839                 throw new UnsupportedOperationException();
1840             }
1841         }
1842         Binder token = new Binder();
1843         int flags = enable ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS;
1844         try {
1845             NfcAdapter.sService.setReaderMode(token, null, flags, null);
1846         } catch (RemoteException e) {
1847             attemptDeadServiceRecovery(e);
1848         }
1849     }
1850 
1851     /**
1852      * Set the NFC controller to enable specific poll/listen technologies,
1853      * as specified in parameters, while this Activity is in the foreground.
1854      *
1855      * Use {@link #FLAG_READER_KEEP} to keep current polling technology.
1856      * Use {@link #FLAG_LISTEN_KEEP} to keep current listenig technology.
1857      * (if the _KEEP flag is specified the other technology flags shouldn't be set
1858      * and are quietly ignored otherwise).
1859      * Use {@link #FLAG_READER_DISABLE} to disable polling.
1860      * Use {@link #FLAG_LISTEN_DISABLE} to disable listening.
1861      * Also refer to {@link #resetDiscoveryTechnology(Activity)} to restore these changes.
1862      * </p>
1863      * The pollTechnology, listenTechnology parameters can be one or several of below list.
1864      * <pre>
1865      *                    Poll                    Listen
1866      *  Passive A         0x01   (NFC_A)           0x01  (NFC_PASSIVE_A)
1867      *  Passive B         0x02   (NFC_B)           0x02  (NFC_PASSIVE_B)
1868      *  Passive F         0x04   (NFC_F)           0x04  (NFC_PASSIVE_F)
1869      *  ISO 15693         0x08   (NFC_V)             -
1870      *  Kovio             0x10   (NFC_BARCODE)       -
1871      * </pre>
1872      * <p>Example usage in an Activity that requires to disable poll,
1873      * keep current listen technologies:
1874      * <pre>
1875      * protected void onResume() {
1876      *     mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
1877      *     mNfcAdapter.setDiscoveryTechnology(this,
1878      *         NfcAdapter.FLAG_READER_DISABLE, NfcAdapter.FLAG_LISTEN_KEEP);
1879      * }</pre></p>
1880      * @param activity The Activity that requests NFC controller to enable specific technologies.
1881      * @param pollTechnology Flags indicating poll technologies.
1882      * @param listenTechnology Flags indicating listen technologies.
1883      * @throws UnsupportedOperationException if FEATURE_NFC,
1884      * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF are unavailable.
1885      */
1886 
1887     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
setDiscoveryTechnology(@onNull Activity activity, @PollTechnology int pollTechnology, @ListenTechnology int listenTechnology)1888     public void setDiscoveryTechnology(@NonNull Activity activity,
1889             @PollTechnology int pollTechnology, @ListenTechnology int listenTechnology) {
1890 
1891         if (listenTechnology == FLAG_LISTEN_DISABLE) {
1892             synchronized (sLock) {
1893                 if (!sHasNfcFeature) {
1894                     throw new UnsupportedOperationException();
1895                 }
1896             }
1897         } else if (pollTechnology == FLAG_READER_DISABLE) {
1898             synchronized (sLock) {
1899                 if (!sHasCeFeature) {
1900                     throw new UnsupportedOperationException();
1901                 }
1902             }
1903         } else {
1904             synchronized (sLock) {
1905                 if (!sHasNfcFeature || !sHasCeFeature) {
1906                     throw new UnsupportedOperationException();
1907                 }
1908             }
1909         }
1910     /*
1911      * Privileged FLAG to set technology mask for all data processed by NFC controller
1912      * Note: Use with caution! The app is responsible for ensuring that the discovery
1913      * technology mask is returned to default.
1914      * Note: FLAG_USE_ALL_TECH used with _KEEP flags will reset the technolody to android default
1915      */
1916         if (Flags.nfcSetDefaultDiscTech()
1917                 && ((pollTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH
1918                 || (listenTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) {
1919             Binder token = new Binder();
1920             try {
1921                 NfcAdapter.sService.updateDiscoveryTechnology(token,
1922                         pollTechnology, listenTechnology);
1923             } catch (RemoteException e) {
1924                 attemptDeadServiceRecovery(e);
1925             }
1926         } else {
1927             mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology);
1928         }
1929     }
1930 
1931     /**
1932      * Restore the poll/listen technologies of NFC controller to its default state,
1933      * which were changed by {@link #setDiscoveryTechnology(Activity , int , int)}
1934      *
1935      * @param activity The Activity that requested to change technologies.
1936      */
1937 
1938     @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
resetDiscoveryTechnology(@onNull Activity activity)1939     public void resetDiscoveryTechnology(@NonNull Activity activity) {
1940         mNfcActivityManager.resetDiscoveryTech(activity);
1941     }
1942 
1943     /**
1944      * Manually invoke Android Beam to share data.
1945      *
1946      * <p>The Android Beam animation is normally only shown when two NFC-capable
1947      * devices come into range.
1948      * By calling this method, an Activity can invoke the Beam animation directly
1949      * even if no other NFC device is in range yet. The Beam animation will then
1950      * prompt the user to tap another NFC-capable device to complete the data
1951      * transfer.
1952      *
1953      * <p>The main advantage of using this method is that it avoids the need for the
1954      * user to tap the screen to complete the transfer, as this method already
1955      * establishes the direction of the transfer and the consent of the user to
1956      * share data. Callers are responsible for making sure that the user has
1957      * consented to sharing data on NFC tap.
1958      *
1959      * <p>Note that to use this method, the passed in Activity must have already
1960      * set data to share over Beam by using method calls such as
1961      * {@link #setNdefPushMessageCallback} or
1962      * {@link #setBeamPushUrisCallback}.
1963      *
1964      * @param activity the current foreground Activity that has registered data to share
1965      * @return whether the Beam animation was successfully invoked
1966      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
1967      * @removed this feature is removed. File sharing can work using other technology like
1968      * Bluetooth.
1969      */
1970     @java.lang.Deprecated
1971     @UnsupportedAppUsage
invokeBeam(Activity activity)1972     public boolean invokeBeam(Activity activity) {
1973         synchronized (sLock) {
1974             if (!sHasNfcFeature) {
1975                 throw new UnsupportedOperationException();
1976             }
1977         }
1978         return false;
1979     }
1980 
1981     /**
1982      * Enable NDEF message push over NFC while this Activity is in the foreground.
1983      *
1984      * <p>You must explicitly call this method every time the activity is
1985      * resumed, and you must call {@link #disableForegroundNdefPush} before
1986      * your activity completes {@link Activity#onPause}.
1987      *
1988      * <p>Strongly recommend to use the new {@link #setNdefPushMessage}
1989      * instead: it automatically hooks into your activity life-cycle,
1990      * so you do not need to call enable/disable in your onResume/onPause.
1991      *
1992      * <p>For NDEF push to function properly the other NFC device must
1993      * support either NFC Forum's SNEP (Simple Ndef Exchange Protocol), or
1994      * Android's "com.android.npp" (Ndef Push Protocol). This was optional
1995      * on Gingerbread level Android NFC devices, but SNEP is mandatory on
1996      * Ice-Cream-Sandwich and beyond.
1997      *
1998      * <p>This method must be called from the main thread.
1999      *
2000      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
2001      *
2002      * @param activity foreground activity
2003      * @param message a NDEF Message to push over NFC
2004      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
2005      * @removed this feature is removed. File sharing can work using other technology like
2006      * Bluetooth.
2007      */
2008     @Deprecated
2009     @UnsupportedAppUsage
enableForegroundNdefPush(Activity activity, NdefMessage message)2010     public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
2011         synchronized (sLock) {
2012             if (!sHasNfcFeature) {
2013                 throw new UnsupportedOperationException();
2014             }
2015         }
2016     }
2017 
2018     /**
2019      * Disable NDEF message push over P2P.
2020      *
2021      * <p>After calling {@link #enableForegroundNdefPush}, an activity
2022      * must call this method before its {@link Activity#onPause} callback
2023      * completes.
2024      *
2025      * <p>Strongly recommend to use the new {@link #setNdefPushMessage}
2026      * instead: it automatically hooks into your activity life-cycle,
2027      * so you do not need to call enable/disable in your onResume/onPause.
2028      *
2029      * <p>This method must be called from the main thread.
2030      *
2031      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
2032      *
2033      * @param activity the Foreground activity
2034      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
2035      * @removed this feature is removed. File sharing can work using other technology like
2036      * Bluetooth.
2037      */
2038     @Deprecated
2039     @UnsupportedAppUsage
disableForegroundNdefPush(Activity activity)2040     public void disableForegroundNdefPush(Activity activity) {
2041         synchronized (sLock) {
2042             if (!sHasNfcFeature) {
2043                 throw new UnsupportedOperationException();
2044             }
2045         }
2046     }
2047 
2048     /**
2049      * Sets Secure NFC feature.
2050      * <p>This API is for the Settings application.
2051      * @return True if successful
2052      * @hide
2053      */
2054     @SystemApi
2055     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
enableSecureNfc(boolean enable)2056     public boolean enableSecureNfc(boolean enable) {
2057         if (!sHasNfcFeature && !sHasCeFeature) {
2058             throw new UnsupportedOperationException();
2059         }
2060         try {
2061             return sService.setNfcSecure(enable);
2062         } catch (RemoteException e) {
2063             attemptDeadServiceRecovery(e);
2064             // Try one more time
2065             if (sService == null) {
2066                 Log.e(TAG, "Failed to recover NFC Service.");
2067                 return false;
2068             }
2069             try {
2070                 return sService.setNfcSecure(enable);
2071             } catch (RemoteException ee) {
2072                 Log.e(TAG, "Failed to recover NFC Service.");
2073             }
2074             return false;
2075         }
2076     }
2077 
2078     /**
2079      * Checks if the device supports Secure NFC functionality.
2080      *
2081      * @return True if device supports Secure NFC, false otherwise
2082      * @throws UnsupportedOperationException if FEATURE_NFC,
2083      * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
2084      * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
2085      * are unavailable
2086      */
isSecureNfcSupported()2087     public boolean isSecureNfcSupported() {
2088         if (!sHasNfcFeature && !sHasCeFeature) {
2089             throw new UnsupportedOperationException();
2090         }
2091         try {
2092             return sService.deviceSupportsNfcSecure();
2093         } catch (RemoteException e) {
2094             attemptDeadServiceRecovery(e);
2095             // Try one more time
2096             if (sService == null) {
2097                 Log.e(TAG, "Failed to recover NFC Service.");
2098                 return false;
2099             }
2100             try {
2101                 return sService.deviceSupportsNfcSecure();
2102             } catch (RemoteException ee) {
2103                 Log.e(TAG, "Failed to recover NFC Service.");
2104             }
2105             return false;
2106         }
2107     }
2108 
2109     /**
2110      * Returns information regarding Nfc antennas on the device
2111      * such as their relative positioning on the device.
2112      *
2113      * @return Information on the nfc antenna(s) on the device.
2114      * @throws UnsupportedOperationException if FEATURE_NFC,
2115      * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
2116      * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
2117      * are unavailable
2118      */
2119     @Nullable
getNfcAntennaInfo()2120     public NfcAntennaInfo getNfcAntennaInfo() {
2121         if (!sHasNfcFeature && !sHasCeFeature) {
2122             throw new UnsupportedOperationException();
2123         }
2124         try {
2125             return sService.getNfcAntennaInfo();
2126         } catch (RemoteException e) {
2127             attemptDeadServiceRecovery(e);
2128             // Try one more time
2129             if (sService == null) {
2130                 Log.e(TAG, "Failed to recover NFC Service.");
2131                 return null;
2132             }
2133             try {
2134                 return sService.getNfcAntennaInfo();
2135             } catch (RemoteException ee) {
2136                 Log.e(TAG, "Failed to recover NFC Service.");
2137             }
2138             return null;
2139         }
2140     }
2141 
2142     /**
2143      * Checks Secure NFC feature is enabled.
2144      *
2145      * @return True if Secure NFC is enabled, false otherwise
2146      * @throws UnsupportedOperationException if FEATURE_NFC,
2147      * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
2148      * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
2149      * are unavailable
2150      * @throws UnsupportedOperationException if device doesn't support
2151      *         Secure NFC functionality. {@link #isSecureNfcSupported}
2152      */
isSecureNfcEnabled()2153     public boolean isSecureNfcEnabled() {
2154         if (!sHasNfcFeature && !sHasCeFeature) {
2155             throw new UnsupportedOperationException();
2156         }
2157         try {
2158             return sService.isNfcSecureEnabled();
2159         } catch (RemoteException e) {
2160             attemptDeadServiceRecovery(e);
2161             // Try one more time
2162             if (sService == null) {
2163                 Log.e(TAG, "Failed to recover NFC Service.");
2164                 return false;
2165             }
2166             try {
2167                 return sService.isNfcSecureEnabled();
2168             } catch (RemoteException ee) {
2169                 Log.e(TAG, "Failed to recover NFC Service.");
2170             }
2171             return false;
2172         }
2173     }
2174 
2175     /**
2176      * Sets NFC Reader option feature.
2177      * <p>This API is for the Settings application.
2178      * @return True if successful
2179      * @hide
2180      */
2181     @SystemApi
2182     @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
2183     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
enableReaderOption(boolean enable)2184     public boolean enableReaderOption(boolean enable) {
2185         if (!sHasNfcFeature) {
2186             throw new UnsupportedOperationException();
2187         }
2188         try {
2189             return sService.enableReaderOption(enable);
2190         } catch (RemoteException e) {
2191             attemptDeadServiceRecovery(e);
2192             // Try one more time
2193             if (sService == null) {
2194                 Log.e(TAG, "Failed to recover NFC Service.");
2195                 return false;
2196             }
2197             try {
2198                 return sService.enableReaderOption(enable);
2199             } catch (RemoteException ee) {
2200                 Log.e(TAG, "Failed to recover NFC Service.");
2201             }
2202             return false;
2203         }
2204     }
2205 
2206     /**
2207      * Checks if the device supports NFC Reader option functionality.
2208      *
2209      * @return True if device supports NFC Reader option, false otherwise
2210      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
2211      */
2212     @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
isReaderOptionSupported()2213     public boolean isReaderOptionSupported() {
2214         if (!sHasNfcFeature) {
2215             throw new UnsupportedOperationException();
2216         }
2217         try {
2218             return sService.isReaderOptionSupported();
2219         } catch (RemoteException e) {
2220             attemptDeadServiceRecovery(e);
2221             // Try one more time
2222             if (sService == null) {
2223                 Log.e(TAG, "Failed to recover NFC Service.");
2224                 return false;
2225             }
2226             try {
2227                 return sService.isReaderOptionSupported();
2228             } catch (RemoteException ee) {
2229                 Log.e(TAG, "Failed to recover NFC Service.");
2230             }
2231             return false;
2232         }
2233     }
2234 
2235     /**
2236      * Checks NFC Reader option feature is enabled.
2237      *
2238      * @return True if NFC Reader option  is enabled, false otherwise
2239      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
2240      * @throws UnsupportedOperationException if device doesn't support
2241      *         NFC Reader option functionality. {@link #isReaderOptionSupported}
2242      */
2243     @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
isReaderOptionEnabled()2244     public boolean isReaderOptionEnabled() {
2245         if (!sHasNfcFeature) {
2246             throw new UnsupportedOperationException();
2247         }
2248         try {
2249             return sService.isReaderOptionEnabled();
2250         } catch (RemoteException e) {
2251             attemptDeadServiceRecovery(e);
2252             // Try one more time
2253             if (sService == null) {
2254                 Log.e(TAG, "Failed to recover NFC Service.");
2255                 return false;
2256             }
2257             try {
2258                 return sService.isReaderOptionEnabled();
2259             } catch (RemoteException ee) {
2260                 Log.e(TAG, "Failed to recover NFC Service.");
2261             }
2262             return false;
2263         }
2264     }
2265 
2266     /**
2267      * Enable NDEF Push feature.
2268      * <p>This API is for the Settings application.
2269      * @hide
2270      * @removed
2271      */
2272     @SystemApi
2273     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
2274     @UnsupportedAppUsage
enableNdefPush()2275     public boolean enableNdefPush() {
2276         return false;
2277     }
2278 
2279     /**
2280      * Disable NDEF Push feature.
2281      * <p>This API is for the Settings application.
2282      * @hide
2283      * @removed
2284      */
2285     @SystemApi
2286     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
2287     @UnsupportedAppUsage
disableNdefPush()2288     public boolean disableNdefPush() {
2289         return false;
2290     }
2291 
2292     /**
2293      * Return true if the NDEF Push (Android Beam) feature is enabled.
2294      * <p>This function will return true only if both NFC is enabled, and the
2295      * NDEF Push feature is enabled.
2296      * <p>Note that if NFC is enabled but NDEF Push is disabled then this
2297      * device can still <i>receive</i> NDEF messages, it just cannot send them.
2298      * <p>Applications cannot directly toggle the NDEF Push feature, but they
2299      * can request Settings UI allowing the user to toggle NDEF Push using
2300      * <code>startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS))</code>
2301      * <p>Example usage in an Activity that requires NDEF Push:
2302      * <p><pre>
2303      * protected void onResume() {
2304      *     super.onResume();
2305      *     if (!nfcAdapter.isEnabled()) {
2306      *         startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
2307      *     } else if (!nfcAdapter.isNdefPushEnabled()) {
2308      *         startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS));
2309      *     }
2310      * }</pre>
2311      *
2312      * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
2313      * @return true if NDEF Push feature is enabled
2314      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
2315      * @removed this feature is removed. File sharing can work using other technology like
2316      * Bluetooth.
2317      */
2318     @java.lang.Deprecated
2319     @UnsupportedAppUsage
isNdefPushEnabled()2320     public boolean isNdefPushEnabled() {
2321         synchronized (sLock) {
2322             if (!sHasNfcFeature) {
2323                 throw new UnsupportedOperationException();
2324             }
2325         }
2326         return false;
2327     }
2328 
2329     /**
2330      * Signals that you are no longer interested in communicating with an NFC tag
2331      * for as long as it remains in range.
2332      *
2333      * All future attempted communication to this tag will fail with {@link IOException}.
2334      * The NFC controller will be put in a low-power polling mode, allowing the device
2335      * to save power in cases where it's "attached" to a tag all the time (e.g. a tag in
2336      * car dock).
2337      *
2338      * Additionally the debounceMs parameter allows you to specify for how long the tag needs
2339      * to have gone out of range, before it will be dispatched again.
2340      *
2341      * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms).
2342      * This means that if the tag repeatedly goes in and out of range (for example, in
2343      * case of a flaky connection), and the controller happens to poll every time the
2344      * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag
2345      * having been "in range" during the interval.
2346      *
2347      * Note 2: if a tag with another UID is detected after this API is called, its effect
2348      * will be cancelled; if this tag shows up before the amount of time specified in
2349      * debounceMs, it will be dispatched again.
2350      *
2351      * Note 3: some tags have a random UID, in which case this API won't work reliably.
2352      *
2353      * @param tag        the {@link android.nfc.Tag Tag} to ignore.
2354      * @param debounceMs minimum amount of time the tag needs to be out of range before being
2355      *                   dispatched again.
2356      * @param tagRemovedListener listener to be called when the tag is removed from the field.
2357      *                           Note that this will only be called if the tag has been out of range
2358      *                           for at least debounceMs, or if another tag came into range before
2359      *                           debounceMs. May be null in case you don't want a callback.
2360      * @param handler the {@link android.os.Handler Handler} that will be used for delivering
2361      *                the callback. if the handler is null, then the thread used for delivering
2362      *                the callback is unspecified.
2363      * @return false if the tag couldn't be found (or has already gone out of range), true otherwise
2364      */
ignore(final Tag tag, int debounceMs, final OnTagRemovedListener tagRemovedListener, final Handler handler)2365     public boolean ignore(final Tag tag, int debounceMs,
2366                           final OnTagRemovedListener tagRemovedListener, final Handler handler) {
2367         ITagRemovedCallback.Stub iListener = null;
2368         if (tagRemovedListener != null) {
2369             iListener = new ITagRemovedCallback.Stub() {
2370                 @Override
2371                 public void onTagRemoved() throws RemoteException {
2372                     if (handler != null) {
2373                         handler.post(new Runnable() {
2374                             @Override
2375                             public void run() {
2376                                 tagRemovedListener.onTagRemoved();
2377                             }
2378                         });
2379                     } else {
2380                         tagRemovedListener.onTagRemoved();
2381                     }
2382                     synchronized (mLock) {
2383                         mTagRemovedListener = null;
2384                     }
2385                 }
2386             };
2387         }
2388         synchronized (mLock) {
2389             mTagRemovedListener = iListener;
2390         }
2391         try {
2392             return sService.ignore(tag.getServiceHandle(), debounceMs, iListener);
2393         } catch (RemoteException e) {
2394             return false;
2395         }
2396     }
2397 
2398     /**
2399      * Inject a mock NFC tag.<p>
2400      * Used for testing purposes.
2401      * <p class="note">Requires the
2402      * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
2403      * @hide
2404      */
dispatch(Tag tag)2405     public void dispatch(Tag tag) {
2406         if (tag == null) {
2407             throw new NullPointerException("tag cannot be null");
2408         }
2409         try {
2410             sService.dispatch(tag);
2411         } catch (RemoteException e) {
2412             attemptDeadServiceRecovery(e);
2413         }
2414     }
2415 
2416     /**
2417      * Registers a new NFC unlock handler with the NFC service.
2418      *
2419      * <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted
2420      * NFC device. The handler should return true if it successfully authenticates the user and
2421      * unlocks the keyguard.
2422      *
2423      * <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for
2424      * at the lockscreen. Polling for less tag technologies reduces latency, and so it is
2425      * strongly recommended to only provide the Tag technologies that the handler is expected to
2426      * receive. There must be at least one tag technology provided, otherwise the unlock handler
2427      * is ignored.
2428      *
2429      * @hide
2430      */
2431     @SystemApi
2432     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
addNfcUnlockHandler(final NfcUnlockHandler unlockHandler, String[] tagTechnologies)2433     public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
2434                                        String[] tagTechnologies) {
2435         synchronized (sLock) {
2436             if (!sHasNfcFeature) {
2437                 throw new UnsupportedOperationException();
2438             }
2439         }
2440         // If there are no tag technologies, don't bother adding unlock handler
2441         if (tagTechnologies.length == 0) {
2442             return false;
2443         }
2444 
2445         try {
2446             synchronized (mLock) {
2447                 if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
2448                     // update the tag technologies
2449                     sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
2450                     mNfcUnlockHandlers.remove(unlockHandler);
2451                 }
2452 
2453                 INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
2454                     @Override
2455                     public boolean onUnlockAttempted(Tag tag) throws RemoteException {
2456                         return unlockHandler.onUnlockAttempted(tag);
2457                     }
2458                 };
2459 
2460                 sService.addNfcUnlockHandler(iHandler,
2461                         Tag.getTechCodesFromStrings(tagTechnologies));
2462                 mNfcUnlockHandlers.put(unlockHandler, iHandler);
2463             }
2464         } catch (RemoteException e) {
2465             attemptDeadServiceRecovery(e);
2466             return false;
2467         } catch (IllegalArgumentException e) {
2468             Log.e(TAG, "Unable to register LockscreenDispatch", e);
2469             return false;
2470         }
2471 
2472         return true;
2473     }
2474 
2475     /**
2476      * Removes a previously registered unlock handler. Also removes the tag technologies
2477      * associated with the removed unlock handler.
2478      *
2479      * @hide
2480      */
2481     @SystemApi
2482     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
removeNfcUnlockHandler(NfcUnlockHandler unlockHandler)2483     public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) {
2484         synchronized (sLock) {
2485             if (!sHasNfcFeature) {
2486                 throw new UnsupportedOperationException();
2487             }
2488         }
2489         try {
2490             synchronized (mLock) {
2491                 if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
2492                     sService.removeNfcUnlockHandler(mNfcUnlockHandlers.remove(unlockHandler));
2493                 }
2494 
2495                 return true;
2496             }
2497         } catch (RemoteException e) {
2498             attemptDeadServiceRecovery(e);
2499             return false;
2500         }
2501     }
2502 
2503     /**
2504      * @hide
2505      */
2506     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getNfcAdapterExtrasInterface()2507     public INfcAdapterExtras getNfcAdapterExtrasInterface() {
2508         if (mContext == null) {
2509             throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
2510                     + " NFC extras APIs");
2511         }
2512         try {
2513             return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
2514         } catch (RemoteException e) {
2515             attemptDeadServiceRecovery(e);
2516             // Try one more time
2517             if (sService == null) {
2518                 Log.e(TAG, "Failed to recover NFC Service.");
2519                 return null;
2520             }
2521             try {
2522                 return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
2523             } catch (RemoteException ee) {
2524                 Log.e(TAG, "Failed to recover NFC Service.");
2525             }
2526             return null;
2527         }
2528     }
2529 
enforceResumed(Activity activity)2530     void enforceResumed(Activity activity) {
2531         if (!activity.isResumed()) {
2532             throw new IllegalStateException("API cannot be called while activity is paused");
2533         }
2534     }
2535 
getSdkVersion()2536     int getSdkVersion() {
2537         if (mContext == null) {
2538             return android.os.Build.VERSION_CODES.GINGERBREAD; // best guess
2539         } else {
2540             return mContext.getApplicationInfo().targetSdkVersion;
2541         }
2542     }
2543 
2544     /**
2545      * Sets NFC controller always on feature.
2546      * <p>This API is for the NFCC internal state management. It allows to discriminate
2547      * the controller function from the NFC function by keeping the NFC controller on without
2548      * any NFC RF enabled if necessary.
2549      * <p>This call is asynchronous. Register a listener {@link #ControllerAlwaysOnListener}
2550      * by {@link #registerControllerAlwaysOnListener} to find out when the operation is
2551      * complete.
2552      * <p>If this returns true, then either NFCC always on state has been set based on the value,
2553      * or a {@link ControllerAlwaysOnListener#onControllerAlwaysOnChanged(boolean)} will be invoked
2554      * to indicate the state change.
2555      * If this returns false, then there is some problem that prevents an attempt to turn NFCC
2556      * always on.
2557      * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
2558      * disabled), if false the NFCC will follow completely the Nfc adapter state.
2559      * @throws UnsupportedOperationException if FEATURE_NFC,
2560      * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
2561      * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
2562      * are unavailable
2563      * @return void
2564      * @hide
2565      */
2566     @SystemApi
2567     @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
setControllerAlwaysOn(boolean value)2568     public boolean setControllerAlwaysOn(boolean value) {
2569         if (!sHasNfcFeature && !sHasCeFeature) {
2570             throw new UnsupportedOperationException();
2571         }
2572         try {
2573             return sService.setControllerAlwaysOn(value);
2574         } catch (RemoteException e) {
2575             attemptDeadServiceRecovery(e);
2576             // Try one more time
2577             if (sService == null) {
2578                 Log.e(TAG, "Failed to recover NFC Service.");
2579                 return false;
2580             }
2581             try {
2582                 return sService.setControllerAlwaysOn(value);
2583             } catch (RemoteException ee) {
2584                 Log.e(TAG, "Failed to recover NFC Service.");
2585             }
2586             return false;
2587         }
2588     }
2589 
2590     /**
2591      * Checks NFC controller always on feature is enabled.
2592      *
2593      * @return True if NFC controller always on is enabled, false otherwise
2594      * @throws UnsupportedOperationException if FEATURE_NFC,
2595      * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
2596      * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
2597      * are unavailable
2598      * @hide
2599      */
2600     @SystemApi
2601     @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
isControllerAlwaysOn()2602     public boolean isControllerAlwaysOn() {
2603         try {
2604             return sService.isControllerAlwaysOn();
2605         } catch (RemoteException e) {
2606             attemptDeadServiceRecovery(e);
2607             // Try one more time
2608             if (sService == null) {
2609                 Log.e(TAG, "Failed to recover NFC Service.");
2610                 return false;
2611             }
2612             try {
2613                 return sService.isControllerAlwaysOn();
2614             } catch (RemoteException ee) {
2615                 Log.e(TAG, "Failed to recover NFC Service.");
2616             }
2617             return false;
2618         }
2619     }
2620 
2621     /**
2622      * Checks if the device supports NFC controller always on functionality.
2623      *
2624      * @return True if device supports NFC controller always on, false otherwise
2625      * @throws UnsupportedOperationException if FEATURE_NFC,
2626      * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
2627      * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
2628      * are unavailable
2629      * @hide
2630      */
2631     @SystemApi
2632     @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
isControllerAlwaysOnSupported()2633     public boolean isControllerAlwaysOnSupported() {
2634         if (!sHasNfcFeature && !sHasCeFeature) {
2635             throw new UnsupportedOperationException();
2636         }
2637         try {
2638             return sService.isControllerAlwaysOnSupported();
2639         } catch (RemoteException e) {
2640             attemptDeadServiceRecovery(e);
2641             // Try one more time
2642             if (sService == null) {
2643                 Log.e(TAG, "Failed to recover NFC Service.");
2644                 return false;
2645             }
2646             try {
2647                 return sService.isControllerAlwaysOnSupported();
2648             } catch (RemoteException ee) {
2649                 Log.e(TAG, "Failed to recover NFC Service.");
2650             }
2651             return false;
2652         }
2653     }
2654 
2655     /**
2656      * Register a {@link ControllerAlwaysOnListener} to listen for NFC controller always on
2657      * state changes
2658      * <p>The provided listener will be invoked by the given {@link Executor}.
2659      *
2660      * @param executor an {@link Executor} to execute given listener
2661      * @param listener user implementation of the {@link ControllerAlwaysOnListener}
2662      * @hide
2663      */
2664     @SystemApi
2665     @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
registerControllerAlwaysOnListener( @onNull @allbackExecutor Executor executor, @NonNull ControllerAlwaysOnListener listener)2666     public void registerControllerAlwaysOnListener(
2667             @NonNull @CallbackExecutor Executor executor,
2668             @NonNull ControllerAlwaysOnListener listener) {
2669         mControllerAlwaysOnListener.register(executor, listener);
2670     }
2671 
2672     /**
2673      * Unregister the specified {@link ControllerAlwaysOnListener}
2674      * <p>The same {@link ControllerAlwaysOnListener} object used when calling
2675      * {@link #registerControllerAlwaysOnListener(Executor, ControllerAlwaysOnListener)}
2676      * must be used.
2677      *
2678      * <p>Listeners are automatically unregistered when application process goes away
2679      *
2680      * @param listener user implementation of the {@link ControllerAlwaysOnListener}
2681      * @hide
2682      */
2683     @SystemApi
2684     @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
unregisterControllerAlwaysOnListener( @onNull ControllerAlwaysOnListener listener)2685     public void unregisterControllerAlwaysOnListener(
2686             @NonNull ControllerAlwaysOnListener listener) {
2687         mControllerAlwaysOnListener.unregister(listener);
2688     }
2689 
2690 
2691     /**
2692      * Sets whether we dispatch NFC Tag intents to the package.
2693      *
2694      * <p>{@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
2695      * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is
2696      * disallowed.
2697      * <p>An app is added to the preference list with the allowed flag set to {@code true}
2698      * when a Tag intent is dispatched to the package for the first time. This API is called
2699      * by settings to note that the user wants to change this default preference.
2700      *
2701      * @param userId the user to whom this package name will belong to
2702      * @param pkg the full name (i.e. com.google.android.tag) of the package that will be added to
2703      * the preference list
2704      * @param allow {@code true} to allow dispatching Tag intents to the package's activity,
2705      * {@code false} otherwise
2706      * @return the {@link #TagIntentAppPreferenceResult} value
2707      * @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns
2708      * {@code false}
2709      *
2710      * @hide
2711      */
2712     @SystemApi
2713     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
2714     @TagIntentAppPreferenceResult
setTagIntentAppPreferenceForUser(@serIdInt int userId, @NonNull String pkg, boolean allow)2715     public int setTagIntentAppPreferenceForUser(@UserIdInt int userId,
2716                 @NonNull String pkg, boolean allow) {
2717         Objects.requireNonNull(pkg, "pkg cannot be null");
2718         if (!isTagIntentAppPreferenceSupported()) {
2719             Log.e(TAG, "TagIntentAppPreference is not supported");
2720             throw new UnsupportedOperationException();
2721         }
2722         try {
2723             return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
2724         } catch (RemoteException e) {
2725             attemptDeadServiceRecovery(e);
2726             // Try one more time
2727             if (sService == null) {
2728                 Log.e(TAG, "Failed to recover NFC Service.");
2729             }
2730             try {
2731                 return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow);
2732             } catch (RemoteException ee) {
2733                 Log.e(TAG, "Failed to recover NFC Service.");
2734             }
2735             return TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE;
2736         }
2737     }
2738 
2739 
2740     /**
2741      * Get the Tag dispatch preference list of the UserId.
2742      *
2743      * <p>This returns a mapping of package names for this user id to whether we dispatch Tag
2744      * intents to the package. {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
2745      * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is
2746      * mapped to {@code false}.
2747      * <p>There are three different possible cases:
2748      * <p>A package not being in the preference list.
2749      * It does not contain any Tag intent filters or the user never triggers a Tag detection that
2750      * matches the intent filter of the package.
2751      * <p>A package being mapped to {@code true}.
2752      * When a package has been launched by a tag detection for the first time, the package name is
2753      * put to the map and by default mapped to {@code true}. The package will receive Tag intents as
2754      * usual.
2755      * <p>A package being mapped to {@code false}.
2756      * The user chooses to disable this package and it will not receive any Tag intents anymore.
2757      *
2758      * @param userId the user to whom this preference list will belong to
2759      * @return a map of the UserId which indicates the mapping from package name to
2760      * boolean(allow status), otherwise return an empty map
2761      * @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns
2762      * {@code false}
2763      *
2764      * @hide
2765      */
2766     @SystemApi
2767     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
2768     @NonNull
getTagIntentAppPreferenceForUser(@serIdInt int userId)2769     public Map<String, Boolean> getTagIntentAppPreferenceForUser(@UserIdInt int userId) {
2770         if (!isTagIntentAppPreferenceSupported()) {
2771             Log.e(TAG, "TagIntentAppPreference is not supported");
2772             throw new UnsupportedOperationException();
2773         }
2774         try {
2775             Map<String, Boolean> result = (Map<String, Boolean>) sService
2776                      .getTagIntentAppPreferenceForUser(userId);
2777             return result;
2778         } catch (RemoteException e) {
2779             attemptDeadServiceRecovery(e);
2780             // Try one more time
2781             if (sService == null) {
2782                 Log.e(TAG, "Failed to recover NFC Service.");
2783                 return Collections.emptyMap();
2784             }
2785             try {
2786                 Map<String, Boolean> result = (Map<String, Boolean>) sService
2787                         .getTagIntentAppPreferenceForUser(userId);
2788                 return result;
2789             } catch (RemoteException ee) {
2790                 Log.e(TAG, "Failed to recover NFC Service.");
2791             }
2792             return Collections.emptyMap();
2793         }
2794     }
2795 
2796     /**
2797      * Checks if the device supports Tag application preference.
2798      *
2799      * @return {@code true} if the device supports Tag application preference, {@code false}
2800      * otherwise
2801      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
2802      *
2803      * @hide
2804      */
2805     @SystemApi
2806     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
isTagIntentAppPreferenceSupported()2807     public boolean isTagIntentAppPreferenceSupported() {
2808         if (!sHasNfcFeature) {
2809             throw new UnsupportedOperationException();
2810         }
2811         try {
2812             return sService.isTagIntentAppPreferenceSupported();
2813         } catch (RemoteException e) {
2814             attemptDeadServiceRecovery(e);
2815             // Try one more time
2816             if (sService == null) {
2817                 Log.e(TAG, "Failed to recover NFC Service.");
2818                 return false;
2819             }
2820             try {
2821                 return sService.isTagIntentAppPreferenceSupported();
2822             } catch (RemoteException ee) {
2823                 Log.e(TAG, "Failed to recover NFC Service.");
2824             }
2825             return false;
2826         }
2827     }
2828 
2829    /**
2830      * Notifies the system of a new polling loop.
2831      *
2832      * @param frame is the new frame.
2833      *
2834      * @hide
2835      */
2836     @TestApi
2837     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
notifyPollingLoop(@onNull PollingFrame pollingFrame)2838     public void notifyPollingLoop(@NonNull PollingFrame pollingFrame) {
2839         try {
2840             if (sService == null) {
2841                 attemptDeadServiceRecovery(null);
2842             }
2843             sService.notifyPollingLoop(pollingFrame);
2844         } catch (RemoteException e) {
2845             attemptDeadServiceRecovery(e);
2846             // Try one more time
2847             if (sService == null) {
2848                 Log.e(TAG, "Failed to recover NFC Service.");
2849                 return;
2850             }
2851             try {
2852                 sService.notifyPollingLoop(pollingFrame);
2853             } catch (RemoteException ee) {
2854                 Log.e(TAG, "Failed to recover NFC Service.");
2855             }
2856         }
2857     }
2858 
2859    /**
2860      * Notifies the system of a an HCE session being deactivated.
2861      *     *
2862      * @hide
2863      */
2864     @TestApi
2865     @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
notifyHceDeactivated()2866     public void notifyHceDeactivated() {
2867         try {
2868             if (sService == null) {
2869                 attemptDeadServiceRecovery(null);
2870             }
2871             sService.notifyHceDeactivated();
2872         } catch (RemoteException e) {
2873             attemptDeadServiceRecovery(e);
2874             // Try one more time
2875             if (sService == null) {
2876                 Log.e(TAG, "Failed to recover NFC Service.");
2877                 return;
2878             }
2879             try {
2880                 sService.notifyHceDeactivated();
2881             } catch (RemoteException ee) {
2882                 Log.e(TAG, "Failed to recover NFC Service.");
2883             }
2884         }
2885     }
2886 
2887     /**
2888      * Sets NFC charging feature.
2889      * <p>This API is for the Settings application.
2890      * @return True if successful
2891      * @hide
2892      */
2893     @SystemApi
2894     @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
2895     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
setWlcEnabled(boolean enable)2896     public boolean setWlcEnabled(boolean enable) {
2897         if (!sHasNfcWlcFeature) {
2898             throw new UnsupportedOperationException();
2899         }
2900         try {
2901             return sService.setWlcEnabled(enable);
2902         } catch (RemoteException e) {
2903             attemptDeadServiceRecovery(e);
2904             // Try one more time
2905             if (sService == null) {
2906                 Log.e(TAG, "Failed to recover NFC Service.");
2907                 return false;
2908             }
2909             try {
2910                 return sService.setWlcEnabled(enable);
2911             } catch (RemoteException ee) {
2912                 Log.e(TAG, "Failed to recover NFC Service.");
2913             }
2914             return false;
2915         }
2916     }
2917 
2918     /**
2919      * Checks NFC charging feature is enabled.
2920      *
2921      * @return True if NFC charging is enabled, false otherwise
2922      * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
2923      * is unavailable
2924      */
2925     @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
isWlcEnabled()2926     public boolean isWlcEnabled() {
2927         if (!sHasNfcWlcFeature) {
2928             throw new UnsupportedOperationException();
2929         }
2930         try {
2931             return sService.isWlcEnabled();
2932         } catch (RemoteException e) {
2933             attemptDeadServiceRecovery(e);
2934             // Try one more time
2935             if (sService == null) {
2936                 Log.e(TAG, "Failed to recover NFC Service.");
2937                 return false;
2938             }
2939             try {
2940                 return sService.isWlcEnabled();
2941             } catch (RemoteException ee) {
2942                 Log.e(TAG, "Failed to recover NFC Service.");
2943             }
2944             return false;
2945         }
2946     }
2947 
2948     /**
2949      * A listener to be invoked when NFC controller always on state changes.
2950      * <p>Register your {@code ControllerAlwaysOnListener} implementation with {@link
2951      * NfcAdapter#registerWlcStateListener} and disable it with {@link
2952      * NfcAdapter#unregisterWlcStateListenerListener}.
2953      * @see #registerWlcStateListener
2954      * @hide
2955      */
2956     @SystemApi
2957     @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
2958     public interface WlcStateListener {
2959         /**
2960          * Called on NFC WLC state changes
2961          */
onWlcStateChanged(@onNull WlcListenerDeviceInfo wlcListenerDeviceInfo)2962         void onWlcStateChanged(@NonNull WlcListenerDeviceInfo wlcListenerDeviceInfo);
2963     }
2964 
2965     /**
2966      * Register a {@link WlcStateListener} to listen for NFC WLC state changes
2967      * <p>The provided listener will be invoked by the given {@link Executor}.
2968      *
2969      * @param executor an {@link Executor} to execute given listener
2970      * @param listener user implementation of the {@link WlcStateListener}
2971      * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
2972      * is unavailable
2973      *
2974      * @hide
2975      */
2976     @SystemApi
2977     @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
registerWlcStateListener( @onNull @allbackExecutor Executor executor, @NonNull WlcStateListener listener)2978     public void registerWlcStateListener(
2979             @NonNull @CallbackExecutor Executor executor,
2980             @NonNull WlcStateListener listener) {
2981         if (!sHasNfcWlcFeature) {
2982             throw new UnsupportedOperationException();
2983         }
2984         mNfcWlcStateListener.register(executor, listener);
2985     }
2986 
2987     /**
2988      * Unregister the specified {@link WlcStateListener}
2989      * <p>The same {@link WlcStateListener} object used when calling
2990      * {@link #registerWlcStateListener(Executor, WlcStateListener)}
2991      * must be used.
2992      *
2993      * <p>Listeners are automatically unregistered when application process goes away
2994      *
2995      * @param listener user implementation of the {@link WlcStateListener}a
2996      * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
2997      * is unavailable
2998      *
2999      * @hide
3000      */
3001     @SystemApi
3002     @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
unregisterWlcStateListener( @onNull WlcStateListener listener)3003     public void unregisterWlcStateListener(
3004             @NonNull WlcStateListener listener) {
3005         if (!sHasNfcWlcFeature) {
3006             throw new UnsupportedOperationException();
3007         }
3008         mNfcWlcStateListener.unregister(listener);
3009     }
3010 
3011     /**
3012      * Returns information on the NFC charging listener device
3013      *
3014      * @return Information on the NFC charging listener device
3015      * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
3016      * is unavailable
3017      */
3018     @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
3019     @Nullable
getWlcListenerDeviceInfo()3020     public WlcListenerDeviceInfo getWlcListenerDeviceInfo() {
3021         if (!sHasNfcWlcFeature) {
3022             throw new UnsupportedOperationException();
3023         }
3024         try {
3025             return sService.getWlcListenerDeviceInfo();
3026         } catch (RemoteException e) {
3027             attemptDeadServiceRecovery(e);
3028             // Try one more time
3029             if (sService == null) {
3030                 Log.e(TAG, "Failed to recover NFC Service.");
3031                 return null;
3032             }
3033             try {
3034                 return sService.getWlcListenerDeviceInfo();
3035             } catch (RemoteException ee) {
3036                 Log.e(TAG, "Failed to recover NFC Service.");
3037             }
3038             return null;
3039         }
3040     }
3041 
3042     /**
3043      * Vendor NCI command success.
3044      * @hide
3045      */
3046     @SystemApi
3047     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3048     public static final int SEND_VENDOR_NCI_STATUS_SUCCESS = 0;
3049     /**
3050      * Vendor NCI command rejected.
3051      * @hide
3052      */
3053     @SystemApi
3054     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3055     public static final int SEND_VENDOR_NCI_STATUS_REJECTED = 1;
3056     /**
3057      * Vendor NCI command corrupted.
3058      * @hide
3059      */
3060     @SystemApi
3061     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3062     public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED  = 2;
3063     /**
3064      * Vendor NCI command failed with unknown reason.
3065      * @hide
3066      */
3067     @SystemApi
3068     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3069     public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3;
3070 
3071     /**
3072      * @hide
3073      */
3074     @Retention(RetentionPolicy.SOURCE)
3075     @IntDef(value = {
3076             SEND_VENDOR_NCI_STATUS_SUCCESS,
3077             SEND_VENDOR_NCI_STATUS_REJECTED,
3078             SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED,
3079             SEND_VENDOR_NCI_STATUS_FAILED,
3080     })
3081     @interface SendVendorNciStatus {}
3082 
3083     /**
3084      * Message Type for NCI Command.
3085      * @hide
3086      */
3087     @SystemApi
3088     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3089     public static final int MESSAGE_TYPE_COMMAND = 1;
3090 
3091     /**
3092      * @hide
3093      */
3094     @Retention(RetentionPolicy.SOURCE)
3095     @IntDef(value = {
3096             MESSAGE_TYPE_COMMAND,
3097     })
3098     @interface MessageType {}
3099 
3100     /**
3101      * Send Vendor specific Nci Messages with custom message type.
3102      *
3103      * The format of the NCI messages are defined in the NCI specification. The platform is
3104      * responsible for fragmenting the payload if necessary.
3105      *
3106      * Note that mt (message type) is added at the beginning of method parameters as it is more
3107      * distinctive than other parameters and was requested from vendor.
3108      *
3109      * @param mt message Type of the command
3110      * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
3111      *            the NCI specification
3112      * @param oid opcode ID of the command. This is left to the OEM / vendor to decide
3113      * @param payload containing vendor Nci message payload
3114      * @return message send status
3115      * @hide
3116      */
3117     @SystemApi
3118     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3119     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
sendVendorNciMessage(@essageType int mt, @IntRange(from = 0, to = 15) int gid, @IntRange(from = 0) int oid, @NonNull byte[] payload)3120     public @SendVendorNciStatus int sendVendorNciMessage(@MessageType int mt,
3121             @IntRange(from = 0, to = 15) int gid, @IntRange(from = 0) int oid,
3122             @NonNull byte[] payload) {
3123         Objects.requireNonNull(payload, "Payload must not be null");
3124         try {
3125             return sService.sendVendorNciMessage(mt, gid, oid, payload);
3126         } catch (RemoteException e) {
3127             throw e.rethrowFromSystemServer();
3128         }
3129     }
3130 
3131     /**
3132      * Register an {@link NfcVendorNciCallback} to listen for Nfc vendor responses and notifications
3133      * <p>The provided callback will be invoked by the given {@link Executor}.
3134      *
3135      * <p>When first registering a callback, the callbacks's
3136      * {@link NfcVendorNciCallback#onVendorNciCallBack(byte[])} is immediately invoked to
3137      * notify the vendor notification.
3138      *
3139      * @param executor an {@link Executor} to execute given callback
3140      * @param callback user implementation of the {@link NfcVendorNciCallback}
3141      * @hide
3142      */
3143     @SystemApi
3144     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3145     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
registerNfcVendorNciCallback(@onNull @allbackExecutor Executor executor, @NonNull NfcVendorNciCallback callback)3146     public void registerNfcVendorNciCallback(@NonNull @CallbackExecutor Executor executor,
3147             @NonNull NfcVendorNciCallback callback) {
3148         mNfcVendorNciCallbackListener.register(executor, callback);
3149     }
3150 
3151     /**
3152      * Unregister the specified {@link NfcVendorNciCallback}
3153      *
3154      * <p>The same {@link NfcVendorNciCallback} object used when calling
3155      * {@link #registerNfcVendorNciCallback(Executor, NfcVendorNciCallback)} must be used.
3156      *
3157      * <p>Callbacks are automatically unregistered when application process goes away
3158      *
3159      * @param callback user implementation of the {@link NfcVendorNciCallback}
3160      * @hide
3161      */
3162     @SystemApi
3163     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3164     @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
unregisterNfcVendorNciCallback(@onNull NfcVendorNciCallback callback)3165     public void unregisterNfcVendorNciCallback(@NonNull NfcVendorNciCallback callback) {
3166         mNfcVendorNciCallbackListener.unregister(callback);
3167     }
3168 
3169     /**
3170      * Interface for receiving vendor NCI responses and notifications.
3171      * @hide
3172      */
3173     @SystemApi
3174     @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
3175     public interface NfcVendorNciCallback {
3176         /**
3177          * Invoked when a vendor specific NCI response is received.
3178          *
3179          * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
3180          *            the NCI specification.
3181          * @param oid opcode ID of the command. This is left to the OEM / vendor to decide.
3182          * @param payload containing vendor Nci message payload.
3183          */
3184         @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
onVendorNciResponse( @ntRangefrom = 0, to = 15) int gid, int oid, @NonNull byte[] payload)3185         void onVendorNciResponse(
3186                 @IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload);
3187 
3188         /**
3189          * Invoked when a vendor specific NCI notification is received.
3190          *
3191          * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
3192          *            the NCI specification.
3193          * @param oid opcode ID of the command. This is left to the OEM / vendor to decide.
3194          * @param payload containing vendor Nci message payload.
3195          */
3196         @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
onVendorNciNotification( @ntRangefrom = 9, to = 15) int gid, int oid, @NonNull byte[] payload)3197         void onVendorNciNotification(
3198                 @IntRange(from = 9, to = 15) int gid, int oid, @NonNull byte[] payload);
3199     }
3200 
3201     /**
3202      * Returns an instance of {@link NfcOemExtension} associated with {@link NfcAdapter} instance.
3203      * @hide
3204      */
3205     @SystemApi
3206     @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
getNfcOemExtension()3207     @NonNull public NfcOemExtension getNfcOemExtension() {
3208         synchronized (sLock) {
3209             if (!sHasNfcFeature) {
3210                 throw new UnsupportedOperationException();
3211             }
3212         }
3213         return mNfcOemExtension;
3214     }
3215 }
3216