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