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