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