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.annotation.CallbackExecutor; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.annotation.Nullable; 23 import android.annotation.RequiresPermission; 24 import android.annotation.SdkConstant; 25 import android.annotation.SdkConstant.SdkConstantType; 26 import android.annotation.SystemApi; 27 import android.annotation.UserIdInt; 28 import android.app.Activity; 29 import android.app.ActivityThread; 30 import android.app.OnActivityPausedListener; 31 import android.app.PendingIntent; 32 import android.compat.annotation.UnsupportedAppUsage; 33 import android.content.Context; 34 import android.content.IntentFilter; 35 import android.content.pm.PackageManager; 36 import android.net.Uri; 37 import android.nfc.tech.MifareClassic; 38 import android.nfc.tech.Ndef; 39 import android.nfc.tech.NfcA; 40 import android.nfc.tech.NfcF; 41 import android.os.Build; 42 import android.os.Bundle; 43 import android.os.Handler; 44 import android.os.IBinder; 45 import android.os.RemoteException; 46 import android.util.Log; 47 48 import java.io.IOException; 49 import java.lang.annotation.Retention; 50 import java.lang.annotation.RetentionPolicy; 51 import java.util.ArrayList; 52 import java.util.Collections; 53 import java.util.HashMap; 54 import java.util.List; 55 import java.util.Map; 56 import java.util.Objects; 57 import java.util.concurrent.Executor; 58 59 /** 60 * Represents the local NFC adapter. 61 * <p> 62 * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC 63 * adapter for this Android device. 64 * 65 * <div class="special reference"> 66 * <h3>Developer Guides</h3> 67 * <p>For more information about using NFC, read the 68 * <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p> 69 * <p>To perform basic file sharing between devices, read 70 * <a href="{@docRoot}training/beam-files/index.html">Sharing Files with NFC</a>. 71 * </div> 72 */ 73 public final class NfcAdapter { 74 static final String TAG = "NFC"; 75 76 private final NfcControllerAlwaysOnListener mControllerAlwaysOnListener; 77 78 /** 79 * Intent to start an activity when a tag with NDEF payload is discovered. 80 * 81 * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and 82 * looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the 83 * intent will contain the URI in its data field. If a MIME record is found the intent will 84 * contain the MIME type in its type field. This allows activities to register 85 * {@link IntentFilter}s targeting specific content on tags. Activities should register the 86 * most specific intent filters possible to avoid the activity chooser dialog, which can 87 * disrupt the interaction with the tag as the user interacts with the screen. 88 * 89 * <p>If the tag has an NDEF payload this intent is started before 90 * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither 91 * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started. 92 * 93 * <p>The MIME type or data URI of this intent are normalized before dispatch - 94 * so that MIME, URI scheme and URI host are always lower-case. 95 */ 96 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 97 public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"; 98 99 /** 100 * Intent to start an activity when a tag is discovered and activities are registered for the 101 * specific technologies on the tag. 102 * 103 * <p>To receive this intent an activity must include an intent filter 104 * for this action and specify the desired tech types in a 105 * manifest <code>meta-data</code> entry. Here is an example manfiest entry: 106 * <pre> 107 * <activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"> 108 * <!-- Add a technology filter --> 109 * <intent-filter> 110 * <action android:name="android.nfc.action.TECH_DISCOVERED" /> 111 * </intent-filter> 112 * 113 * <meta-data android:name="android.nfc.action.TECH_DISCOVERED" 114 * android:resource="@xml/filter_nfc" 115 * /> 116 * </activity></pre> 117 * 118 * <p>The meta-data XML file should contain one or more <code>tech-list</code> entries 119 * each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer 120 * to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA". 121 * 122 * <p>A tag matches if any of the 123 * <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each 124 * of the <code>tech-list</code>s is considered independently and the 125 * activity is considered a match is any single <code>tech-list</code> matches the tag that was 126 * discovered. This provides AND and OR semantics for filtering desired techs. Here is an 127 * example that will match any tag using {@link NfcF} or any tag using {@link NfcA}, 128 * {@link MifareClassic}, and {@link Ndef}: 129 * 130 * <pre> 131 * <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 132 * <!-- capture anything using NfcF --> 133 * <tech-list> 134 * <tech>android.nfc.tech.NfcF</tech> 135 * </tech-list> 136 * 137 * <!-- OR --> 138 * 139 * <!-- capture all MIFARE Classics with NDEF payloads --> 140 * <tech-list> 141 * <tech>android.nfc.tech.NfcA</tech> 142 * <tech>android.nfc.tech.MifareClassic</tech> 143 * <tech>android.nfc.tech.Ndef</tech> 144 * </tech-list> 145 * </resources></pre> 146 * 147 * <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before 148 * {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED} 149 * this intent will not be started. If any activities respond to this intent 150 * {@link #ACTION_TAG_DISCOVERED} will not be started. 151 */ 152 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 153 public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"; 154 155 /** 156 * Intent to start an activity when a tag is discovered. 157 * 158 * <p>This intent will not be started when a tag is discovered if any activities respond to 159 * {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag. 160 */ 161 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 162 public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"; 163 164 /** 165 * Broadcast Action: Intent to notify an application that a transaction event has occurred 166 * on the Secure Element. 167 * 168 * <p>This intent will only be sent if the application has requested permission for 169 * {@link android.Manifest.permission#NFC_TRANSACTION_EVENT} and if the application has the 170 * necessary access to Secure Element which witnessed the particular event. 171 */ 172 @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT) 173 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 174 public static final String ACTION_TRANSACTION_DETECTED = 175 "android.nfc.action.TRANSACTION_DETECTED"; 176 177 /** 178 * Broadcast Action: Intent to notify if the preferred payment service changed. 179 * 180 * <p>This intent will only be sent to the application has requested permission for 181 * {@link android.Manifest.permission#NFC_PREFERRED_PAYMENT_INFO} and if the application 182 * has the necessary access to Secure Element which witnessed the particular event. 183 */ 184 @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) 185 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 186 public static final String ACTION_PREFERRED_PAYMENT_CHANGED = 187 "android.nfc.action.PREFERRED_PAYMENT_CHANGED"; 188 189 /** 190 * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED 191 * @hide 192 */ 193 public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST"; 194 195 /** 196 * Mandatory extra containing the {@link Tag} that was discovered for the 197 * {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and 198 * {@link #ACTION_TAG_DISCOVERED} intents. 199 */ 200 public static final String EXTRA_TAG = "android.nfc.extra.TAG"; 201 202 /** 203 * Extra containing an array of {@link NdefMessage} present on the discovered tag.<p> 204 * This extra is mandatory for {@link #ACTION_NDEF_DISCOVERED} intents, 205 * and optional for {@link #ACTION_TECH_DISCOVERED}, and 206 * {@link #ACTION_TAG_DISCOVERED} intents.<p> 207 * When this extra is present there will always be at least one 208 * {@link NdefMessage} element. Most NDEF tags have only one NDEF message, 209 * but we use an array for future compatibility. 210 */ 211 public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES"; 212 213 /** 214 * Optional extra containing a byte array containing the ID of the discovered tag for 215 * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and 216 * {@link #ACTION_TAG_DISCOVERED} intents. 217 */ 218 public static final String EXTRA_ID = "android.nfc.extra.ID"; 219 220 /** 221 * Broadcast Action: The state of the local NFC adapter has been 222 * changed. 223 * <p>For example, NFC has been turned on or off. 224 * <p>Always contains the extra field {@link #EXTRA_ADAPTER_STATE} 225 */ 226 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 227 public static final String ACTION_ADAPTER_STATE_CHANGED = 228 "android.nfc.action.ADAPTER_STATE_CHANGED"; 229 230 /** 231 * Used as an int extra field in {@link #ACTION_ADAPTER_STATE_CHANGED} 232 * intents to request the current power state. Possible values are: 233 * {@link #STATE_OFF}, 234 * {@link #STATE_TURNING_ON}, 235 * {@link #STATE_ON}, 236 * {@link #STATE_TURNING_OFF}, 237 */ 238 public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE"; 239 240 /** 241 * Mandatory byte[] extra field in {@link #ACTION_TRANSACTION_DETECTED} 242 */ 243 public static final String EXTRA_AID = "android.nfc.extra.AID"; 244 245 /** 246 * Optional byte[] extra field in {@link #ACTION_TRANSACTION_DETECTED} 247 */ 248 public static final String EXTRA_DATA = "android.nfc.extra.DATA"; 249 250 /** 251 * Mandatory String extra field in {@link #ACTION_TRANSACTION_DETECTED} 252 * Indicates the Secure Element on which the transaction occurred. 253 * eSE1...eSEn for Embedded Secure Elements, SIM1...SIMn for UICC, etc. 254 */ 255 public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME"; 256 257 /** 258 * Mandatory String extra field in {@link #ACTION_PREFERRED_PAYMENT_CHANGED} 259 * Indicates the condition when trigger this event. Possible values are: 260 * {@link #PREFERRED_PAYMENT_LOADED}, 261 * {@link #PREFERRED_PAYMENT_CHANGED}, 262 * {@link #PREFERRED_PAYMENT_UPDATED}, 263 */ 264 public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON = 265 "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON"; 266 /** 267 * Nfc is enabled and the preferred payment aids are registered. 268 */ 269 public static final int PREFERRED_PAYMENT_LOADED = 1; 270 /** 271 * User selected another payment application as the preferred payment. 272 */ 273 public static final int PREFERRED_PAYMENT_CHANGED = 2; 274 /** 275 * Current preferred payment has issued an update (registered/unregistered new aids or has been 276 * updated itself). 277 */ 278 public static final int PREFERRED_PAYMENT_UPDATED = 3; 279 280 public static final int STATE_OFF = 1; 281 public static final int STATE_TURNING_ON = 2; 282 public static final int STATE_ON = 3; 283 public static final int STATE_TURNING_OFF = 4; 284 285 /** 286 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 287 * <p> 288 * Setting this flag enables polling for Nfc-A technology. 289 */ 290 public static final int FLAG_READER_NFC_A = 0x1; 291 292 /** 293 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 294 * <p> 295 * Setting this flag enables polling for Nfc-B technology. 296 */ 297 public static final int FLAG_READER_NFC_B = 0x2; 298 299 /** 300 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 301 * <p> 302 * Setting this flag enables polling for Nfc-F technology. 303 */ 304 public static final int FLAG_READER_NFC_F = 0x4; 305 306 /** 307 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 308 * <p> 309 * Setting this flag enables polling for Nfc-V (ISO15693) technology. 310 */ 311 public static final int FLAG_READER_NFC_V = 0x8; 312 313 /** 314 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 315 * <p> 316 * Setting this flag enables polling for NfcBarcode technology. 317 */ 318 public static final int FLAG_READER_NFC_BARCODE = 0x10; 319 320 /** 321 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 322 * <p> 323 * Setting this flag allows the caller to prevent the 324 * platform from performing an NDEF check on the tags it 325 * finds. 326 */ 327 public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80; 328 329 /** 330 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 331 * <p> 332 * Setting this flag allows the caller to prevent the 333 * platform from playing sounds when it discovers a tag. 334 */ 335 public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100; 336 337 /** 338 * Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 339 * <p> 340 * Setting this integer extra allows the calling application to specify 341 * the delay that the platform will use for performing presence checks 342 * on any discovered tag. 343 */ 344 public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence"; 345 346 /** 347 * @hide 348 * @removed 349 */ 350 @SystemApi 351 @UnsupportedAppUsage 352 public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1; 353 354 /** @hide */ 355 public static final String ACTION_HANDOVER_TRANSFER_STARTED = 356 "android.nfc.action.HANDOVER_TRANSFER_STARTED"; 357 358 /** @hide */ 359 public static final String ACTION_HANDOVER_TRANSFER_DONE = 360 "android.nfc.action.HANDOVER_TRANSFER_DONE"; 361 362 /** @hide */ 363 public static final String EXTRA_HANDOVER_TRANSFER_STATUS = 364 "android.nfc.extra.HANDOVER_TRANSFER_STATUS"; 365 366 /** @hide */ 367 public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0; 368 /** @hide */ 369 public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1; 370 371 /** @hide */ 372 public static final String EXTRA_HANDOVER_TRANSFER_URI = 373 "android.nfc.extra.HANDOVER_TRANSFER_URI"; 374 375 /** 376 * Broadcast Action: Notify possible NFC transaction blocked because device is locked. 377 * <p>An external NFC field detected when device locked and SecureNfc enabled. 378 * @hide 379 */ 380 public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = 381 "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC"; 382 383 /** 384 * The requested app is correctly added to the Tag intent app preference. 385 * 386 * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow) 387 * @hide 388 */ 389 @SystemApi 390 public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; 391 392 /** 393 * The requested app is not installed on the device. 394 * 395 * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow) 396 * @hide 397 */ 398 @SystemApi 399 public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; 400 401 /** 402 * The NfcService is not available. 403 * 404 * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow) 405 * @hide 406 */ 407 @SystemApi 408 public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; 409 410 /** 411 * Possible response codes from {@link #setTagIntentAppPreferenceForUser}. 412 * 413 * @hide 414 */ 415 @IntDef(prefix = { "TAG_INTENT_APP_PREF_RESULT" }, value = { 416 TAG_INTENT_APP_PREF_RESULT_SUCCESS, 417 TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND, 418 TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE}) 419 @Retention(RetentionPolicy.SOURCE) 420 public @interface TagIntentAppPreferenceResult {} 421 422 // Guarded by NfcAdapter.class 423 static boolean sIsInitialized = false; 424 static boolean sHasNfcFeature; 425 static boolean sHasCeFeature; 426 427 // Final after first constructor, except for 428 // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort 429 // recovery 430 @UnsupportedAppUsage 431 static INfcAdapter sService; 432 static NfcServiceManager.ServiceRegisterer sServiceRegisterer; 433 static INfcTag sTagService; 434 static INfcCardEmulation sCardEmulationService; 435 static INfcFCardEmulation sNfcFCardEmulationService; 436 437 /** 438 * The NfcAdapter object for each application context. 439 * There is a 1-1 relationship between application context and 440 * NfcAdapter object. 441 */ 442 static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class 443 444 /** 445 * NfcAdapter used with a null context. This ctor was deprecated but we have 446 * to support it for backwards compatibility. New methods that require context 447 * might throw when called on the null-context NfcAdapter. 448 */ 449 static NfcAdapter sNullContextNfcAdapter; // protected by NfcAdapter.class 450 451 final NfcActivityManager mNfcActivityManager; 452 final Context mContext; 453 final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers; 454 final Object mLock; 455 456 ITagRemovedCallback mTagRemovedListener; // protected by mLock 457 458 /** 459 * A callback to be invoked when the system finds a tag while the foreground activity is 460 * operating in reader mode. 461 * <p>Register your {@code ReaderCallback} implementation with {@link 462 * NfcAdapter#enableReaderMode} and disable it with {@link 463 * NfcAdapter#disableReaderMode}. 464 * @see NfcAdapter#enableReaderMode 465 */ 466 public interface ReaderCallback { onTagDiscovered(Tag tag)467 public void onTagDiscovered(Tag tag); 468 } 469 470 /** 471 * A listener to be invoked when NFC controller always on state changes. 472 * <p>Register your {@code ControllerAlwaysOnListener} implementation with {@link 473 * NfcAdapter#registerControllerAlwaysOnListener} and disable it with {@link 474 * NfcAdapter#unregisterControllerAlwaysOnListener}. 475 * @see #registerControllerAlwaysOnListener 476 * @hide 477 */ 478 @SystemApi 479 public interface ControllerAlwaysOnListener { 480 /** 481 * Called on NFC controller always on state changes 482 */ onControllerAlwaysOnChanged(boolean isEnabled)483 void onControllerAlwaysOnChanged(boolean isEnabled); 484 } 485 486 /** 487 * A callback to be invoked when the system successfully delivers your {@link NdefMessage} 488 * to another device. 489 * @see #setOnNdefPushCompleteCallback 490 * @deprecated this feature is removed. File sharing can work using other technology like 491 * Bluetooth. 492 */ 493 @java.lang.Deprecated 494 public interface OnNdefPushCompleteCallback { 495 /** 496 * Called on successful NDEF push. 497 * 498 * <p>This callback is usually made on a binder thread (not the UI thread). 499 * 500 * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set 501 * @see #setNdefPushMessageCallback 502 */ onNdefPushComplete(NfcEvent event)503 public void onNdefPushComplete(NfcEvent event); 504 } 505 506 /** 507 * A callback to be invoked when another NFC device capable of NDEF push (Android Beam) 508 * is within range. 509 * <p>Implement this interface and pass it to {@link 510 * NfcAdapter#setNdefPushMessageCallback setNdefPushMessageCallback()} in order to create an 511 * {@link NdefMessage} at the moment that another device is within range for NFC. Using this 512 * callback allows you to create a message with data that might vary based on the 513 * content currently visible to the user. Alternatively, you can call {@link 514 * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the 515 * same data. 516 * @deprecated this feature is removed. File sharing can work using other technology like 517 * Bluetooth. 518 */ 519 @java.lang.Deprecated 520 public interface CreateNdefMessageCallback { 521 /** 522 * Called to provide a {@link NdefMessage} to push. 523 * 524 * <p>This callback is usually made on a binder thread (not the UI thread). 525 * 526 * <p>Called when this device is in range of another device 527 * that might support NDEF push. It allows the application to 528 * create the NDEF message only when it is required. 529 * 530 * <p>NDEF push cannot occur until this method returns, so do not 531 * block for too long. 532 * 533 * <p>The Android operating system will usually show a system UI 534 * on top of your activity during this time, so do not try to request 535 * input from the user to complete the callback, or provide custom NDEF 536 * push UI. The user probably will not see it. 537 * 538 * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set 539 * @return NDEF message to push, or null to not provide a message 540 */ createNdefMessage(NfcEvent event)541 public NdefMessage createNdefMessage(NfcEvent event); 542 } 543 544 545 /** 546 * @deprecated this feature is removed. File sharing can work using other technology like 547 * Bluetooth. 548 */ 549 @java.lang.Deprecated 550 public interface CreateBeamUrisCallback { createBeamUris(NfcEvent event)551 public Uri[] createBeamUris(NfcEvent event); 552 } 553 554 /** 555 * A callback that is invoked when a tag is removed from the field. 556 * @see NfcAdapter#ignore 557 */ 558 public interface OnTagRemovedListener { onTagRemoved()559 void onTagRemoved(); 560 } 561 562 /** 563 * A callback to be invoked when an application has registered as a 564 * handler to unlock the device given an NFC tag at the lockscreen. 565 * @hide 566 */ 567 @SystemApi 568 public interface NfcUnlockHandler { 569 /** 570 * Called at the lock screen to attempt to unlock the device with the given tag. 571 * @param tag the detected tag, to be used to unlock the device 572 * @return true if the device was successfully unlocked 573 */ onUnlockAttempted(Tag tag)574 public boolean onUnlockAttempted(Tag tag); 575 } 576 577 /** 578 * Return list of Secure Elements which support off host card emulation. 579 * 580 * @return List<String> containing secure elements on the device which supports 581 * off host card emulation. eSE for Embedded secure element, 582 * SIM for UICC and so on. 583 * @hide 584 */ getSupportedOffHostSecureElements()585 public @NonNull List<String> getSupportedOffHostSecureElements() { 586 if (mContext == null) { 587 throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " 588 + " getSupportedOffHostSecureElements APIs"); 589 } 590 List<String> offHostSE = new ArrayList<String>(); 591 PackageManager pm = mContext.getPackageManager(); 592 if (pm == null) { 593 Log.e(TAG, "Cannot get package manager, assuming no off-host CE feature"); 594 return offHostSE; 595 } 596 if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)) { 597 offHostSE.add("SIM"); 598 } 599 if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE)) { 600 offHostSE.add("eSE"); 601 } 602 return offHostSE; 603 } 604 605 /** 606 * Returns the NfcAdapter for application context, 607 * or throws if NFC is not available. 608 * @hide 609 */ 610 @UnsupportedAppUsage getNfcAdapter(Context context)611 public static synchronized NfcAdapter getNfcAdapter(Context context) { 612 if (context == null) { 613 if (sNullContextNfcAdapter == null) { 614 sNullContextNfcAdapter = new NfcAdapter(null); 615 } 616 return sNullContextNfcAdapter; 617 } 618 if (!sIsInitialized) { 619 PackageManager pm; 620 pm = context.getPackageManager(); 621 sHasNfcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC); 622 sHasCeFeature = 623 pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION) 624 || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF) 625 || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC) 626 || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE); 627 /* is this device meant to have NFC */ 628 if (!sHasNfcFeature && !sHasCeFeature) { 629 Log.v(TAG, "this device does not have NFC support"); 630 throw new UnsupportedOperationException(); 631 } 632 NfcServiceManager manager = NfcFrameworkInitializer.getNfcServiceManager(); 633 if (manager == null) { 634 Log.e(TAG, "NfcServiceManager is null"); 635 throw new UnsupportedOperationException(); 636 } 637 sServiceRegisterer = manager.getNfcManagerServiceRegisterer(); 638 sService = getServiceInterface(); 639 if (sService == null) { 640 Log.e(TAG, "could not retrieve NFC service"); 641 throw new UnsupportedOperationException(); 642 } 643 if (sHasNfcFeature) { 644 try { 645 sTagService = sService.getNfcTagInterface(); 646 } catch (RemoteException e) { 647 Log.e(TAG, "could not retrieve NFC Tag service"); 648 throw new UnsupportedOperationException(); 649 } 650 } 651 if (sHasCeFeature) { 652 try { 653 sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface(); 654 } catch (RemoteException e) { 655 Log.e(TAG, "could not retrieve NFC-F card emulation service"); 656 throw new UnsupportedOperationException(); 657 } 658 try { 659 sCardEmulationService = sService.getNfcCardEmulationInterface(); 660 } catch (RemoteException e) { 661 Log.e(TAG, "could not retrieve card emulation service"); 662 throw new UnsupportedOperationException(); 663 } 664 } 665 666 sIsInitialized = true; 667 } 668 NfcAdapter adapter = sNfcAdapters.get(context); 669 if (adapter == null) { 670 adapter = new NfcAdapter(context); 671 sNfcAdapters.put(context, adapter); 672 } 673 return adapter; 674 } 675 676 /** get handle to NFC service interface */ getServiceInterface()677 private static INfcAdapter getServiceInterface() { 678 /* get a handle to NFC service */ 679 IBinder b = sServiceRegisterer.get(); 680 if (b == null) { 681 return null; 682 } 683 return INfcAdapter.Stub.asInterface(b); 684 } 685 686 /** 687 * Helper to get the default NFC Adapter. 688 * <p> 689 * Most Android devices will only have one NFC Adapter (NFC Controller). 690 * <p> 691 * This helper is the equivalent of: 692 * <pre> 693 * NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); 694 * NfcAdapter adapter = manager.getDefaultAdapter();</pre> 695 * @param context the calling application's context 696 * 697 * @return the default NFC adapter, or null if no NFC adapter exists 698 */ getDefaultAdapter(Context context)699 public static NfcAdapter getDefaultAdapter(Context context) { 700 if (context == null) { 701 throw new IllegalArgumentException("context cannot be null"); 702 } 703 context = context.getApplicationContext(); 704 if (context == null) { 705 throw new IllegalArgumentException( 706 "context not associated with any application (using a mock context?)"); 707 } 708 709 if (sIsInitialized && sServiceRegisterer.tryGet() == null) { 710 synchronized (NfcAdapter.class) { 711 /* Stale sService pointer */ 712 if (sIsInitialized) sIsInitialized = false; 713 } 714 return null; 715 } 716 /* Try to initialize the service */ 717 NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); 718 if (manager == null) { 719 // NFC not available 720 return null; 721 } 722 return manager.getDefaultAdapter(); 723 } 724 725 /** 726 * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p> 727 * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required 728 * for many NFC API methods. Those methods will fail when called on an NfcAdapter 729 * object created from this method.<p> 730 * @deprecated use {@link #getDefaultAdapter(Context)} 731 * @hide 732 */ 733 @Deprecated 734 @UnsupportedAppUsage getDefaultAdapter()735 public static NfcAdapter getDefaultAdapter() { 736 // introduced in API version 9 (GB 2.3) 737 // deprecated in API version 10 (GB 2.3.3) 738 // removed from public API in version 16 (ICS MR2) 739 // should maintain as a hidden API for binary compatibility for a little longer 740 Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " + 741 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception()); 742 743 return NfcAdapter.getNfcAdapter(null); 744 } 745 NfcAdapter(Context context)746 NfcAdapter(Context context) { 747 mContext = context; 748 mNfcActivityManager = new NfcActivityManager(this); 749 mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>(); 750 mTagRemovedListener = null; 751 mLock = new Object(); 752 mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService()); 753 } 754 755 /** 756 * @hide 757 */ 758 @UnsupportedAppUsage getContext()759 public Context getContext() { 760 return mContext; 761 } 762 763 /** 764 * Returns the binder interface to the service. 765 * @hide 766 */ 767 @UnsupportedAppUsage getService()768 public INfcAdapter getService() { 769 isEnabled(); // NOP call to recover sService if it is stale 770 return sService; 771 } 772 773 /** 774 * Returns the binder interface to the tag service. 775 * @hide 776 */ getTagService()777 public INfcTag getTagService() { 778 isEnabled(); // NOP call to recover sTagService if it is stale 779 return sTagService; 780 } 781 782 /** 783 * Returns the binder interface to the card emulation service. 784 * @hide 785 */ getCardEmulationService()786 public INfcCardEmulation getCardEmulationService() { 787 isEnabled(); 788 return sCardEmulationService; 789 } 790 791 /** 792 * Returns the binder interface to the NFC-F card emulation service. 793 * @hide 794 */ getNfcFCardEmulationService()795 public INfcFCardEmulation getNfcFCardEmulationService() { 796 isEnabled(); 797 return sNfcFCardEmulationService; 798 } 799 800 /** 801 * Returns the binder interface to the NFC-DTA test interface. 802 * @hide 803 */ getNfcDtaInterface()804 public INfcDta getNfcDtaInterface() { 805 if (mContext == null) { 806 throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " 807 + " NFC extras APIs"); 808 } 809 try { 810 return sService.getNfcDtaInterface(mContext.getPackageName()); 811 } catch (RemoteException e) { 812 attemptDeadServiceRecovery(e); 813 // Try one more time 814 if (sService == null) { 815 Log.e(TAG, "Failed to recover NFC Service."); 816 return null; 817 } 818 try { 819 return sService.getNfcDtaInterface(mContext.getPackageName()); 820 } catch (RemoteException ee) { 821 Log.e(TAG, "Failed to recover NFC Service."); 822 } 823 return null; 824 } 825 } 826 827 /** 828 * NFC service dead - attempt best effort recovery 829 * @hide 830 */ 831 @UnsupportedAppUsage attemptDeadServiceRecovery(Exception e)832 public void attemptDeadServiceRecovery(Exception e) { 833 Log.e(TAG, "NFC service dead - attempting to recover", e); 834 INfcAdapter service = getServiceInterface(); 835 if (service == null) { 836 Log.e(TAG, "could not retrieve NFC service during service recovery"); 837 // nothing more can be done now, sService is still stale, we'll hit 838 // this recovery path again later 839 return; 840 } 841 // assigning to sService is not thread-safe, but this is best-effort code 842 // and on a well-behaved system should never happen 843 sService = service; 844 try { 845 sTagService = service.getNfcTagInterface(); 846 } catch (RemoteException ee) { 847 Log.e(TAG, "could not retrieve NFC tag service during service recovery"); 848 // nothing more can be done now, sService is still stale, we'll hit 849 // this recovery path again later 850 return; 851 } 852 853 try { 854 sCardEmulationService = service.getNfcCardEmulationInterface(); 855 } catch (RemoteException ee) { 856 Log.e(TAG, "could not retrieve NFC card emulation service during service recovery"); 857 } 858 859 try { 860 sNfcFCardEmulationService = service.getNfcFCardEmulationInterface(); 861 } catch (RemoteException ee) { 862 Log.e(TAG, "could not retrieve NFC-F card emulation service during service recovery"); 863 } 864 865 return; 866 } 867 868 /** 869 * Return true if this NFC Adapter has any features enabled. 870 * 871 * <p>If this method returns false, the NFC hardware is guaranteed not to 872 * generate or respond to any NFC communication over its NFC radio. 873 * <p>Applications can use this to check if NFC is enabled. Applications 874 * can request Settings UI allowing the user to toggle NFC using: 875 * <p><pre>startActivity(new Intent(Settings.ACTION_NFC_SETTINGS))</pre> 876 * 877 * @see android.provider.Settings#ACTION_NFC_SETTINGS 878 * @return true if this NFC Adapter has any features enabled 879 */ isEnabled()880 public boolean isEnabled() { 881 try { 882 return sService.getState() == STATE_ON; 883 } catch (RemoteException e) { 884 attemptDeadServiceRecovery(e); 885 // Try one more time 886 if (sService == null) { 887 Log.e(TAG, "Failed to recover NFC Service."); 888 return false; 889 } 890 try { 891 return sService.getState() == STATE_ON; 892 } catch (RemoteException ee) { 893 Log.e(TAG, "Failed to recover NFC Service."); 894 } 895 return false; 896 } 897 } 898 899 /** 900 * Return the state of this NFC Adapter. 901 * 902 * <p>Returns one of {@link #STATE_ON}, {@link #STATE_TURNING_ON}, 903 * {@link #STATE_OFF}, {@link #STATE_TURNING_OFF}. 904 * 905 * <p>{@link #isEnabled()} is equivalent to 906 * <code>{@link #getAdapterState()} == {@link #STATE_ON}</code> 907 * 908 * @return the current state of this NFC adapter 909 * 910 * @hide 911 */ 912 @UnsupportedAppUsage getAdapterState()913 public int getAdapterState() { 914 try { 915 return sService.getState(); 916 } catch (RemoteException e) { 917 attemptDeadServiceRecovery(e); 918 // Try one more time 919 if (sService == null) { 920 Log.e(TAG, "Failed to recover NFC Service."); 921 return NfcAdapter.STATE_OFF; 922 } 923 try { 924 return sService.getState(); 925 } catch (RemoteException ee) { 926 Log.e(TAG, "Failed to recover NFC Service."); 927 } 928 return NfcAdapter.STATE_OFF; 929 } 930 } 931 932 /** 933 * Enable NFC hardware. 934 * 935 * <p>This call is asynchronous. Listen for 936 * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the 937 * operation is complete. 938 * 939 * <p>If this returns true, then either NFC is already on, or 940 * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent 941 * to indicate a state transition. If this returns false, then 942 * there is some problem that prevents an attempt to turn 943 * NFC on (for example we are in airplane mode and NFC is not 944 * toggleable in airplane mode on this platform). 945 * 946 * @hide 947 */ 948 @SystemApi 949 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) enable()950 public boolean enable() { 951 try { 952 return sService.enable(); 953 } catch (RemoteException e) { 954 attemptDeadServiceRecovery(e); 955 // Try one more time 956 if (sService == null) { 957 Log.e(TAG, "Failed to recover NFC Service."); 958 return false; 959 } 960 try { 961 return sService.enable(); 962 } catch (RemoteException ee) { 963 Log.e(TAG, "Failed to recover NFC Service."); 964 } 965 return false; 966 } 967 } 968 969 /** 970 * Disable NFC hardware. 971 * 972 * <p>No NFC features will work after this call, and the hardware 973 * will not perform or respond to any NFC communication. 974 * 975 * <p>This call is asynchronous. Listen for 976 * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the 977 * operation is complete. 978 * 979 * <p>If this returns true, then either NFC is already off, or 980 * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent 981 * to indicate a state transition. If this returns false, then 982 * there is some problem that prevents an attempt to turn 983 * NFC off. 984 * 985 * @hide 986 */ 987 @SystemApi 988 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) disable()989 public boolean disable() { 990 try { 991 return sService.disable(true); 992 } catch (RemoteException e) { 993 attemptDeadServiceRecovery(e); 994 // Try one more time 995 if (sService == null) { 996 Log.e(TAG, "Failed to recover NFC Service."); 997 return false; 998 } 999 try { 1000 return sService.disable(true); 1001 } catch (RemoteException ee) { 1002 Log.e(TAG, "Failed to recover NFC Service."); 1003 } 1004 return false; 1005 } 1006 } 1007 1008 /** 1009 * Disable NFC hardware. 1010 * @hide 1011 */ 1012 @SystemApi 1013 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) disable(boolean persist)1014 public boolean disable(boolean persist) { 1015 try { 1016 return sService.disable(persist); 1017 } catch (RemoteException e) { 1018 attemptDeadServiceRecovery(e); 1019 // Try one more time 1020 if (sService == null) { 1021 Log.e(TAG, "Failed to recover NFC Service."); 1022 return false; 1023 } 1024 try { 1025 return sService.disable(persist); 1026 } catch (RemoteException ee) { 1027 Log.e(TAG, "Failed to recover NFC Service."); 1028 } 1029 return false; 1030 } 1031 } 1032 1033 /** 1034 * Pauses polling for a {@code timeoutInMs} millis. If polling must be resumed before timeout, 1035 * use {@link #resumePolling()}. 1036 * @hide 1037 */ pausePolling(int timeoutInMs)1038 public void pausePolling(int timeoutInMs) { 1039 try { 1040 sService.pausePolling(timeoutInMs); 1041 } catch (RemoteException e) { 1042 attemptDeadServiceRecovery(e); 1043 } 1044 } 1045 1046 /** 1047 * Resumes default polling for the current device state if polling is paused. Calling 1048 * this while polling is not paused is a no-op. 1049 * 1050 * @hide 1051 */ resumePolling()1052 public void resumePolling() { 1053 try { 1054 sService.resumePolling(); 1055 } catch (RemoteException e) { 1056 attemptDeadServiceRecovery(e); 1057 } 1058 } 1059 1060 /** 1061 * Set one or more {@link Uri}s to send using Android Beam (TM). Every 1062 * Uri you provide must have either scheme 'file' or scheme 'content'. 1063 * 1064 * <p>For the data provided through this method, Android Beam tries to 1065 * switch to alternate transports such as Bluetooth to achieve a fast 1066 * transfer speed. Hence this method is very suitable 1067 * for transferring large files such as pictures or songs. 1068 * 1069 * <p>The receiving side will store the content of each Uri in 1070 * a file and present a notification to the user to open the file 1071 * with a {@link android.content.Intent} with action 1072 * {@link android.content.Intent#ACTION_VIEW}. 1073 * If multiple URIs are sent, the {@link android.content.Intent} will refer 1074 * to the first of the stored files. 1075 * 1076 * <p>This method may be called at any time before {@link Activity#onDestroy}, 1077 * but the URI(s) are only made available for Android Beam when the 1078 * specified activity(s) are in resumed (foreground) state. The recommended 1079 * approach is to call this method during your Activity's 1080 * {@link Activity#onCreate} - see sample 1081 * code below. This method does not immediately perform any I/O or blocking work, 1082 * so is safe to call on your main thread. 1083 * 1084 * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback} 1085 * have priority over both {@link #setNdefPushMessage} and 1086 * {@link #setNdefPushMessageCallback}. 1087 * 1088 * <p>If {@link #setBeamPushUris} is called with a null Uri array, 1089 * and/or {@link #setBeamPushUrisCallback} is called with a null callback, 1090 * then the Uri push will be completely disabled for the specified activity(s). 1091 * 1092 * <p>Code example: 1093 * <pre> 1094 * protected void onCreate(Bundle savedInstanceState) { 1095 * super.onCreate(savedInstanceState); 1096 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 1097 * if (nfcAdapter == null) return; // NFC not available on this device 1098 * nfcAdapter.setBeamPushUris(new Uri[] {uri1, uri2}, this); 1099 * }</pre> 1100 * And that is it. Only one call per activity is necessary. The Android 1101 * OS will automatically release its references to the Uri(s) and the 1102 * Activity object when it is destroyed if you follow this pattern. 1103 * 1104 * <p>If your Activity wants to dynamically supply Uri(s), 1105 * then set a callback using {@link #setBeamPushUrisCallback} instead 1106 * of using this method. 1107 * 1108 * <p class="note">Do not pass in an Activity that has already been through 1109 * {@link Activity#onDestroy}. This is guaranteed if you call this API 1110 * during {@link Activity#onCreate}. 1111 * 1112 * <p class="note">If this device does not support alternate transports 1113 * such as Bluetooth or WiFI, calling this method does nothing. 1114 * 1115 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1116 * 1117 * @param uris an array of Uri(s) to push over Android Beam 1118 * @param activity activity for which the Uri(s) will be pushed 1119 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1120 * @removed this feature is removed. File sharing can work using other technology like 1121 * Bluetooth. 1122 */ 1123 @java.lang.Deprecated 1124 @UnsupportedAppUsage setBeamPushUris(Uri[] uris, Activity activity)1125 public void setBeamPushUris(Uri[] uris, Activity activity) { 1126 synchronized (NfcAdapter.class) { 1127 if (!sHasNfcFeature) { 1128 throw new UnsupportedOperationException(); 1129 } 1130 } 1131 } 1132 1133 /** 1134 * Set a callback that will dynamically generate one or more {@link Uri}s 1135 * to send using Android Beam (TM). Every Uri the callback provides 1136 * must have either scheme 'file' or scheme 'content'. 1137 * 1138 * <p>For the data provided through this callback, Android Beam tries to 1139 * switch to alternate transports such as Bluetooth to achieve a fast 1140 * transfer speed. Hence this method is very suitable 1141 * for transferring large files such as pictures or songs. 1142 * 1143 * <p>The receiving side will store the content of each Uri in 1144 * a file and present a notification to the user to open the file 1145 * with a {@link android.content.Intent} with action 1146 * {@link android.content.Intent#ACTION_VIEW}. 1147 * If multiple URIs are sent, the {@link android.content.Intent} will refer 1148 * to the first of the stored files. 1149 * 1150 * <p>This method may be called at any time before {@link Activity#onDestroy}, 1151 * but the URI(s) are only made available for Android Beam when the 1152 * specified activity(s) are in resumed (foreground) state. The recommended 1153 * approach is to call this method during your Activity's 1154 * {@link Activity#onCreate} - see sample 1155 * code below. This method does not immediately perform any I/O or blocking work, 1156 * so is safe to call on your main thread. 1157 * 1158 * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback} 1159 * have priority over both {@link #setNdefPushMessage} and 1160 * {@link #setNdefPushMessageCallback}. 1161 * 1162 * <p>If {@link #setBeamPushUris} is called with a null Uri array, 1163 * and/or {@link #setBeamPushUrisCallback} is called with a null callback, 1164 * then the Uri push will be completely disabled for the specified activity(s). 1165 * 1166 * <p>Code example: 1167 * <pre> 1168 * protected void onCreate(Bundle savedInstanceState) { 1169 * super.onCreate(savedInstanceState); 1170 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 1171 * if (nfcAdapter == null) return; // NFC not available on this device 1172 * nfcAdapter.setBeamPushUrisCallback(callback, this); 1173 * }</pre> 1174 * And that is it. Only one call per activity is necessary. The Android 1175 * OS will automatically release its references to the Uri(s) and the 1176 * Activity object when it is destroyed if you follow this pattern. 1177 * 1178 * <p class="note">Do not pass in an Activity that has already been through 1179 * {@link Activity#onDestroy}. This is guaranteed if you call this API 1180 * during {@link Activity#onCreate}. 1181 * 1182 * <p class="note">If this device does not support alternate transports 1183 * such as Bluetooth or WiFI, calling this method does nothing. 1184 * 1185 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1186 * 1187 * @param callback callback, or null to disable 1188 * @param activity activity for which the Uri(s) will be pushed 1189 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1190 * @removed this feature is removed. File sharing can work using other technology like 1191 * Bluetooth. 1192 */ 1193 @java.lang.Deprecated 1194 @UnsupportedAppUsage setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity)1195 public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) { 1196 synchronized (NfcAdapter.class) { 1197 if (!sHasNfcFeature) { 1198 throw new UnsupportedOperationException(); 1199 } 1200 } 1201 } 1202 1203 /** 1204 * Set a static {@link NdefMessage} to send using Android Beam (TM). 1205 * 1206 * <p>This method may be called at any time before {@link Activity#onDestroy}, 1207 * but the NDEF message is only made available for NDEF push when the 1208 * specified activity(s) are in resumed (foreground) state. The recommended 1209 * approach is to call this method during your Activity's 1210 * {@link Activity#onCreate} - see sample 1211 * code below. This method does not immediately perform any I/O or blocking work, 1212 * so is safe to call on your main thread. 1213 * 1214 * <p>Only one NDEF message can be pushed by the currently resumed activity. 1215 * If both {@link #setNdefPushMessage} and 1216 * {@link #setNdefPushMessageCallback} are set, then 1217 * the callback will take priority. 1218 * 1219 * <p>If neither {@link #setNdefPushMessage} or 1220 * {@link #setNdefPushMessageCallback} have been called for your activity, then 1221 * the Android OS may choose to send a default NDEF message on your behalf, 1222 * such as a URI for your application. 1223 * 1224 * <p>If {@link #setNdefPushMessage} is called with a null NDEF message, 1225 * and/or {@link #setNdefPushMessageCallback} is called with a null callback, 1226 * then NDEF push will be completely disabled for the specified activity(s). 1227 * This also disables any default NDEF message the Android OS would have 1228 * otherwise sent on your behalf for those activity(s). 1229 * 1230 * <p>If you want to prevent the Android OS from sending default NDEF 1231 * messages completely (for all activities), you can include a 1232 * {@code <meta-data>} element inside the {@code <application>} 1233 * element of your AndroidManifest.xml file, like this: 1234 * <pre> 1235 * <application ...> 1236 * <meta-data android:name="android.nfc.disable_beam_default" 1237 * android:value="true" /> 1238 * </application></pre> 1239 * 1240 * <p>The API allows for multiple activities to be specified at a time, 1241 * but it is strongly recommended to just register one at a time, 1242 * and to do so during the activity's {@link Activity#onCreate}. For example: 1243 * <pre> 1244 * protected void onCreate(Bundle savedInstanceState) { 1245 * super.onCreate(savedInstanceState); 1246 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 1247 * if (nfcAdapter == null) return; // NFC not available on this device 1248 * nfcAdapter.setNdefPushMessage(ndefMessage, this); 1249 * }</pre> 1250 * And that is it. Only one call per activity is necessary. The Android 1251 * OS will automatically release its references to the NDEF message and the 1252 * Activity object when it is destroyed if you follow this pattern. 1253 * 1254 * <p>If your Activity wants to dynamically generate an NDEF message, 1255 * then set a callback using {@link #setNdefPushMessageCallback} instead 1256 * of a static message. 1257 * 1258 * <p class="note">Do not pass in an Activity that has already been through 1259 * {@link Activity#onDestroy}. This is guaranteed if you call this API 1260 * during {@link Activity#onCreate}. 1261 * 1262 * <p class="note">For sending large content such as pictures and songs, 1263 * consider using {@link #setBeamPushUris}, which switches to alternate transports 1264 * such as Bluetooth to achieve a fast transfer rate. 1265 * 1266 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1267 * 1268 * @param message NDEF message to push over NFC, or null to disable 1269 * @param activity activity for which the NDEF message will be pushed 1270 * @param activities optional additional activities, however we strongly recommend 1271 * to only register one at a time, and to do so in that activity's 1272 * {@link Activity#onCreate} 1273 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1274 * @removed this feature is removed. File sharing can work using other technology like 1275 * Bluetooth. 1276 */ 1277 @java.lang.Deprecated 1278 @UnsupportedAppUsage setNdefPushMessage(NdefMessage message, Activity activity, Activity ... activities)1279 public void setNdefPushMessage(NdefMessage message, Activity activity, 1280 Activity ... activities) { 1281 synchronized (NfcAdapter.class) { 1282 if (!sHasNfcFeature) { 1283 throw new UnsupportedOperationException(); 1284 } 1285 } 1286 } 1287 1288 /** 1289 * @hide 1290 * @removed 1291 */ 1292 @SystemApi 1293 @UnsupportedAppUsage setNdefPushMessage(NdefMessage message, Activity activity, int flags)1294 public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) { 1295 synchronized (NfcAdapter.class) { 1296 if (!sHasNfcFeature) { 1297 throw new UnsupportedOperationException(); 1298 } 1299 } 1300 } 1301 1302 /** 1303 * Set a callback that dynamically generates NDEF messages to send using Android Beam (TM). 1304 * 1305 * <p>This method may be called at any time before {@link Activity#onDestroy}, 1306 * but the NDEF message callback can only occur when the 1307 * specified activity(s) are in resumed (foreground) state. The recommended 1308 * approach is to call this method during your Activity's 1309 * {@link Activity#onCreate} - see sample 1310 * code below. This method does not immediately perform any I/O or blocking work, 1311 * so is safe to call on your main thread. 1312 * 1313 * <p>Only one NDEF message can be pushed by the currently resumed activity. 1314 * If both {@link #setNdefPushMessage} and 1315 * {@link #setNdefPushMessageCallback} are set, then 1316 * the callback will take priority. 1317 * 1318 * <p>If neither {@link #setNdefPushMessage} or 1319 * {@link #setNdefPushMessageCallback} have been called for your activity, then 1320 * the Android OS may choose to send a default NDEF message on your behalf, 1321 * such as a URI for your application. 1322 * 1323 * <p>If {@link #setNdefPushMessage} is called with a null NDEF message, 1324 * and/or {@link #setNdefPushMessageCallback} is called with a null callback, 1325 * then NDEF push will be completely disabled for the specified activity(s). 1326 * This also disables any default NDEF message the Android OS would have 1327 * otherwise sent on your behalf for those activity(s). 1328 * 1329 * <p>If you want to prevent the Android OS from sending default NDEF 1330 * messages completely (for all activities), you can include a 1331 * {@code <meta-data>} element inside the {@code <application>} 1332 * element of your AndroidManifest.xml file, like this: 1333 * <pre> 1334 * <application ...> 1335 * <meta-data android:name="android.nfc.disable_beam_default" 1336 * android:value="true" /> 1337 * </application></pre> 1338 * 1339 * <p>The API allows for multiple activities to be specified at a time, 1340 * but it is strongly recommended to just register one at a time, 1341 * and to do so during the activity's {@link Activity#onCreate}. For example: 1342 * <pre> 1343 * protected void onCreate(Bundle savedInstanceState) { 1344 * super.onCreate(savedInstanceState); 1345 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 1346 * if (nfcAdapter == null) return; // NFC not available on this device 1347 * nfcAdapter.setNdefPushMessageCallback(callback, this); 1348 * }</pre> 1349 * And that is it. Only one call per activity is necessary. The Android 1350 * OS will automatically release its references to the callback and the 1351 * Activity object when it is destroyed if you follow this pattern. 1352 * 1353 * <p class="note">Do not pass in an Activity that has already been through 1354 * {@link Activity#onDestroy}. This is guaranteed if you call this API 1355 * during {@link Activity#onCreate}. 1356 * <p class="note">For sending large content such as pictures and songs, 1357 * consider using {@link #setBeamPushUris}, which switches to alternate transports 1358 * such as Bluetooth to achieve a fast transfer rate. 1359 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1360 * 1361 * @param callback callback, or null to disable 1362 * @param activity activity for which the NDEF message will be pushed 1363 * @param activities optional additional activities, however we strongly recommend 1364 * to only register one at a time, and to do so in that activity's 1365 * {@link Activity#onCreate} 1366 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1367 * @removed this feature is removed. File sharing can work using other technology like 1368 * Bluetooth. 1369 */ 1370 @java.lang.Deprecated 1371 @UnsupportedAppUsage setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity, Activity ... activities)1372 public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity, 1373 Activity ... activities) { 1374 synchronized (NfcAdapter.class) { 1375 if (!sHasNfcFeature) { 1376 throw new UnsupportedOperationException(); 1377 } 1378 } 1379 } 1380 1381 /** 1382 * Set a callback on successful Android Beam (TM). 1383 * 1384 * <p>This method may be called at any time before {@link Activity#onDestroy}, 1385 * but the callback can only occur when the 1386 * specified activity(s) are in resumed (foreground) state. The recommended 1387 * approach is to call this method during your Activity's 1388 * {@link Activity#onCreate} - see sample 1389 * code below. This method does not immediately perform any I/O or blocking work, 1390 * so is safe to call on your main thread. 1391 * 1392 * <p>The API allows for multiple activities to be specified at a time, 1393 * but it is strongly recommended to just register one at a time, 1394 * and to do so during the activity's {@link Activity#onCreate}. For example: 1395 * <pre> 1396 * protected void onCreate(Bundle savedInstanceState) { 1397 * super.onCreate(savedInstanceState); 1398 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 1399 * if (nfcAdapter == null) return; // NFC not available on this device 1400 * nfcAdapter.setOnNdefPushCompleteCallback(callback, this); 1401 * }</pre> 1402 * And that is it. Only one call per activity is necessary. The Android 1403 * OS will automatically release its references to the callback and the 1404 * Activity object when it is destroyed if you follow this pattern. 1405 * 1406 * <p class="note">Do not pass in an Activity that has already been through 1407 * {@link Activity#onDestroy}. This is guaranteed if you call this API 1408 * during {@link Activity#onCreate}. 1409 * 1410 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1411 * 1412 * @param callback callback, or null to disable 1413 * @param activity activity for which the NDEF message will be pushed 1414 * @param activities optional additional activities, however we strongly recommend 1415 * to only register one at a time, and to do so in that activity's 1416 * {@link Activity#onCreate} 1417 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1418 * @removed this feature is removed. File sharing can work using other technology like 1419 * Bluetooth. 1420 */ 1421 @java.lang.Deprecated 1422 @UnsupportedAppUsage setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback, Activity activity, Activity ... activities)1423 public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback, 1424 Activity activity, Activity ... activities) { 1425 synchronized (NfcAdapter.class) { 1426 if (!sHasNfcFeature) { 1427 throw new UnsupportedOperationException(); 1428 } 1429 } 1430 } 1431 1432 /** 1433 * Enable foreground dispatch to the given Activity. 1434 * 1435 * <p>This will give priority to the foreground activity when 1436 * dispatching a discovered {@link Tag} to an application. 1437 * 1438 * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents 1439 * for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and 1440 * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED} 1441 * relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled 1442 * by passing in the tech lists separately. Each first level entry in the tech list represents 1443 * an array of technologies that must all be present to match. If any of the first level sets 1444 * match then the dispatch is routed through the given PendingIntent. In other words, the second 1445 * level is ANDed together and the first level entries are ORed together. 1446 * 1447 * <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters 1448 * that acts a wild card and will cause the foreground activity to receive all tags via the 1449 * {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent. 1450 * 1451 * <p>This method must be called from the main thread, and only when the activity is in the 1452 * foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before 1453 * the completion of their {@link Activity#onPause} callback to disable foreground dispatch 1454 * after it has been enabled. 1455 * 1456 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1457 * 1458 * @param activity the Activity to dispatch to 1459 * @param intent the PendingIntent to start for the dispatch 1460 * @param filters the IntentFilters to override dispatching for, or null to always dispatch 1461 * @param techLists the tech lists used to perform matching for dispatching of the 1462 * {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent 1463 * @throws IllegalStateException if the Activity is not currently in the foreground 1464 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1465 */ enableForegroundDispatch(Activity activity, PendingIntent intent, IntentFilter[] filters, String[][] techLists)1466 public void enableForegroundDispatch(Activity activity, PendingIntent intent, 1467 IntentFilter[] filters, String[][] techLists) { 1468 synchronized (NfcAdapter.class) { 1469 if (!sHasNfcFeature) { 1470 throw new UnsupportedOperationException(); 1471 } 1472 } 1473 if (activity == null || intent == null) { 1474 throw new NullPointerException(); 1475 } 1476 if (!activity.isResumed()) { 1477 throw new IllegalStateException("Foreground dispatch can only be enabled " + 1478 "when your activity is resumed"); 1479 } 1480 try { 1481 TechListParcel parcel = null; 1482 if (techLists != null && techLists.length > 0) { 1483 parcel = new TechListParcel(techLists); 1484 } 1485 ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity, 1486 mForegroundDispatchListener); 1487 sService.setForegroundDispatch(intent, filters, parcel); 1488 } catch (RemoteException e) { 1489 attemptDeadServiceRecovery(e); 1490 } 1491 } 1492 1493 /** 1494 * Disable foreground dispatch to the given activity. 1495 * 1496 * <p>After calling {@link #enableForegroundDispatch}, an activity 1497 * must call this method before its {@link Activity#onPause} callback 1498 * completes. 1499 * 1500 * <p>This method must be called from the main thread. 1501 * 1502 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1503 * 1504 * @param activity the Activity to disable dispatch to 1505 * @throws IllegalStateException if the Activity has already been paused 1506 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1507 */ disableForegroundDispatch(Activity activity)1508 public void disableForegroundDispatch(Activity activity) { 1509 synchronized (NfcAdapter.class) { 1510 if (!sHasNfcFeature) { 1511 throw new UnsupportedOperationException(); 1512 } 1513 } 1514 ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity, 1515 mForegroundDispatchListener); 1516 disableForegroundDispatchInternal(activity, false); 1517 } 1518 1519 OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() { 1520 @Override 1521 public void onPaused(Activity activity) { 1522 disableForegroundDispatchInternal(activity, true); 1523 } 1524 }; 1525 disableForegroundDispatchInternal(Activity activity, boolean force)1526 void disableForegroundDispatchInternal(Activity activity, boolean force) { 1527 try { 1528 sService.setForegroundDispatch(null, null, null); 1529 if (!force && !activity.isResumed()) { 1530 throw new IllegalStateException("You must disable foreground dispatching " + 1531 "while your activity is still resumed"); 1532 } 1533 } catch (RemoteException e) { 1534 attemptDeadServiceRecovery(e); 1535 } 1536 } 1537 1538 /** 1539 * Limit the NFC controller to reader mode while this Activity is in the foreground. 1540 * 1541 * <p>In this mode the NFC controller will only act as an NFC tag reader/writer, 1542 * thus disabling any peer-to-peer (Android Beam) and card-emulation modes of 1543 * the NFC adapter on this device. 1544 * 1545 * <p>Use {@link #FLAG_READER_SKIP_NDEF_CHECK} to prevent the platform from 1546 * performing any NDEF checks in reader mode. Note that this will prevent the 1547 * {@link Ndef} tag technology from being enumerated on the tag, and that 1548 * NDEF-based tag dispatch will not be functional. 1549 * 1550 * <p>For interacting with tags that are emulated on another Android device 1551 * using Android's host-based card-emulation, the recommended flags are 1552 * {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}. 1553 * 1554 * @param activity the Activity that requests the adapter to be in reader mode 1555 * @param callback the callback to be called when a tag is discovered 1556 * @param flags Flags indicating poll technologies and other optional parameters 1557 * @param extras Additional extras for configuring reader mode. 1558 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1559 */ enableReaderMode(Activity activity, ReaderCallback callback, int flags, Bundle extras)1560 public void enableReaderMode(Activity activity, ReaderCallback callback, int flags, 1561 Bundle extras) { 1562 synchronized (NfcAdapter.class) { 1563 if (!sHasNfcFeature) { 1564 throw new UnsupportedOperationException(); 1565 } 1566 } 1567 mNfcActivityManager.enableReaderMode(activity, callback, flags, extras); 1568 } 1569 1570 /** 1571 * Restore the NFC adapter to normal mode of operation: supporting 1572 * peer-to-peer (Android Beam), card emulation, and polling for 1573 * all supported tag technologies. 1574 * 1575 * @param activity the Activity that currently has reader mode enabled 1576 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1577 */ disableReaderMode(Activity activity)1578 public void disableReaderMode(Activity activity) { 1579 synchronized (NfcAdapter.class) { 1580 if (!sHasNfcFeature) { 1581 throw new UnsupportedOperationException(); 1582 } 1583 } 1584 mNfcActivityManager.disableReaderMode(activity); 1585 } 1586 1587 /** 1588 * Manually invoke Android Beam to share data. 1589 * 1590 * <p>The Android Beam animation is normally only shown when two NFC-capable 1591 * devices come into range. 1592 * By calling this method, an Activity can invoke the Beam animation directly 1593 * even if no other NFC device is in range yet. The Beam animation will then 1594 * prompt the user to tap another NFC-capable device to complete the data 1595 * transfer. 1596 * 1597 * <p>The main advantage of using this method is that it avoids the need for the 1598 * user to tap the screen to complete the transfer, as this method already 1599 * establishes the direction of the transfer and the consent of the user to 1600 * share data. Callers are responsible for making sure that the user has 1601 * consented to sharing data on NFC tap. 1602 * 1603 * <p>Note that to use this method, the passed in Activity must have already 1604 * set data to share over Beam by using method calls such as 1605 * {@link #setNdefPushMessageCallback} or 1606 * {@link #setBeamPushUrisCallback}. 1607 * 1608 * @param activity the current foreground Activity that has registered data to share 1609 * @return whether the Beam animation was successfully invoked 1610 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1611 * @removed this feature is removed. File sharing can work using other technology like 1612 * Bluetooth. 1613 */ 1614 @java.lang.Deprecated 1615 @UnsupportedAppUsage invokeBeam(Activity activity)1616 public boolean invokeBeam(Activity activity) { 1617 synchronized (NfcAdapter.class) { 1618 if (!sHasNfcFeature) { 1619 throw new UnsupportedOperationException(); 1620 } 1621 } 1622 return false; 1623 } 1624 1625 /** 1626 * Enable NDEF message push over NFC while this Activity is in the foreground. 1627 * 1628 * <p>You must explicitly call this method every time the activity is 1629 * resumed, and you must call {@link #disableForegroundNdefPush} before 1630 * your activity completes {@link Activity#onPause}. 1631 * 1632 * <p>Strongly recommend to use the new {@link #setNdefPushMessage} 1633 * instead: it automatically hooks into your activity life-cycle, 1634 * so you do not need to call enable/disable in your onResume/onPause. 1635 * 1636 * <p>For NDEF push to function properly the other NFC device must 1637 * support either NFC Forum's SNEP (Simple Ndef Exchange Protocol), or 1638 * Android's "com.android.npp" (Ndef Push Protocol). This was optional 1639 * on Gingerbread level Android NFC devices, but SNEP is mandatory on 1640 * Ice-Cream-Sandwich and beyond. 1641 * 1642 * <p>This method must be called from the main thread. 1643 * 1644 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1645 * 1646 * @param activity foreground activity 1647 * @param message a NDEF Message to push over NFC 1648 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable 1649 * @removed this feature is removed. File sharing can work using other technology like 1650 * Bluetooth. 1651 */ 1652 @Deprecated 1653 @UnsupportedAppUsage enableForegroundNdefPush(Activity activity, NdefMessage message)1654 public void enableForegroundNdefPush(Activity activity, NdefMessage message) { 1655 synchronized (NfcAdapter.class) { 1656 if (!sHasNfcFeature) { 1657 throw new UnsupportedOperationException(); 1658 } 1659 } 1660 } 1661 1662 /** 1663 * Disable NDEF message push over P2P. 1664 * 1665 * <p>After calling {@link #enableForegroundNdefPush}, an activity 1666 * must call this method before its {@link Activity#onPause} callback 1667 * completes. 1668 * 1669 * <p>Strongly recommend to use the new {@link #setNdefPushMessage} 1670 * instead: it automatically hooks into your activity life-cycle, 1671 * so you do not need to call enable/disable in your onResume/onPause. 1672 * 1673 * <p>This method must be called from the main thread. 1674 * 1675 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1676 * 1677 * @param activity the Foreground activity 1678 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable 1679 * @removed this feature is removed. File sharing can work using other technology like 1680 * Bluetooth. 1681 */ 1682 @Deprecated 1683 @UnsupportedAppUsage disableForegroundNdefPush(Activity activity)1684 public void disableForegroundNdefPush(Activity activity) { 1685 synchronized (NfcAdapter.class) { 1686 if (!sHasNfcFeature) { 1687 throw new UnsupportedOperationException(); 1688 } 1689 } 1690 } 1691 1692 /** 1693 * Sets Secure NFC feature. 1694 * <p>This API is for the Settings application. 1695 * @return True if successful 1696 * @hide 1697 */ 1698 @SystemApi 1699 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) enableSecureNfc(boolean enable)1700 public boolean enableSecureNfc(boolean enable) { 1701 if (!sHasNfcFeature && !sHasCeFeature) { 1702 throw new UnsupportedOperationException(); 1703 } 1704 try { 1705 return sService.setNfcSecure(enable); 1706 } catch (RemoteException e) { 1707 attemptDeadServiceRecovery(e); 1708 // Try one more time 1709 if (sService == null) { 1710 Log.e(TAG, "Failed to recover NFC Service."); 1711 return false; 1712 } 1713 try { 1714 return sService.setNfcSecure(enable); 1715 } catch (RemoteException ee) { 1716 Log.e(TAG, "Failed to recover NFC Service."); 1717 } 1718 return false; 1719 } 1720 } 1721 1722 /** 1723 * Checks if the device supports Secure NFC functionality. 1724 * 1725 * @return True if device supports Secure NFC, false otherwise 1726 * @throws UnsupportedOperationException if FEATURE_NFC, 1727 * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 1728 * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE 1729 * are unavailable 1730 */ isSecureNfcSupported()1731 public boolean isSecureNfcSupported() { 1732 if (!sHasNfcFeature && !sHasCeFeature) { 1733 throw new UnsupportedOperationException(); 1734 } 1735 try { 1736 return sService.deviceSupportsNfcSecure(); 1737 } catch (RemoteException e) { 1738 attemptDeadServiceRecovery(e); 1739 // Try one more time 1740 if (sService == null) { 1741 Log.e(TAG, "Failed to recover NFC Service."); 1742 return false; 1743 } 1744 try { 1745 return sService.deviceSupportsNfcSecure(); 1746 } catch (RemoteException ee) { 1747 Log.e(TAG, "Failed to recover NFC Service."); 1748 } 1749 return false; 1750 } 1751 } 1752 1753 /** 1754 * Returns information regarding Nfc antennas on the device 1755 * such as their relative positioning on the device. 1756 * 1757 * @return Information on the nfc antenna(s) on the device. 1758 * @throws UnsupportedOperationException if FEATURE_NFC, 1759 * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 1760 * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE 1761 * are unavailable 1762 */ 1763 @Nullable getNfcAntennaInfo()1764 public NfcAntennaInfo getNfcAntennaInfo() { 1765 if (!sHasNfcFeature && !sHasCeFeature) { 1766 throw new UnsupportedOperationException(); 1767 } 1768 try { 1769 return sService.getNfcAntennaInfo(); 1770 } catch (RemoteException e) { 1771 attemptDeadServiceRecovery(e); 1772 // Try one more time 1773 if (sService == null) { 1774 Log.e(TAG, "Failed to recover NFC Service."); 1775 return null; 1776 } 1777 try { 1778 return sService.getNfcAntennaInfo(); 1779 } catch (RemoteException ee) { 1780 Log.e(TAG, "Failed to recover NFC Service."); 1781 } 1782 return null; 1783 } 1784 } 1785 1786 /** 1787 * Checks Secure NFC feature is enabled. 1788 * 1789 * @return True if Secure NFC is enabled, false otherwise 1790 * @throws UnsupportedOperationException if FEATURE_NFC, 1791 * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 1792 * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE 1793 * are unavailable 1794 * @throws UnsupportedOperationException if device doesn't support 1795 * Secure NFC functionality. {@link #isSecureNfcSupported} 1796 */ isSecureNfcEnabled()1797 public boolean isSecureNfcEnabled() { 1798 if (!sHasNfcFeature && !sHasCeFeature) { 1799 throw new UnsupportedOperationException(); 1800 } 1801 try { 1802 return sService.isNfcSecureEnabled(); 1803 } catch (RemoteException e) { 1804 attemptDeadServiceRecovery(e); 1805 // Try one more time 1806 if (sService == null) { 1807 Log.e(TAG, "Failed to recover NFC Service."); 1808 return false; 1809 } 1810 try { 1811 return sService.isNfcSecureEnabled(); 1812 } catch (RemoteException ee) { 1813 Log.e(TAG, "Failed to recover NFC Service."); 1814 } 1815 return false; 1816 } 1817 } 1818 1819 /** 1820 * Enable NDEF Push feature. 1821 * <p>This API is for the Settings application. 1822 * @hide 1823 * @removed 1824 */ 1825 @SystemApi 1826 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 1827 @UnsupportedAppUsage enableNdefPush()1828 public boolean enableNdefPush() { 1829 return false; 1830 } 1831 1832 /** 1833 * Disable NDEF Push feature. 1834 * <p>This API is for the Settings application. 1835 * @hide 1836 * @removed 1837 */ 1838 @SystemApi 1839 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 1840 @UnsupportedAppUsage disableNdefPush()1841 public boolean disableNdefPush() { 1842 return false; 1843 } 1844 1845 /** 1846 * Return true if the NDEF Push (Android Beam) feature is enabled. 1847 * <p>This function will return true only if both NFC is enabled, and the 1848 * NDEF Push feature is enabled. 1849 * <p>Note that if NFC is enabled but NDEF Push is disabled then this 1850 * device can still <i>receive</i> NDEF messages, it just cannot send them. 1851 * <p>Applications cannot directly toggle the NDEF Push feature, but they 1852 * can request Settings UI allowing the user to toggle NDEF Push using 1853 * <code>startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS))</code> 1854 * <p>Example usage in an Activity that requires NDEF Push: 1855 * <p><pre> 1856 * protected void onResume() { 1857 * super.onResume(); 1858 * if (!nfcAdapter.isEnabled()) { 1859 * startActivity(new Intent(Settings.ACTION_NFC_SETTINGS)); 1860 * } else if (!nfcAdapter.isNdefPushEnabled()) { 1861 * startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS)); 1862 * } 1863 * }</pre> 1864 * 1865 * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS 1866 * @return true if NDEF Push feature is enabled 1867 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable. 1868 * @removed this feature is removed. File sharing can work using other technology like 1869 * Bluetooth. 1870 */ 1871 @java.lang.Deprecated 1872 @UnsupportedAppUsage isNdefPushEnabled()1873 public boolean isNdefPushEnabled() { 1874 synchronized (NfcAdapter.class) { 1875 if (!sHasNfcFeature) { 1876 throw new UnsupportedOperationException(); 1877 } 1878 } 1879 return false; 1880 } 1881 1882 /** 1883 * Signals that you are no longer interested in communicating with an NFC tag 1884 * for as long as it remains in range. 1885 * 1886 * All future attempted communication to this tag will fail with {@link IOException}. 1887 * The NFC controller will be put in a low-power polling mode, allowing the device 1888 * to save power in cases where it's "attached" to a tag all the time (e.g. a tag in 1889 * car dock). 1890 * 1891 * Additionally the debounceMs parameter allows you to specify for how long the tag needs 1892 * to have gone out of range, before it will be dispatched again. 1893 * 1894 * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms). 1895 * This means that if the tag repeatedly goes in and out of range (for example, in 1896 * case of a flaky connection), and the controller happens to poll every time the 1897 * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag 1898 * having been "in range" during the interval. 1899 * 1900 * Note 2: if a tag with another UID is detected after this API is called, its effect 1901 * will be cancelled; if this tag shows up before the amount of time specified in 1902 * debounceMs, it will be dispatched again. 1903 * 1904 * Note 3: some tags have a random UID, in which case this API won't work reliably. 1905 * 1906 * @param tag the {@link android.nfc.Tag Tag} to ignore. 1907 * @param debounceMs minimum amount of time the tag needs to be out of range before being 1908 * dispatched again. 1909 * @param tagRemovedListener listener to be called when the tag is removed from the field. 1910 * Note that this will only be called if the tag has been out of range 1911 * for at least debounceMs, or if another tag came into range before 1912 * debounceMs. May be null in case you don't want a callback. 1913 * @param handler the {@link android.os.Handler Handler} that will be used for delivering 1914 * the callback. if the handler is null, then the thread used for delivering 1915 * the callback is unspecified. 1916 * @return false if the tag couldn't be found (or has already gone out of range), true otherwise 1917 */ ignore(final Tag tag, int debounceMs, final OnTagRemovedListener tagRemovedListener, final Handler handler)1918 public boolean ignore(final Tag tag, int debounceMs, 1919 final OnTagRemovedListener tagRemovedListener, final Handler handler) { 1920 ITagRemovedCallback.Stub iListener = null; 1921 if (tagRemovedListener != null) { 1922 iListener = new ITagRemovedCallback.Stub() { 1923 @Override 1924 public void onTagRemoved() throws RemoteException { 1925 if (handler != null) { 1926 handler.post(new Runnable() { 1927 @Override 1928 public void run() { 1929 tagRemovedListener.onTagRemoved(); 1930 } 1931 }); 1932 } else { 1933 tagRemovedListener.onTagRemoved(); 1934 } 1935 synchronized (mLock) { 1936 mTagRemovedListener = null; 1937 } 1938 } 1939 }; 1940 } 1941 synchronized (mLock) { 1942 mTagRemovedListener = iListener; 1943 } 1944 try { 1945 return sService.ignore(tag.getServiceHandle(), debounceMs, iListener); 1946 } catch (RemoteException e) { 1947 return false; 1948 } 1949 } 1950 1951 /** 1952 * Inject a mock NFC tag.<p> 1953 * Used for testing purposes. 1954 * <p class="note">Requires the 1955 * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 1956 * @hide 1957 */ dispatch(Tag tag)1958 public void dispatch(Tag tag) { 1959 if (tag == null) { 1960 throw new NullPointerException("tag cannot be null"); 1961 } 1962 try { 1963 sService.dispatch(tag); 1964 } catch (RemoteException e) { 1965 attemptDeadServiceRecovery(e); 1966 } 1967 } 1968 1969 /** 1970 * Registers a new NFC unlock handler with the NFC service. 1971 * 1972 * <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted 1973 * NFC device. The handler should return true if it successfully authenticates the user and 1974 * unlocks the keyguard. 1975 * 1976 * <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for 1977 * at the lockscreen. Polling for less tag technologies reduces latency, and so it is 1978 * strongly recommended to only provide the Tag technologies that the handler is expected to 1979 * receive. There must be at least one tag technology provided, otherwise the unlock handler 1980 * is ignored. 1981 * 1982 * @hide 1983 */ 1984 @SystemApi 1985 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) addNfcUnlockHandler(final NfcUnlockHandler unlockHandler, String[] tagTechnologies)1986 public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler, 1987 String[] tagTechnologies) { 1988 synchronized (NfcAdapter.class) { 1989 if (!sHasNfcFeature) { 1990 throw new UnsupportedOperationException(); 1991 } 1992 } 1993 // If there are no tag technologies, don't bother adding unlock handler 1994 if (tagTechnologies.length == 0) { 1995 return false; 1996 } 1997 1998 try { 1999 synchronized (mLock) { 2000 if (mNfcUnlockHandlers.containsKey(unlockHandler)) { 2001 // update the tag technologies 2002 sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler)); 2003 mNfcUnlockHandlers.remove(unlockHandler); 2004 } 2005 2006 INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() { 2007 @Override 2008 public boolean onUnlockAttempted(Tag tag) throws RemoteException { 2009 return unlockHandler.onUnlockAttempted(tag); 2010 } 2011 }; 2012 2013 sService.addNfcUnlockHandler(iHandler, 2014 Tag.getTechCodesFromStrings(tagTechnologies)); 2015 mNfcUnlockHandlers.put(unlockHandler, iHandler); 2016 } 2017 } catch (RemoteException e) { 2018 attemptDeadServiceRecovery(e); 2019 return false; 2020 } catch (IllegalArgumentException e) { 2021 Log.e(TAG, "Unable to register LockscreenDispatch", e); 2022 return false; 2023 } 2024 2025 return true; 2026 } 2027 2028 /** 2029 * Removes a previously registered unlock handler. Also removes the tag technologies 2030 * associated with the removed unlock handler. 2031 * 2032 * @hide 2033 */ 2034 @SystemApi 2035 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) removeNfcUnlockHandler(NfcUnlockHandler unlockHandler)2036 public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) { 2037 synchronized (NfcAdapter.class) { 2038 if (!sHasNfcFeature) { 2039 throw new UnsupportedOperationException(); 2040 } 2041 } 2042 try { 2043 synchronized (mLock) { 2044 if (mNfcUnlockHandlers.containsKey(unlockHandler)) { 2045 sService.removeNfcUnlockHandler(mNfcUnlockHandlers.remove(unlockHandler)); 2046 } 2047 2048 return true; 2049 } 2050 } catch (RemoteException e) { 2051 attemptDeadServiceRecovery(e); 2052 return false; 2053 } 2054 } 2055 2056 /** 2057 * @hide 2058 */ 2059 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getNfcAdapterExtrasInterface()2060 public INfcAdapterExtras getNfcAdapterExtrasInterface() { 2061 if (mContext == null) { 2062 throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " 2063 + " NFC extras APIs"); 2064 } 2065 try { 2066 return sService.getNfcAdapterExtrasInterface(mContext.getPackageName()); 2067 } catch (RemoteException e) { 2068 attemptDeadServiceRecovery(e); 2069 // Try one more time 2070 if (sService == null) { 2071 Log.e(TAG, "Failed to recover NFC Service."); 2072 return null; 2073 } 2074 try { 2075 return sService.getNfcAdapterExtrasInterface(mContext.getPackageName()); 2076 } catch (RemoteException ee) { 2077 Log.e(TAG, "Failed to recover NFC Service."); 2078 } 2079 return null; 2080 } 2081 } 2082 enforceResumed(Activity activity)2083 void enforceResumed(Activity activity) { 2084 if (!activity.isResumed()) { 2085 throw new IllegalStateException("API cannot be called while activity is paused"); 2086 } 2087 } 2088 getSdkVersion()2089 int getSdkVersion() { 2090 if (mContext == null) { 2091 return android.os.Build.VERSION_CODES.GINGERBREAD; // best guess 2092 } else { 2093 return mContext.getApplicationInfo().targetSdkVersion; 2094 } 2095 } 2096 2097 /** 2098 * Sets NFC controller always on feature. 2099 * <p>This API is for the NFCC internal state management. It allows to discriminate 2100 * the controller function from the NFC function by keeping the NFC controller on without 2101 * any NFC RF enabled if necessary. 2102 * <p>This call is asynchronous. Register a listener {@link #ControllerAlwaysOnListener} 2103 * by {@link #registerControllerAlwaysOnListener} to find out when the operation is 2104 * complete. 2105 * <p>If this returns true, then either NFCC always on state has been set based on the value, 2106 * or a {@link ControllerAlwaysOnListener#onControllerAlwaysOnChanged(boolean)} will be invoked 2107 * to indicate the state change. 2108 * If this returns false, then there is some problem that prevents an attempt to turn NFCC 2109 * always on. 2110 * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is 2111 * disabled), if false the NFCC will follow completely the Nfc adapter state. 2112 * @throws UnsupportedOperationException if FEATURE_NFC, 2113 * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 2114 * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE 2115 * are unavailable 2116 * @return void 2117 * @hide 2118 */ 2119 @SystemApi 2120 @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) setControllerAlwaysOn(boolean value)2121 public boolean setControllerAlwaysOn(boolean value) { 2122 if (!sHasNfcFeature && !sHasCeFeature) { 2123 throw new UnsupportedOperationException(); 2124 } 2125 try { 2126 return sService.setControllerAlwaysOn(value); 2127 } catch (RemoteException e) { 2128 attemptDeadServiceRecovery(e); 2129 // Try one more time 2130 if (sService == null) { 2131 Log.e(TAG, "Failed to recover NFC Service."); 2132 return false; 2133 } 2134 try { 2135 return sService.setControllerAlwaysOn(value); 2136 } catch (RemoteException ee) { 2137 Log.e(TAG, "Failed to recover NFC Service."); 2138 } 2139 return false; 2140 } 2141 } 2142 2143 /** 2144 * Checks NFC controller always on feature is enabled. 2145 * 2146 * @return True if NFC controller always on is enabled, false otherwise 2147 * @throws UnsupportedOperationException if FEATURE_NFC, 2148 * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 2149 * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE 2150 * are unavailable 2151 * @hide 2152 */ 2153 @SystemApi 2154 @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) isControllerAlwaysOn()2155 public boolean isControllerAlwaysOn() { 2156 try { 2157 return sService.isControllerAlwaysOn(); 2158 } catch (RemoteException e) { 2159 attemptDeadServiceRecovery(e); 2160 // Try one more time 2161 if (sService == null) { 2162 Log.e(TAG, "Failed to recover NFC Service."); 2163 return false; 2164 } 2165 try { 2166 return sService.isControllerAlwaysOn(); 2167 } catch (RemoteException ee) { 2168 Log.e(TAG, "Failed to recover NFC Service."); 2169 } 2170 return false; 2171 } 2172 } 2173 2174 /** 2175 * Checks if the device supports NFC controller always on functionality. 2176 * 2177 * @return True if device supports NFC controller always on, false otherwise 2178 * @throws UnsupportedOperationException if FEATURE_NFC, 2179 * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 2180 * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE 2181 * are unavailable 2182 * @hide 2183 */ 2184 @SystemApi 2185 @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) isControllerAlwaysOnSupported()2186 public boolean isControllerAlwaysOnSupported() { 2187 if (!sHasNfcFeature && !sHasCeFeature) { 2188 throw new UnsupportedOperationException(); 2189 } 2190 try { 2191 return sService.isControllerAlwaysOnSupported(); 2192 } catch (RemoteException e) { 2193 attemptDeadServiceRecovery(e); 2194 // Try one more time 2195 if (sService == null) { 2196 Log.e(TAG, "Failed to recover NFC Service."); 2197 return false; 2198 } 2199 try { 2200 return sService.isControllerAlwaysOnSupported(); 2201 } catch (RemoteException ee) { 2202 Log.e(TAG, "Failed to recover NFC Service."); 2203 } 2204 return false; 2205 } 2206 } 2207 2208 /** 2209 * Register a {@link ControllerAlwaysOnListener} to listen for NFC controller always on 2210 * state changes 2211 * <p>The provided listener will be invoked by the given {@link Executor}. 2212 * 2213 * @param executor an {@link Executor} to execute given listener 2214 * @param listener user implementation of the {@link ControllerAlwaysOnListener} 2215 * @hide 2216 */ 2217 @SystemApi 2218 @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) registerControllerAlwaysOnListener( @onNull @allbackExecutor Executor executor, @NonNull ControllerAlwaysOnListener listener)2219 public void registerControllerAlwaysOnListener( 2220 @NonNull @CallbackExecutor Executor executor, 2221 @NonNull ControllerAlwaysOnListener listener) { 2222 mControllerAlwaysOnListener.register(executor, listener); 2223 } 2224 2225 /** 2226 * Unregister the specified {@link ControllerAlwaysOnListener} 2227 * <p>The same {@link ControllerAlwaysOnListener} object used when calling 2228 * {@link #registerControllerAlwaysOnListener(Executor, ControllerAlwaysOnListener)} 2229 * must be used. 2230 * 2231 * <p>Listeners are automatically unregistered when application process goes away 2232 * 2233 * @param listener user implementation of the {@link ControllerAlwaysOnListener} 2234 * @hide 2235 */ 2236 @SystemApi 2237 @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) unregisterControllerAlwaysOnListener( @onNull ControllerAlwaysOnListener listener)2238 public void unregisterControllerAlwaysOnListener( 2239 @NonNull ControllerAlwaysOnListener listener) { 2240 mControllerAlwaysOnListener.unregister(listener); 2241 } 2242 2243 2244 /** 2245 * Sets whether we dispatch NFC Tag intents to the package. 2246 * 2247 * <p>{@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or 2248 * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is 2249 * disallowed. 2250 * <p>An app is added to the preference list with the allowed flag set to {@code true} 2251 * when a Tag intent is dispatched to the package for the first time. This API is called 2252 * by settings to note that the user wants to change this default preference. 2253 * 2254 * @param userId the user to whom this package name will belong to 2255 * @param pkg the full name (i.e. com.google.android.tag) of the package that will be added to 2256 * the preference list 2257 * @param allow {@code true} to allow dispatching Tag intents to the package's activity, 2258 * {@code false} otherwise 2259 * @return the {@link #TagIntentAppPreferenceResult} value 2260 * @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns 2261 * {@code false} 2262 * 2263 * @hide 2264 */ 2265 @SystemApi 2266 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 2267 @TagIntentAppPreferenceResult setTagIntentAppPreferenceForUser(@serIdInt int userId, @NonNull String pkg, boolean allow)2268 public int setTagIntentAppPreferenceForUser(@UserIdInt int userId, 2269 @NonNull String pkg, boolean allow) { 2270 Objects.requireNonNull(pkg, "pkg cannot be null"); 2271 if (!isTagIntentAppPreferenceSupported()) { 2272 Log.e(TAG, "TagIntentAppPreference is not supported"); 2273 throw new UnsupportedOperationException(); 2274 } 2275 try { 2276 return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow); 2277 } catch (RemoteException e) { 2278 attemptDeadServiceRecovery(e); 2279 // Try one more time 2280 if (sService == null) { 2281 Log.e(TAG, "Failed to recover NFC Service."); 2282 } 2283 try { 2284 return sService.setTagIntentAppPreferenceForUser(userId, pkg, allow); 2285 } catch (RemoteException ee) { 2286 Log.e(TAG, "Failed to recover NFC Service."); 2287 } 2288 return TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE; 2289 } 2290 } 2291 2292 2293 /** 2294 * Get the Tag dispatch preference list of the UserId. 2295 * 2296 * <p>This returns a mapping of package names for this user id to whether we dispatch Tag 2297 * intents to the package. {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or 2298 * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is 2299 * mapped to {@code false}. 2300 * <p>There are three different possible cases: 2301 * <p>A package not being in the preference list. 2302 * It does not contain any Tag intent filters or the user never triggers a Tag detection that 2303 * matches the intent filter of the package. 2304 * <p>A package being mapped to {@code true}. 2305 * When a package has been launched by a tag detection for the first time, the package name is 2306 * put to the map and by default mapped to {@code true}. The package will receive Tag intents as 2307 * usual. 2308 * <p>A package being mapped to {@code false}. 2309 * The user chooses to disable this package and it will not receive any Tag intents anymore. 2310 * 2311 * @param userId the user to whom this preference list will belong to 2312 * @return a map of the UserId which indicates the mapping from package name to 2313 * boolean(allow status), otherwise return an empty map 2314 * @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns 2315 * {@code false} 2316 * 2317 * @hide 2318 */ 2319 @SystemApi 2320 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) 2321 @NonNull getTagIntentAppPreferenceForUser(@serIdInt int userId)2322 public Map<String, Boolean> getTagIntentAppPreferenceForUser(@UserIdInt int userId) { 2323 if (!isTagIntentAppPreferenceSupported()) { 2324 Log.e(TAG, "TagIntentAppPreference is not supported"); 2325 throw new UnsupportedOperationException(); 2326 } 2327 try { 2328 Map<String, Boolean> result = (Map<String, Boolean>) sService 2329 .getTagIntentAppPreferenceForUser(userId); 2330 return result; 2331 } catch (RemoteException e) { 2332 attemptDeadServiceRecovery(e); 2333 // Try one more time 2334 if (sService == null) { 2335 Log.e(TAG, "Failed to recover NFC Service."); 2336 return Collections.emptyMap(); 2337 } 2338 try { 2339 Map<String, Boolean> result = (Map<String, Boolean>) sService 2340 .getTagIntentAppPreferenceForUser(userId); 2341 return result; 2342 } catch (RemoteException ee) { 2343 Log.e(TAG, "Failed to recover NFC Service."); 2344 } 2345 return Collections.emptyMap(); 2346 } 2347 } 2348 2349 /** 2350 * Checks if the device supports Tag application preference. 2351 * 2352 * @return {@code true} if the device supports Tag application preference, {@code false} 2353 * otherwise 2354 * @throws UnsupportedOperationException if FEATURE_NFC is unavailable 2355 * 2356 * @hide 2357 */ 2358 @SystemApi 2359 @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) isTagIntentAppPreferenceSupported()2360 public boolean isTagIntentAppPreferenceSupported() { 2361 if (!sHasNfcFeature) { 2362 throw new UnsupportedOperationException(); 2363 } 2364 try { 2365 return sService.isTagIntentAppPreferenceSupported(); 2366 } catch (RemoteException e) { 2367 attemptDeadServiceRecovery(e); 2368 // Try one more time 2369 if (sService == null) { 2370 Log.e(TAG, "Failed to recover NFC Service."); 2371 return false; 2372 } 2373 try { 2374 return sService.isTagIntentAppPreferenceSupported(); 2375 } catch (RemoteException ee) { 2376 Log.e(TAG, "Failed to recover NFC Service."); 2377 } 2378 return false; 2379 } 2380 } 2381 } 2382