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