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 17package android.nfc; 18 19import java.util.HashMap; 20 21import android.annotation.SdkConstant; 22import android.annotation.SdkConstant.SdkConstantType; 23import android.app.Activity; 24import android.app.ActivityThread; 25import android.app.OnActivityPausedListener; 26import android.app.PendingIntent; 27import android.content.Context; 28import android.content.IntentFilter; 29import android.content.pm.IPackageManager; 30import android.content.pm.PackageManager; 31import android.net.Uri; 32import android.nfc.tech.MifareClassic; 33import android.nfc.tech.Ndef; 34import android.nfc.tech.NfcA; 35import android.nfc.tech.NfcF; 36import android.os.Bundle; 37import android.os.IBinder; 38import android.os.RemoteException; 39import android.os.ServiceManager; 40import android.util.Log; 41 42/** 43 * Represents the local NFC adapter. 44 * <p> 45 * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC 46 * adapter for this Android device. 47 * 48 * <div class="special reference"> 49 * <h3>Developer Guides</h3> 50 * <p>For more information about using NFC, read the 51 * <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p> 52 * <p>To perform basic file sharing between devices, read 53 * <a href="{@docRoot}training/beam-files/index.html">Sharing Files with NFC</a>. 54 * </div> 55 */ 56public final class NfcAdapter { 57 static final String TAG = "NFC"; 58 59 /** 60 * Intent to start an activity when a tag with NDEF payload is discovered. 61 * 62 * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and 63 * looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the 64 * intent will contain the URI in its data field. If a MIME record is found the intent will 65 * contain the MIME type in its type field. This allows activities to register 66 * {@link IntentFilter}s targeting specific content on tags. Activities should register the 67 * most specific intent filters possible to avoid the activity chooser dialog, which can 68 * disrupt the interaction with the tag as the user interacts with the screen. 69 * 70 * <p>If the tag has an NDEF payload this intent is started before 71 * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither 72 * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started. 73 * 74 * <p>The MIME type or data URI of this intent are normalized before dispatch - 75 * so that MIME, URI scheme and URI host are always lower-case. 76 */ 77 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 78 public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"; 79 80 /** 81 * Intent to start an activity when a tag is discovered and activities are registered for the 82 * specific technologies on the tag. 83 * 84 * <p>To receive this intent an activity must include an intent filter 85 * for this action and specify the desired tech types in a 86 * manifest <code>meta-data</code> entry. Here is an example manfiest entry: 87 * <pre> 88 * <activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"> 89 * <!-- Add a technology filter --> 90 * <intent-filter> 91 * <action android:name="android.nfc.action.TECH_DISCOVERED" /> 92 * </intent-filter> 93 * 94 * <meta-data android:name="android.nfc.action.TECH_DISCOVERED" 95 * android:resource="@xml/filter_nfc" 96 * /> 97 * </activity></pre> 98 * 99 * <p>The meta-data XML file should contain one or more <code>tech-list</code> entries 100 * each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer 101 * to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA". 102 * 103 * <p>A tag matches if any of the 104 * <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each 105 * of the <code>tech-list</code>s is considered independently and the 106 * activity is considered a match is any single <code>tech-list</code> matches the tag that was 107 * discovered. This provides AND and OR semantics for filtering desired techs. Here is an 108 * example that will match any tag using {@link NfcF} or any tag using {@link NfcA}, 109 * {@link MifareClassic}, and {@link Ndef}: 110 * 111 * <pre> 112 * <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 113 * <!-- capture anything using NfcF --> 114 * <tech-list> 115 * <tech>android.nfc.tech.NfcF</tech> 116 * </tech-list> 117 * 118 * <!-- OR --> 119 * 120 * <!-- capture all MIFARE Classics with NDEF payloads --> 121 * <tech-list> 122 * <tech>android.nfc.tech.NfcA</tech> 123 * <tech>android.nfc.tech.MifareClassic</tech> 124 * <tech>android.nfc.tech.Ndef</tech> 125 * </tech-list> 126 * </resources></pre> 127 * 128 * <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before 129 * {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED} 130 * this intent will not be started. If any activities respond to this intent 131 * {@link #ACTION_TAG_DISCOVERED} will not be started. 132 */ 133 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 134 public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"; 135 136 /** 137 * Intent to start an activity when a tag is discovered. 138 * 139 * <p>This intent will not be started when a tag is discovered if any activities respond to 140 * {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag. 141 */ 142 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 143 public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"; 144 145 /** 146 * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED 147 * @hide 148 */ 149 public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST"; 150 151 /** 152 * Mandatory extra containing the {@link Tag} that was discovered for the 153 * {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and 154 * {@link #ACTION_TAG_DISCOVERED} intents. 155 */ 156 public static final String EXTRA_TAG = "android.nfc.extra.TAG"; 157 158 /** 159 * Extra containing an array of {@link NdefMessage} present on the discovered tag.<p> 160 * This extra is mandatory for {@link #ACTION_NDEF_DISCOVERED} intents, 161 * and optional for {@link #ACTION_TECH_DISCOVERED}, and 162 * {@link #ACTION_TAG_DISCOVERED} intents.<p> 163 * When this extra is present there will always be at least one 164 * {@link NdefMessage} element. Most NDEF tags have only one NDEF message, 165 * but we use an array for future compatibility. 166 */ 167 public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES"; 168 169 /** 170 * Optional extra containing a byte array containing the ID of the discovered tag for 171 * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and 172 * {@link #ACTION_TAG_DISCOVERED} intents. 173 */ 174 public static final String EXTRA_ID = "android.nfc.extra.ID"; 175 176 /** 177 * Broadcast Action: The state of the local NFC adapter has been 178 * changed. 179 * <p>For example, NFC has been turned on or off. 180 * <p>Always contains the extra field {@link #EXTRA_ADAPTER_STATE} 181 */ 182 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 183 public static final String ACTION_ADAPTER_STATE_CHANGED = 184 "android.nfc.action.ADAPTER_STATE_CHANGED"; 185 186 /** 187 * Used as an int extra field in {@link #ACTION_ADAPTER_STATE_CHANGED} 188 * intents to request the current power state. Possible values are: 189 * {@link #STATE_OFF}, 190 * {@link #STATE_TURNING_ON}, 191 * {@link #STATE_ON}, 192 * {@link #STATE_TURNING_OFF}, 193 */ 194 public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE"; 195 196 public static final int STATE_OFF = 1; 197 public static final int STATE_TURNING_ON = 2; 198 public static final int STATE_ON = 3; 199 public static final int STATE_TURNING_OFF = 4; 200 201 /** 202 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 203 * <p> 204 * Setting this flag enables polling for Nfc-A technology. 205 */ 206 public static final int FLAG_READER_NFC_A = 0x1; 207 208 /** 209 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 210 * <p> 211 * Setting this flag enables polling for Nfc-B technology. 212 */ 213 public static final int FLAG_READER_NFC_B = 0x2; 214 215 /** 216 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 217 * <p> 218 * Setting this flag enables polling for Nfc-F technology. 219 */ 220 public static final int FLAG_READER_NFC_F = 0x4; 221 222 /** 223 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 224 * <p> 225 * Setting this flag enables polling for Nfc-V (ISO15693) technology. 226 */ 227 public static final int FLAG_READER_NFC_V = 0x8; 228 229 /** 230 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 231 * <p> 232 * Setting this flag enables polling for NfcBarcode technology. 233 */ 234 public static final int FLAG_READER_NFC_BARCODE = 0x10; 235 236 /** 237 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 238 * <p> 239 * Setting this flag allows the caller to prevent the 240 * platform from performing an NDEF check on the tags it 241 * finds. 242 */ 243 public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80; 244 245 /** 246 * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 247 * <p> 248 * Setting this flag allows the caller to prevent the 249 * platform from playing sounds when it discovers a tag. 250 */ 251 public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100; 252 253 /** 254 * Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}. 255 * <p> 256 * Setting this integer extra allows the calling application to specify 257 * the delay that the platform will use for performing presence checks 258 * on any discovered tag. 259 */ 260 public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence"; 261 262 /** @hide */ 263 public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1; 264 265 /** @hide */ 266 public static final String ACTION_HANDOVER_TRANSFER_STARTED = 267 "android.nfc.action.HANDOVER_TRANSFER_STARTED"; 268 269 /** @hide */ 270 public static final String ACTION_HANDOVER_TRANSFER_DONE = 271 "android.nfc.action.HANDOVER_TRANSFER_DONE"; 272 273 /** @hide */ 274 public static final String EXTRA_HANDOVER_TRANSFER_STATUS = 275 "android.nfc.extra.HANDOVER_TRANSFER_STATUS"; 276 277 /** @hide */ 278 public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0; 279 /** @hide */ 280 public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1; 281 282 /** @hide */ 283 public static final String EXTRA_HANDOVER_TRANSFER_URI = 284 "android.nfc.extra.HANDOVER_TRANSFER_URI"; 285 286 // Guarded by NfcAdapter.class 287 static boolean sIsInitialized = false; 288 289 // Final after first constructor, except for 290 // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort 291 // recovery 292 static INfcAdapter sService; 293 static INfcTag sTagService; 294 static INfcCardEmulation sCardEmulationService; 295 296 /** 297 * The NfcAdapter object for each application context. 298 * There is a 1-1 relationship between application context and 299 * NfcAdapter object. 300 */ 301 static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class 302 303 /** 304 * NfcAdapter used with a null context. This ctor was deprecated but we have 305 * to support it for backwards compatibility. New methods that require context 306 * might throw when called on the null-context NfcAdapter. 307 */ 308 static NfcAdapter sNullContextNfcAdapter; // protected by NfcAdapter.class 309 310 final NfcActivityManager mNfcActivityManager; 311 final Context mContext; 312 313 /** 314 * A callback to be invoked when the system finds a tag while the foreground activity is 315 * operating in reader mode. 316 * <p>Register your {@code ReaderCallback} implementation with {@link 317 * NfcAdapter#enableReaderMode} and disable it with {@link 318 * NfcAdapter#disableReaderMode}. 319 * @see NfcAdapter#enableReaderMode 320 */ 321 public interface ReaderCallback { 322 public void onTagDiscovered(Tag tag); 323 } 324 325 /** 326 * A callback to be invoked when the system successfully delivers your {@link NdefMessage} 327 * to another device. 328 * @see #setOnNdefPushCompleteCallback 329 */ 330 public interface OnNdefPushCompleteCallback { 331 /** 332 * Called on successful NDEF push. 333 * 334 * <p>This callback is usually made on a binder thread (not the UI thread). 335 * 336 * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set 337 * @see #setNdefPushMessageCallback 338 */ 339 public void onNdefPushComplete(NfcEvent event); 340 } 341 342 /** 343 * A callback to be invoked when another NFC device capable of NDEF push (Android Beam) 344 * is within range. 345 * <p>Implement this interface and pass it to {@link 346 * NfcAdapter#setNdefPushMessageCallback setNdefPushMessageCallback()} in order to create an 347 * {@link NdefMessage} at the moment that another device is within range for NFC. Using this 348 * callback allows you to create a message with data that might vary based on the 349 * content currently visible to the user. Alternatively, you can call {@link 350 * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the 351 * same data. 352 */ 353 public interface CreateNdefMessageCallback { 354 /** 355 * Called to provide a {@link NdefMessage} to push. 356 * 357 * <p>This callback is usually made on a binder thread (not the UI thread). 358 * 359 * <p>Called when this device is in range of another device 360 * that might support NDEF push. It allows the application to 361 * create the NDEF message only when it is required. 362 * 363 * <p>NDEF push cannot occur until this method returns, so do not 364 * block for too long. 365 * 366 * <p>The Android operating system will usually show a system UI 367 * on top of your activity during this time, so do not try to request 368 * input from the user to complete the callback, or provide custom NDEF 369 * push UI. The user probably will not see it. 370 * 371 * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set 372 * @return NDEF message to push, or null to not provide a message 373 */ 374 public NdefMessage createNdefMessage(NfcEvent event); 375 } 376 377 378 // TODO javadoc 379 public interface CreateBeamUrisCallback { 380 public Uri[] createBeamUris(NfcEvent event); 381 } 382 383 /** 384 * Helper to check if this device has FEATURE_NFC, but without using 385 * a context. 386 * Equivalent to 387 * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC) 388 */ 389 private static boolean hasNfcFeature() { 390 IPackageManager pm = ActivityThread.getPackageManager(); 391 if (pm == null) { 392 Log.e(TAG, "Cannot get package manager, assuming no NFC feature"); 393 return false; 394 } 395 try { 396 return pm.hasSystemFeature(PackageManager.FEATURE_NFC); 397 } catch (RemoteException e) { 398 Log.e(TAG, "Package manager query failed, assuming no NFC feature", e); 399 return false; 400 } 401 } 402 403 /** 404 * Returns the NfcAdapter for application context, 405 * or throws if NFC is not available. 406 * @hide 407 */ 408 public static synchronized NfcAdapter getNfcAdapter(Context context) { 409 if (!sIsInitialized) { 410 /* is this device meant to have NFC */ 411 if (!hasNfcFeature()) { 412 Log.v(TAG, "this device does not have NFC support"); 413 throw new UnsupportedOperationException(); 414 } 415 416 sService = getServiceInterface(); 417 if (sService == null) { 418 Log.e(TAG, "could not retrieve NFC service"); 419 throw new UnsupportedOperationException(); 420 } 421 try { 422 sTagService = sService.getNfcTagInterface(); 423 } catch (RemoteException e) { 424 Log.e(TAG, "could not retrieve NFC Tag service"); 425 throw new UnsupportedOperationException(); 426 } 427 428 try { 429 sCardEmulationService = sService.getNfcCardEmulationInterface(); 430 } catch (RemoteException e) { 431 Log.e(TAG, "could not retrieve card emulation service"); 432 throw new UnsupportedOperationException(); 433 } 434 435 sIsInitialized = true; 436 } 437 if (context == null) { 438 if (sNullContextNfcAdapter == null) { 439 sNullContextNfcAdapter = new NfcAdapter(null); 440 } 441 return sNullContextNfcAdapter; 442 } 443 NfcAdapter adapter = sNfcAdapters.get(context); 444 if (adapter == null) { 445 adapter = new NfcAdapter(context); 446 sNfcAdapters.put(context, adapter); 447 } 448 return adapter; 449 } 450 451 /** get handle to NFC service interface */ 452 private static INfcAdapter getServiceInterface() { 453 /* get a handle to NFC service */ 454 IBinder b = ServiceManager.getService("nfc"); 455 if (b == null) { 456 return null; 457 } 458 return INfcAdapter.Stub.asInterface(b); 459 } 460 461 /** 462 * Helper to get the default NFC Adapter. 463 * <p> 464 * Most Android devices will only have one NFC Adapter (NFC Controller). 465 * <p> 466 * This helper is the equivalent of: 467 * <pre> 468 * NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); 469 * NfcAdapter adapter = manager.getDefaultAdapter();</pre> 470 * @param context the calling application's context 471 * 472 * @return the default NFC adapter, or null if no NFC adapter exists 473 */ 474 public static NfcAdapter getDefaultAdapter(Context context) { 475 if (context == null) { 476 throw new IllegalArgumentException("context cannot be null"); 477 } 478 context = context.getApplicationContext(); 479 if (context == null) { 480 throw new IllegalArgumentException( 481 "context not associated with any application (using a mock context?)"); 482 } 483 /* use getSystemService() for consistency */ 484 NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); 485 if (manager == null) { 486 // NFC not available 487 return null; 488 } 489 return manager.getDefaultAdapter(); 490 } 491 492 /** 493 * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p> 494 * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required 495 * for many NFC API methods. Those methods will fail when called on an NfcAdapter 496 * object created from this method.<p> 497 * @deprecated use {@link #getDefaultAdapter(Context)} 498 * @hide 499 */ 500 @Deprecated 501 public static NfcAdapter getDefaultAdapter() { 502 // introduced in API version 9 (GB 2.3) 503 // deprecated in API version 10 (GB 2.3.3) 504 // removed from public API in version 16 (ICS MR2) 505 // should maintain as a hidden API for binary compatibility for a little longer 506 Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " + 507 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception()); 508 509 return NfcAdapter.getNfcAdapter(null); 510 } 511 512 NfcAdapter(Context context) { 513 mContext = context; 514 mNfcActivityManager = new NfcActivityManager(this); 515 } 516 517 /** 518 * @hide 519 */ 520 public Context getContext() { 521 return mContext; 522 } 523 524 /** 525 * Returns the binder interface to the service. 526 * @hide 527 */ 528 public INfcAdapter getService() { 529 isEnabled(); // NOP call to recover sService if it is stale 530 return sService; 531 } 532 533 /** 534 * Returns the binder interface to the tag service. 535 * @hide 536 */ 537 public INfcTag getTagService() { 538 isEnabled(); // NOP call to recover sTagService if it is stale 539 return sTagService; 540 } 541 542 /** 543 * Returns the binder interface to the card emulation service. 544 * @hide 545 */ 546 public INfcCardEmulation getCardEmulationService() { 547 isEnabled(); 548 return sCardEmulationService; 549 } 550 551 /** 552 * NFC service dead - attempt best effort recovery 553 * @hide 554 */ 555 public void attemptDeadServiceRecovery(Exception e) { 556 Log.e(TAG, "NFC service dead - attempting to recover", e); 557 INfcAdapter service = getServiceInterface(); 558 if (service == null) { 559 Log.e(TAG, "could not retrieve NFC service during service recovery"); 560 // nothing more can be done now, sService is still stale, we'll hit 561 // this recovery path again later 562 return; 563 } 564 // assigning to sService is not thread-safe, but this is best-effort code 565 // and on a well-behaved system should never happen 566 sService = service; 567 try { 568 sTagService = service.getNfcTagInterface(); 569 } catch (RemoteException ee) { 570 Log.e(TAG, "could not retrieve NFC tag service during service recovery"); 571 // nothing more can be done now, sService is still stale, we'll hit 572 // this recovery path again later 573 return; 574 } 575 576 try { 577 sCardEmulationService = service.getNfcCardEmulationInterface(); 578 } catch (RemoteException ee) { 579 Log.e(TAG, "could not retrieve NFC card emulation service during service recovery"); 580 } 581 582 return; 583 } 584 585 /** 586 * Return true if this NFC Adapter has any features enabled. 587 * 588 * <p>If this method returns false, the NFC hardware is guaranteed not to 589 * generate or respond to any NFC communication over its NFC radio. 590 * <p>Applications can use this to check if NFC is enabled. Applications 591 * can request Settings UI allowing the user to toggle NFC using: 592 * <p><pre>startActivity(new Intent(Settings.ACTION_NFC_SETTINGS))</pre> 593 * 594 * @see android.provider.Settings#ACTION_NFC_SETTINGS 595 * @return true if this NFC Adapter has any features enabled 596 */ 597 public boolean isEnabled() { 598 try { 599 return sService.getState() == STATE_ON; 600 } catch (RemoteException e) { 601 attemptDeadServiceRecovery(e); 602 return false; 603 } 604 } 605 606 /** 607 * Return the state of this NFC Adapter. 608 * 609 * <p>Returns one of {@link #STATE_ON}, {@link #STATE_TURNING_ON}, 610 * {@link #STATE_OFF}, {@link #STATE_TURNING_OFF}. 611 * 612 * <p>{@link #isEnabled()} is equivalent to 613 * <code>{@link #getAdapterState()} == {@link #STATE_ON}</code> 614 * 615 * @return the current state of this NFC adapter 616 * 617 * @hide 618 */ 619 public int getAdapterState() { 620 try { 621 return sService.getState(); 622 } catch (RemoteException e) { 623 attemptDeadServiceRecovery(e); 624 return NfcAdapter.STATE_OFF; 625 } 626 } 627 628 /** 629 * Enable NFC hardware. 630 * 631 * <p>This call is asynchronous. Listen for 632 * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the 633 * operation is complete. 634 * 635 * <p>If this returns true, then either NFC is already on, or 636 * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent 637 * to indicate a state transition. If this returns false, then 638 * there is some problem that prevents an attempt to turn 639 * NFC on (for example we are in airplane mode and NFC is not 640 * toggleable in airplane mode on this platform). 641 * 642 * @hide 643 */ 644 public boolean enable() { 645 try { 646 return sService.enable(); 647 } catch (RemoteException e) { 648 attemptDeadServiceRecovery(e); 649 return false; 650 } 651 } 652 653 /** 654 * Disable NFC hardware. 655 * 656 * <p>No NFC features will work after this call, and the hardware 657 * will not perform or respond to any NFC communication. 658 * 659 * <p>This call is asynchronous. Listen for 660 * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the 661 * operation is complete. 662 * 663 * <p>If this returns true, then either NFC is already off, or 664 * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent 665 * to indicate a state transition. If this returns false, then 666 * there is some problem that prevents an attempt to turn 667 * NFC off. 668 * 669 * @hide 670 */ 671 672 public boolean disable() { 673 try { 674 return sService.disable(true); 675 } catch (RemoteException e) { 676 attemptDeadServiceRecovery(e); 677 return false; 678 } 679 } 680 681 /** 682 * Set one or more {@link Uri}s to send using Android Beam (TM). Every 683 * Uri you provide must have either scheme 'file' or scheme 'content'. 684 * 685 * <p>For the data provided through this method, Android Beam tries to 686 * switch to alternate transports such as Bluetooth to achieve a fast 687 * transfer speed. Hence this method is very suitable 688 * for transferring large files such as pictures or songs. 689 * 690 * <p>The receiving side will store the content of each Uri in 691 * a file and present a notification to the user to open the file 692 * with a {@link android.content.Intent} with action 693 * {@link android.content.Intent#ACTION_VIEW}. 694 * If multiple URIs are sent, the {@link android.content.Intent} will refer 695 * to the first of the stored files. 696 * 697 * <p>This method may be called at any time before {@link Activity#onDestroy}, 698 * but the URI(s) are only made available for Android Beam when the 699 * specified activity(s) are in resumed (foreground) state. The recommended 700 * approach is to call this method during your Activity's 701 * {@link Activity#onCreate} - see sample 702 * code below. This method does not immediately perform any I/O or blocking work, 703 * so is safe to call on your main thread. 704 * 705 * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback} 706 * have priority over both {@link #setNdefPushMessage} and 707 * {@link #setNdefPushMessageCallback}. 708 * 709 * <p>If {@link #setBeamPushUris} is called with a null Uri array, 710 * and/or {@link #setBeamPushUrisCallback} is called with a null callback, 711 * then the Uri push will be completely disabled for the specified activity(s). 712 * 713 * <p>Code example: 714 * <pre> 715 * protected void onCreate(Bundle savedInstanceState) { 716 * super.onCreate(savedInstanceState); 717 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 718 * if (nfcAdapter == null) return; // NFC not available on this device 719 * nfcAdapter.setBeamPushUris(new Uri[] {uri1, uri2}, this); 720 * }</pre> 721 * And that is it. Only one call per activity is necessary. The Android 722 * OS will automatically release its references to the Uri(s) and the 723 * Activity object when it is destroyed if you follow this pattern. 724 * 725 * <p>If your Activity wants to dynamically supply Uri(s), 726 * then set a callback using {@link #setBeamPushUrisCallback} instead 727 * of using this method. 728 * 729 * <p class="note">Do not pass in an Activity that has already been through 730 * {@link Activity#onDestroy}. This is guaranteed if you call this API 731 * during {@link Activity#onCreate}. 732 * 733 * <p class="note">If this device does not support alternate transports 734 * such as Bluetooth or WiFI, calling this method does nothing. 735 * 736 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 737 * 738 * @param uris an array of Uri(s) to push over Android Beam 739 * @param activity activity for which the Uri(s) will be pushed 740 */ 741 public void setBeamPushUris(Uri[] uris, Activity activity) { 742 if (activity == null) { 743 throw new NullPointerException("activity cannot be null"); 744 } 745 if (uris != null) { 746 for (Uri uri : uris) { 747 if (uri == null) throw new NullPointerException("Uri not " + 748 "allowed to be null"); 749 String scheme = uri.getScheme(); 750 if (scheme == null || (!scheme.equalsIgnoreCase("file") && 751 !scheme.equalsIgnoreCase("content"))) { 752 throw new IllegalArgumentException("URI needs to have " + 753 "either scheme file or scheme content"); 754 } 755 } 756 } 757 mNfcActivityManager.setNdefPushContentUri(activity, uris); 758 } 759 760 /** 761 * Set a callback that will dynamically generate one or more {@link Uri}s 762 * to send using Android Beam (TM). Every Uri the callback provides 763 * must have either scheme 'file' or scheme 'content'. 764 * 765 * <p>For the data provided through this callback, Android Beam tries to 766 * switch to alternate transports such as Bluetooth to achieve a fast 767 * transfer speed. Hence this method is very suitable 768 * for transferring large files such as pictures or songs. 769 * 770 * <p>The receiving side will store the content of each Uri in 771 * a file and present a notification to the user to open the file 772 * with a {@link android.content.Intent} with action 773 * {@link android.content.Intent#ACTION_VIEW}. 774 * If multiple URIs are sent, the {@link android.content.Intent} will refer 775 * to the first of the stored files. 776 * 777 * <p>This method may be called at any time before {@link Activity#onDestroy}, 778 * but the URI(s) are only made available for Android Beam when the 779 * specified activity(s) are in resumed (foreground) state. The recommended 780 * approach is to call this method during your Activity's 781 * {@link Activity#onCreate} - see sample 782 * code below. This method does not immediately perform any I/O or blocking work, 783 * so is safe to call on your main thread. 784 * 785 * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback} 786 * have priority over both {@link #setNdefPushMessage} and 787 * {@link #setNdefPushMessageCallback}. 788 * 789 * <p>If {@link #setBeamPushUris} is called with a null Uri array, 790 * and/or {@link #setBeamPushUrisCallback} is called with a null callback, 791 * then the Uri push will be completely disabled for the specified activity(s). 792 * 793 * <p>Code example: 794 * <pre> 795 * protected void onCreate(Bundle savedInstanceState) { 796 * super.onCreate(savedInstanceState); 797 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 798 * if (nfcAdapter == null) return; // NFC not available on this device 799 * nfcAdapter.setBeamPushUrisCallback(callback, this); 800 * }</pre> 801 * And that is it. Only one call per activity is necessary. The Android 802 * OS will automatically release its references to the Uri(s) and the 803 * Activity object when it is destroyed if you follow this pattern. 804 * 805 * <p class="note">Do not pass in an Activity that has already been through 806 * {@link Activity#onDestroy}. This is guaranteed if you call this API 807 * during {@link Activity#onCreate}. 808 * 809 * <p class="note">If this device does not support alternate transports 810 * such as Bluetooth or WiFI, calling this method does nothing. 811 * 812 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 813 * 814 * @param callback callback, or null to disable 815 * @param activity activity for which the Uri(s) will be pushed 816 */ 817 public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) { 818 if (activity == null) { 819 throw new NullPointerException("activity cannot be null"); 820 } 821 mNfcActivityManager.setNdefPushContentUriCallback(activity, callback); 822 } 823 824 /** 825 * Set a static {@link NdefMessage} to send using Android Beam (TM). 826 * 827 * <p>This method may be called at any time before {@link Activity#onDestroy}, 828 * but the NDEF message is only made available for NDEF push when the 829 * specified activity(s) are in resumed (foreground) state. The recommended 830 * approach is to call this method during your Activity's 831 * {@link Activity#onCreate} - see sample 832 * code below. This method does not immediately perform any I/O or blocking work, 833 * so is safe to call on your main thread. 834 * 835 * <p>Only one NDEF message can be pushed by the currently resumed activity. 836 * If both {@link #setNdefPushMessage} and 837 * {@link #setNdefPushMessageCallback} are set, then 838 * the callback will take priority. 839 * 840 * <p>If neither {@link #setNdefPushMessage} or 841 * {@link #setNdefPushMessageCallback} have been called for your activity, then 842 * the Android OS may choose to send a default NDEF message on your behalf, 843 * such as a URI for your application. 844 * 845 * <p>If {@link #setNdefPushMessage} is called with a null NDEF message, 846 * and/or {@link #setNdefPushMessageCallback} is called with a null callback, 847 * then NDEF push will be completely disabled for the specified activity(s). 848 * This also disables any default NDEF message the Android OS would have 849 * otherwise sent on your behalf for those activity(s). 850 * 851 * <p>If you want to prevent the Android OS from sending default NDEF 852 * messages completely (for all activities), you can include a 853 * {@code <meta-data>} element inside the {@code <application>} 854 * element of your AndroidManifest.xml file, like this: 855 * <pre> 856 * <application ...> 857 * <meta-data android:name="android.nfc.disable_beam_default" 858 * android:value="true" /> 859 * </application></pre> 860 * 861 * <p>The API allows for multiple activities to be specified at a time, 862 * but it is strongly recommended to just register one at a time, 863 * and to do so during the activity's {@link Activity#onCreate}. For example: 864 * <pre> 865 * protected void onCreate(Bundle savedInstanceState) { 866 * super.onCreate(savedInstanceState); 867 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 868 * if (nfcAdapter == null) return; // NFC not available on this device 869 * nfcAdapter.setNdefPushMessage(ndefMessage, this); 870 * }</pre> 871 * And that is it. Only one call per activity is necessary. The Android 872 * OS will automatically release its references to the NDEF message and the 873 * Activity object when it is destroyed if you follow this pattern. 874 * 875 * <p>If your Activity wants to dynamically generate an NDEF message, 876 * then set a callback using {@link #setNdefPushMessageCallback} instead 877 * of a static message. 878 * 879 * <p class="note">Do not pass in an Activity that has already been through 880 * {@link Activity#onDestroy}. This is guaranteed if you call this API 881 * during {@link Activity#onCreate}. 882 * 883 * <p class="note">For sending large content such as pictures and songs, 884 * consider using {@link #setBeamPushUris}, which switches to alternate transports 885 * such as Bluetooth to achieve a fast transfer rate. 886 * 887 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 888 * 889 * @param message NDEF message to push over NFC, or null to disable 890 * @param activity activity for which the NDEF message will be pushed 891 * @param activities optional additional activities, however we strongly recommend 892 * to only register one at a time, and to do so in that activity's 893 * {@link Activity#onCreate} 894 */ 895 public void setNdefPushMessage(NdefMessage message, Activity activity, 896 Activity ... activities) { 897 int targetSdkVersion = getSdkVersion(); 898 try { 899 if (activity == null) { 900 throw new NullPointerException("activity cannot be null"); 901 } 902 mNfcActivityManager.setNdefPushMessage(activity, message, 0); 903 for (Activity a : activities) { 904 if (a == null) { 905 throw new NullPointerException("activities cannot contain null"); 906 } 907 mNfcActivityManager.setNdefPushMessage(a, message, 0); 908 } 909 } catch (IllegalStateException e) { 910 if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) { 911 // Less strict on old applications - just log the error 912 Log.e(TAG, "Cannot call API with Activity that has already " + 913 "been destroyed", e); 914 } else { 915 // Prevent new applications from making this mistake, re-throw 916 throw(e); 917 } 918 } 919 } 920 921 /** 922 * @hide 923 */ 924 public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) { 925 if (activity == null) { 926 throw new NullPointerException("activity cannot be null"); 927 } 928 mNfcActivityManager.setNdefPushMessage(activity, message, flags); 929 } 930 931 /** 932 * Set a callback that dynamically generates NDEF messages to send using Android Beam (TM). 933 * 934 * <p>This method may be called at any time before {@link Activity#onDestroy}, 935 * but the NDEF message callback can only occur when the 936 * specified activity(s) are in resumed (foreground) state. The recommended 937 * approach is to call this method during your Activity's 938 * {@link Activity#onCreate} - see sample 939 * code below. This method does not immediately perform any I/O or blocking work, 940 * so is safe to call on your main thread. 941 * 942 * <p>Only one NDEF message can be pushed by the currently resumed activity. 943 * If both {@link #setNdefPushMessage} and 944 * {@link #setNdefPushMessageCallback} are set, then 945 * the callback will take priority. 946 * 947 * <p>If neither {@link #setNdefPushMessage} or 948 * {@link #setNdefPushMessageCallback} have been called for your activity, then 949 * the Android OS may choose to send a default NDEF message on your behalf, 950 * such as a URI for your application. 951 * 952 * <p>If {@link #setNdefPushMessage} is called with a null NDEF message, 953 * and/or {@link #setNdefPushMessageCallback} is called with a null callback, 954 * then NDEF push will be completely disabled for the specified activity(s). 955 * This also disables any default NDEF message the Android OS would have 956 * otherwise sent on your behalf for those activity(s). 957 * 958 * <p>If you want to prevent the Android OS from sending default NDEF 959 * messages completely (for all activities), you can include a 960 * {@code <meta-data>} element inside the {@code <application>} 961 * element of your AndroidManifest.xml file, like this: 962 * <pre> 963 * <application ...> 964 * <meta-data android:name="android.nfc.disable_beam_default" 965 * android:value="true" /> 966 * </application></pre> 967 * 968 * <p>The API allows for multiple activities to be specified at a time, 969 * but it is strongly recommended to just register one at a time, 970 * and to do so during the activity's {@link Activity#onCreate}. For example: 971 * <pre> 972 * protected void onCreate(Bundle savedInstanceState) { 973 * super.onCreate(savedInstanceState); 974 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 975 * if (nfcAdapter == null) return; // NFC not available on this device 976 * nfcAdapter.setNdefPushMessageCallback(callback, this); 977 * }</pre> 978 * And that is it. Only one call per activity is necessary. The Android 979 * OS will automatically release its references to the callback and the 980 * Activity object when it is destroyed if you follow this pattern. 981 * 982 * <p class="note">Do not pass in an Activity that has already been through 983 * {@link Activity#onDestroy}. This is guaranteed if you call this API 984 * during {@link Activity#onCreate}. 985 * <p class="note">For sending large content such as pictures and songs, 986 * consider using {@link #setBeamPushUris}, which switches to alternate transports 987 * such as Bluetooth to achieve a fast transfer rate. 988 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 989 * 990 * @param callback callback, or null to disable 991 * @param activity activity for which the NDEF message will be pushed 992 * @param activities optional additional activities, however we strongly recommend 993 * to only register one at a time, and to do so in that activity's 994 * {@link Activity#onCreate} 995 */ 996 public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity, 997 Activity ... activities) { 998 int targetSdkVersion = getSdkVersion(); 999 try { 1000 if (activity == null) { 1001 throw new NullPointerException("activity cannot be null"); 1002 } 1003 mNfcActivityManager.setNdefPushMessageCallback(activity, callback, 0); 1004 for (Activity a : activities) { 1005 if (a == null) { 1006 throw new NullPointerException("activities cannot contain null"); 1007 } 1008 mNfcActivityManager.setNdefPushMessageCallback(a, callback, 0); 1009 } 1010 } catch (IllegalStateException e) { 1011 if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) { 1012 // Less strict on old applications - just log the error 1013 Log.e(TAG, "Cannot call API with Activity that has already " + 1014 "been destroyed", e); 1015 } else { 1016 // Prevent new applications from making this mistake, re-throw 1017 throw(e); 1018 } 1019 } 1020 } 1021 1022 /** 1023 * @hide 1024 */ 1025 public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity, 1026 int flags) { 1027 if (activity == null) { 1028 throw new NullPointerException("activity cannot be null"); 1029 } 1030 mNfcActivityManager.setNdefPushMessageCallback(activity, callback, flags); 1031 } 1032 1033 /** 1034 * Set a callback on successful Android Beam (TM). 1035 * 1036 * <p>This method may be called at any time before {@link Activity#onDestroy}, 1037 * but the callback can only occur when the 1038 * specified activity(s) are in resumed (foreground) state. The recommended 1039 * approach is to call this method during your Activity's 1040 * {@link Activity#onCreate} - see sample 1041 * code below. This method does not immediately perform any I/O or blocking work, 1042 * so is safe to call on your main thread. 1043 * 1044 * <p>The API allows for multiple activities to be specified at a time, 1045 * but it is strongly recommended to just register one at a time, 1046 * and to do so during the activity's {@link Activity#onCreate}. For example: 1047 * <pre> 1048 * protected void onCreate(Bundle savedInstanceState) { 1049 * super.onCreate(savedInstanceState); 1050 * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this); 1051 * if (nfcAdapter == null) return; // NFC not available on this device 1052 * nfcAdapter.setOnNdefPushCompleteCallback(callback, this); 1053 * }</pre> 1054 * And that is it. Only one call per activity is necessary. The Android 1055 * OS will automatically release its references to the callback and the 1056 * Activity object when it is destroyed if you follow this pattern. 1057 * 1058 * <p class="note">Do not pass in an Activity that has already been through 1059 * {@link Activity#onDestroy}. This is guaranteed if you call this API 1060 * during {@link Activity#onCreate}. 1061 * 1062 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1063 * 1064 * @param callback callback, or null to disable 1065 * @param activity activity for which the NDEF message will be pushed 1066 * @param activities optional additional activities, however we strongly recommend 1067 * to only register one at a time, and to do so in that activity's 1068 * {@link Activity#onCreate} 1069 */ 1070 public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback, 1071 Activity activity, Activity ... activities) { 1072 int targetSdkVersion = getSdkVersion(); 1073 try { 1074 if (activity == null) { 1075 throw new NullPointerException("activity cannot be null"); 1076 } 1077 mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callback); 1078 for (Activity a : activities) { 1079 if (a == null) { 1080 throw new NullPointerException("activities cannot contain null"); 1081 } 1082 mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback); 1083 } 1084 } catch (IllegalStateException e) { 1085 if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) { 1086 // Less strict on old applications - just log the error 1087 Log.e(TAG, "Cannot call API with Activity that has already " + 1088 "been destroyed", e); 1089 } else { 1090 // Prevent new applications from making this mistake, re-throw 1091 throw(e); 1092 } 1093 } 1094 } 1095 1096 /** 1097 * Enable foreground dispatch to the given Activity. 1098 * 1099 * <p>This will give give priority to the foreground activity when 1100 * dispatching a discovered {@link Tag} to an application. 1101 * 1102 * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents 1103 * for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and 1104 * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED} 1105 * relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled 1106 * by passing in the tech lists separately. Each first level entry in the tech list represents 1107 * an array of technologies that must all be present to match. If any of the first level sets 1108 * match then the dispatch is routed through the given PendingIntent. In other words, the second 1109 * level is ANDed together and the first level entries are ORed together. 1110 * 1111 * <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters 1112 * that acts a wild card and will cause the foreground activity to receive all tags via the 1113 * {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent. 1114 * 1115 * <p>This method must be called from the main thread, and only when the activity is in the 1116 * foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before 1117 * the completion of their {@link Activity#onPause} callback to disable foreground dispatch 1118 * after it has been enabled. 1119 * 1120 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1121 * 1122 * @param activity the Activity to dispatch to 1123 * @param intent the PendingIntent to start for the dispatch 1124 * @param filters the IntentFilters to override dispatching for, or null to always dispatch 1125 * @param techLists the tech lists used to perform matching for dispatching of the 1126 * {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent 1127 * @throws IllegalStateException if the Activity is not currently in the foreground 1128 */ 1129 public void enableForegroundDispatch(Activity activity, PendingIntent intent, 1130 IntentFilter[] filters, String[][] techLists) { 1131 if (activity == null || intent == null) { 1132 throw new NullPointerException(); 1133 } 1134 if (!activity.isResumed()) { 1135 throw new IllegalStateException("Foreground dispatch can only be enabled " + 1136 "when your activity is resumed"); 1137 } 1138 try { 1139 TechListParcel parcel = null; 1140 if (techLists != null && techLists.length > 0) { 1141 parcel = new TechListParcel(techLists); 1142 } 1143 ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity, 1144 mForegroundDispatchListener); 1145 sService.setForegroundDispatch(intent, filters, parcel); 1146 } catch (RemoteException e) { 1147 attemptDeadServiceRecovery(e); 1148 } 1149 } 1150 1151 /** 1152 * Disable foreground dispatch to the given activity. 1153 * 1154 * <p>After calling {@link #enableForegroundDispatch}, an activity 1155 * must call this method before its {@link Activity#onPause} callback 1156 * completes. 1157 * 1158 * <p>This method must be called from the main thread. 1159 * 1160 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1161 * 1162 * @param activity the Activity to disable dispatch to 1163 * @throws IllegalStateException if the Activity has already been paused 1164 */ 1165 public void disableForegroundDispatch(Activity activity) { 1166 ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity, 1167 mForegroundDispatchListener); 1168 disableForegroundDispatchInternal(activity, false); 1169 } 1170 1171 OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() { 1172 @Override 1173 public void onPaused(Activity activity) { 1174 disableForegroundDispatchInternal(activity, true); 1175 } 1176 }; 1177 1178 void disableForegroundDispatchInternal(Activity activity, boolean force) { 1179 try { 1180 sService.setForegroundDispatch(null, null, null); 1181 if (!force && !activity.isResumed()) { 1182 throw new IllegalStateException("You must disable foreground dispatching " + 1183 "while your activity is still resumed"); 1184 } 1185 } catch (RemoteException e) { 1186 attemptDeadServiceRecovery(e); 1187 } 1188 } 1189 1190 /** 1191 * Limit the NFC controller to reader mode while this Activity is in the foreground. 1192 * 1193 * <p>In this mode the NFC controller will only act as an NFC tag reader/writer, 1194 * thus disabling any peer-to-peer (Android Beam) and card-emulation modes of 1195 * the NFC adapter on this device. 1196 * 1197 * <p>Use {@link #FLAG_READER_SKIP_NDEF_CHECK} to prevent the platform from 1198 * performing any NDEF checks in reader mode. Note that this will prevent the 1199 * {@link Ndef} tag technology from being enumerated on the tag, and that 1200 * NDEF-based tag dispatch will not be functional. 1201 * 1202 * <p>For interacting with tags that are emulated on another Android device 1203 * using Android's host-based card-emulation, the recommended flags are 1204 * {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}. 1205 * 1206 * @param activity the Activity that requests the adapter to be in reader mode 1207 * @param callback the callback to be called when a tag is discovered 1208 * @param flags Flags indicating poll technologies and other optional parameters 1209 * @param extras Additional extras for configuring reader mode. 1210 */ 1211 public void enableReaderMode(Activity activity, ReaderCallback callback, int flags, 1212 Bundle extras) { 1213 mNfcActivityManager.enableReaderMode(activity, callback, flags, extras); 1214 } 1215 1216 /** 1217 * Restore the NFC adapter to normal mode of operation: supporting 1218 * peer-to-peer (Android Beam), card emulation, and polling for 1219 * all supported tag technologies. 1220 * 1221 * @param activity the Activity that currently has reader mode enabled 1222 */ 1223 public void disableReaderMode(Activity activity) { 1224 mNfcActivityManager.disableReaderMode(activity); 1225 } 1226 1227 /** 1228 * Enable NDEF message push over NFC while this Activity is in the foreground. 1229 * 1230 * <p>You must explicitly call this method every time the activity is 1231 * resumed, and you must call {@link #disableForegroundNdefPush} before 1232 * your activity completes {@link Activity#onPause}. 1233 * 1234 * <p>Strongly recommend to use the new {@link #setNdefPushMessage} 1235 * instead: it automatically hooks into your activity life-cycle, 1236 * so you do not need to call enable/disable in your onResume/onPause. 1237 * 1238 * <p>For NDEF push to function properly the other NFC device must 1239 * support either NFC Forum's SNEP (Simple Ndef Exchange Protocol), or 1240 * Android's "com.android.npp" (Ndef Push Protocol). This was optional 1241 * on Gingerbread level Android NFC devices, but SNEP is mandatory on 1242 * Ice-Cream-Sandwich and beyond. 1243 * 1244 * <p>This method must be called from the main thread. 1245 * 1246 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1247 * 1248 * @param activity foreground activity 1249 * @param message a NDEF Message to push over NFC 1250 * @throws IllegalStateException if the activity is not currently in the foreground 1251 * @deprecated use {@link #setNdefPushMessage} instead 1252 */ 1253 @Deprecated 1254 public void enableForegroundNdefPush(Activity activity, NdefMessage message) { 1255 if (activity == null || message == null) { 1256 throw new NullPointerException(); 1257 } 1258 enforceResumed(activity); 1259 mNfcActivityManager.setNdefPushMessage(activity, message, 0); 1260 } 1261 1262 /** 1263 * Disable NDEF message push over P2P. 1264 * 1265 * <p>After calling {@link #enableForegroundNdefPush}, an activity 1266 * must call this method before its {@link Activity#onPause} callback 1267 * completes. 1268 * 1269 * <p>Strongly recommend to use the new {@link #setNdefPushMessage} 1270 * instead: it automatically hooks into your activity life-cycle, 1271 * so you do not need to call enable/disable in your onResume/onPause. 1272 * 1273 * <p>This method must be called from the main thread. 1274 * 1275 * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission. 1276 * 1277 * @param activity the Foreground activity 1278 * @throws IllegalStateException if the Activity has already been paused 1279 * @deprecated use {@link #setNdefPushMessage} instead 1280 */ 1281 @Deprecated 1282 public void disableForegroundNdefPush(Activity activity) { 1283 if (activity == null) { 1284 throw new NullPointerException(); 1285 } 1286 enforceResumed(activity); 1287 mNfcActivityManager.setNdefPushMessage(activity, null, 0); 1288 mNfcActivityManager.setNdefPushMessageCallback(activity, null, 0); 1289 mNfcActivityManager.setOnNdefPushCompleteCallback(activity, null); 1290 } 1291 1292 /** 1293 * Enable NDEF Push feature. 1294 * <p>This API is for the Settings application. 1295 * @hide 1296 */ 1297 public boolean enableNdefPush() { 1298 try { 1299 return sService.enableNdefPush(); 1300 } catch (RemoteException e) { 1301 attemptDeadServiceRecovery(e); 1302 return false; 1303 } 1304 } 1305 1306 /** 1307 * Disable NDEF Push feature. 1308 * <p>This API is for the Settings application. 1309 * @hide 1310 */ 1311 public boolean disableNdefPush() { 1312 try { 1313 return sService.disableNdefPush(); 1314 } catch (RemoteException e) { 1315 attemptDeadServiceRecovery(e); 1316 return false; 1317 } 1318 } 1319 1320 /** 1321 * Return true if the NDEF Push (Android Beam) feature is enabled. 1322 * <p>This function will return true only if both NFC is enabled, and the 1323 * NDEF Push feature is enabled. 1324 * <p>Note that if NFC is enabled but NDEF Push is disabled then this 1325 * device can still <i>receive</i> NDEF messages, it just cannot send them. 1326 * <p>Applications cannot directly toggle the NDEF Push feature, but they 1327 * can request Settings UI allowing the user to toggle NDEF Push using 1328 * <code>startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS))</code> 1329 * <p>Example usage in an Activity that requires NDEF Push: 1330 * <p><pre> 1331 * protected void onResume() { 1332 * super.onResume(); 1333 * if (!nfcAdapter.isEnabled()) { 1334 * startActivity(new Intent(Settings.ACTION_NFC_SETTINGS)); 1335 * } else if (!nfcAdapter.isNdefPushEnabled()) { 1336 * startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS)); 1337 * } 1338 * }</pre> 1339 * 1340 * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS 1341 * @return true if NDEF Push feature is enabled 1342 */ 1343 public boolean isNdefPushEnabled() { 1344 try { 1345 return sService.isNdefPushEnabled(); 1346 } catch (RemoteException e) { 1347 attemptDeadServiceRecovery(e); 1348 return false; 1349 } 1350 } 1351 1352 /** 1353 * Inject a mock NFC tag.<p> 1354 * Used for testing purposes. 1355 * <p class="note">Requires the 1356 * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission. 1357 * @hide 1358 */ 1359 public void dispatch(Tag tag) { 1360 if (tag == null) { 1361 throw new NullPointerException("tag cannot be null"); 1362 } 1363 try { 1364 sService.dispatch(tag); 1365 } catch (RemoteException e) { 1366 attemptDeadServiceRecovery(e); 1367 } 1368 } 1369 1370 /** 1371 * @hide 1372 */ 1373 public void setP2pModes(int initiatorModes, int targetModes) { 1374 try { 1375 sService.setP2pModes(initiatorModes, targetModes); 1376 } catch (RemoteException e) { 1377 attemptDeadServiceRecovery(e); 1378 } 1379 } 1380 1381 /** 1382 * @hide 1383 */ 1384 public INfcAdapterExtras getNfcAdapterExtrasInterface() { 1385 if (mContext == null) { 1386 throw new UnsupportedOperationException("You need a context on NfcAdapter to use the " 1387 + " NFC extras APIs"); 1388 } 1389 try { 1390 return sService.getNfcAdapterExtrasInterface(mContext.getPackageName()); 1391 } catch (RemoteException e) { 1392 attemptDeadServiceRecovery(e); 1393 return null; 1394 } 1395 } 1396 1397 void enforceResumed(Activity activity) { 1398 if (!activity.isResumed()) { 1399 throw new IllegalStateException("API cannot be called while activity is paused"); 1400 } 1401 } 1402 1403 int getSdkVersion() { 1404 if (mContext == null) { 1405 return android.os.Build.VERSION_CODES.GINGERBREAD; // best guess 1406 } else { 1407 return mContext.getApplicationInfo().targetSdkVersion; 1408 } 1409 } 1410} 1411