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