NfcAdapter.java revision 28319c0cec94977682db32b949628a8e4b8183dc
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 android.annotation.SdkConstant; 20import android.annotation.SdkConstant.SdkConstantType; 21import android.app.Activity; 22import android.app.ActivityThread; 23import android.app.OnActivityPausedListener; 24import android.app.PendingIntent; 25import android.content.Context; 26import android.content.IntentFilter; 27import android.content.pm.IPackageManager; 28import android.content.pm.PackageManager; 29import android.nfc.tech.MifareClassic; 30import android.nfc.tech.Ndef; 31import android.nfc.tech.NfcA; 32import android.nfc.tech.NfcF; 33import android.os.IBinder; 34import android.os.RemoteException; 35import android.os.ServiceManager; 36import android.util.Log; 37 38/** 39 * Represents the local NFC adapter. 40 * <p> 41 * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC 42 * adapter for this Android device. 43 * <p> 44 */ 45public final class NfcAdapter { 46 private static final String TAG = "NFC"; 47 48 /** 49 * Intent to start an activity when a tag with NDEF payload is discovered. 50 * 51 * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and 52 * looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the 53 * intent will contain the URI in its data field. If a MIME record is found the intent will 54 * contain the MIME type in its type field. This allows activities to register 55 * {@link IntentFilter}s targeting specific content on tags. Activities should register the 56 * most specific intent filters possible to avoid the activity chooser dialog, which can 57 * disrupt the interaction with the tag as the user interacts with the screen. 58 * 59 * <p>If the tag has an NDEF payload this intent is started before 60 * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither 61 * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started. 62 */ 63 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 64 public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED"; 65 66 /** 67 * Intent to start an activity when a tag is discovered and activities are registered for the 68 * specific technologies on the tag. 69 * 70 * <p>To receive this intent an activity must include an intent filter 71 * for this action and specify the desired tech types in a 72 * manifest <code>meta-data</code> entry. Here is an example manfiest entry: 73 * <pre> 74 * <activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"> 75 * <!-- Add a technology filter --> 76 * <intent-filter> 77 * <action android:name="android.nfc.action.TECH_DISCOVERED" /> 78 * </intent-filter> 79 * 80 * <meta-data android:name="android.nfc.action.TECH_DISCOVERED" 81 * android:resource="@xml/filter_nfc" 82 * /> 83 * </activity> 84 * </pre> 85 * 86 * <p>The meta-data XML file should contain one or more <code>tech-list</code> entries 87 * each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer 88 * to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA". 89 * 90 * <p>A tag matches if any of the 91 * <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each 92 * of the <code>tech-list</code>s is considered independently and the 93 * activity is considered a match is any single <code>tech-list</code> matches the tag that was 94 * discovered. This provides AND and OR semantics for filtering desired techs. Here is an 95 * example that will match any tag using {@link NfcF} or any tag using {@link NfcA}, 96 * {@link MifareClassic}, and {@link Ndef}: 97 * 98 * <pre> 99 * <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 100 * <!-- capture anything using NfcF --> 101 * <tech-list> 102 * <tech>android.nfc.tech.NfcF</tech> 103 * </tech-list> 104 * 105 * <!-- OR --> 106 * 107 * <!-- capture all MIFARE Classics with NDEF payloads --> 108 * <tech-list> 109 * <tech>android.nfc.tech.NfcA</tech> 110 * <tech>android.nfc.tech.MifareClassic</tech> 111 * <tech>android.nfc.tech.Ndef</tech> 112 * </tech-list> 113 * </resources> 114 * </pre> 115 * 116 * <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before 117 * {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED} 118 * this intent will not be started. If any activities respond to this intent 119 * {@link #ACTION_TAG_DISCOVERED} will not be started. 120 */ 121 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 122 public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED"; 123 124 /** 125 * Intent to start an activity when a tag is discovered. 126 * 127 * <p>This intent will not be started when a tag is discovered if any activities respond to 128 * {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag. 129 */ 130 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 131 public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"; 132 133 /** 134 * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED 135 * @hide 136 */ 137 public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST"; 138 139 /** 140 * Mandatory extra containing the {@link Tag} that was discovered for the 141 * {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and 142 * {@link #ACTION_TAG_DISCOVERED} intents. 143 */ 144 public static final String EXTRA_TAG = "android.nfc.extra.TAG"; 145 146 /** 147 * Optional extra containing an array of {@link NdefMessage} present on the discovered tag for 148 * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and 149 * {@link #ACTION_TAG_DISCOVERED} intents. 150 */ 151 public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES"; 152 153 /** 154 * Optional extra containing a byte array containing the ID of the discovered tag for 155 * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and 156 * {@link #ACTION_TAG_DISCOVERED} intents. 157 */ 158 public static final String EXTRA_ID = "android.nfc.extra.ID"; 159 160 /** 161 * Broadcast Action: a transaction with a secure element has been detected. 162 * <p> 163 * Always contains the extra field 164 * {@link android.nfc.NfcAdapter#EXTRA_AID} 165 * @hide 166 */ 167 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 168 public static final String ACTION_TRANSACTION_DETECTED = 169 "android.nfc.action.TRANSACTION_DETECTED"; 170 171 /** 172 * Broadcast Action: an RF field ON has been detected. 173 * @hide 174 */ 175 public static final String ACTION_RF_FIELD_ON_DETECTED = 176 "android.nfc.action.RF_FIELD_ON_DETECTED"; 177 178 /** 179 * Broadcast Action: an RF Field OFF has been detected. 180 * @hide 181 */ 182 public static final String ACTION_RF_FIELD_OFF_DETECTED = 183 "android.nfc.action.RF_FIELD_OFF_DETECTED"; 184 185 /** 186 * Broadcast Action: an adapter's state changed between enabled and disabled. 187 * 188 * The new value is stored in the extra EXTRA_NEW_BOOLEAN_STATE and just contains 189 * whether it's enabled or disabled, not including any information about whether it's 190 * actively enabling or disabling. 191 * 192 * @hide 193 */ 194 public static final String ACTION_ADAPTER_STATE_CHANGE = 195 "android.nfc.action.ADAPTER_STATE_CHANGE"; 196 197 /** 198 * The Intent extra for ACTION_ADAPTER_STATE_CHANGE, saying what the new state is. 199 * 200 * @hide 201 */ 202 public static final String EXTRA_NEW_BOOLEAN_STATE = "android.nfc.isEnabled"; 203 204 /** 205 * Mandatory byte array extra field in 206 * {@link android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED}. 207 * <p> 208 * Contains the AID of the applet involved in the transaction. 209 * @hide 210 */ 211 public static final String EXTRA_AID = "android.nfc.extra.AID"; 212 213 /** 214 * LLCP link status: The LLCP link is activated. 215 * @hide 216 */ 217 public static final int LLCP_LINK_STATE_ACTIVATED = 0; 218 219 /** 220 * LLCP link status: The LLCP link is deactivated. 221 * @hide 222 */ 223 public static final int LLCP_LINK_STATE_DEACTIVATED = 1; 224 225 /** 226 * Broadcast Action: the LLCP link state changed. 227 * <p> 228 * Always contains the extra field 229 * {@link android.nfc.NfcAdapter#EXTRA_LLCP_LINK_STATE_CHANGED}. 230 * @hide 231 */ 232 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 233 public static final String ACTION_LLCP_LINK_STATE_CHANGED = 234 "android.nfc.action.LLCP_LINK_STATE_CHANGED"; 235 236 /** 237 * Used as int extra field in 238 * {@link android.nfc.NfcAdapter#ACTION_LLCP_LINK_STATE_CHANGED}. 239 * <p> 240 * It contains the new state of the LLCP link. 241 * @hide 242 */ 243 public static final String EXTRA_LLCP_LINK_STATE_CHANGED = "android.nfc.extra.LLCP_LINK_STATE"; 244 245 /** 246 * Tag Reader Discovery mode 247 * @hide 248 */ 249 private static final int DISCOVERY_MODE_TAG_READER = 0; 250 251 /** 252 * NFC-IP1 Peer-to-Peer mode Enables the manager to act as a peer in an 253 * NFC-IP1 communication. Implementations should not assume that the 254 * controller will end up behaving as an NFC-IP1 target or initiator and 255 * should handle both cases, depending on the type of the remote peer type. 256 * @hide 257 */ 258 private static final int DISCOVERY_MODE_NFCIP1 = 1; 259 260 /** 261 * Card Emulation mode Enables the manager to act as an NFC tag. Provided 262 * that a Secure Element (an UICC for instance) is connected to the NFC 263 * controller through its SWP interface, it can be exposed to the outside 264 * NFC world and be addressed by external readers the same way they would 265 * with a tag. 266 * <p> 267 * Which Secure Element is exposed is implementation-dependent. 268 * 269 * @hide 270 */ 271 private static final int DISCOVERY_MODE_CARD_EMULATION = 2; 272 273 274 // Guarded by NfcAdapter.class 275 private static boolean sIsInitialized = false; 276 277 // Final after first constructor, except for 278 // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort 279 // recovery 280 private static INfcAdapter sService; 281 private static INfcTag sTagService; 282 283 /** 284 * Helper to check if this device has FEATURE_NFC, but without using 285 * a context. 286 * Equivalent to 287 * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC) 288 */ 289 private static boolean hasNfcFeature() { 290 IPackageManager pm = ActivityThread.getPackageManager(); 291 if (pm == null) { 292 Log.e(TAG, "Cannot get package manager, assuming no NFC feature"); 293 return false; 294 } 295 try { 296 return pm.hasSystemFeature(PackageManager.FEATURE_NFC); 297 } catch (RemoteException e) { 298 Log.e(TAG, "Package manager query failed, assuming no NFC feature", e); 299 return false; 300 } 301 } 302 303 private static synchronized INfcAdapter setupService() { 304 if (!sIsInitialized) { 305 sIsInitialized = true; 306 307 /* is this device meant to have NFC */ 308 if (!hasNfcFeature()) { 309 Log.v(TAG, "this device does not have NFC support"); 310 return null; 311 } 312 313 sService = getServiceInterface(); 314 if (sService == null) { 315 Log.e(TAG, "could not retrieve NFC service"); 316 return null; 317 } 318 try { 319 sTagService = sService.getNfcTagInterface(); 320 } catch (RemoteException e) { 321 Log.e(TAG, "could not retrieve NFC Tag service"); 322 return null; 323 } 324 } 325 return sService; 326 } 327 328 /** get handle to NFC service interface */ 329 private static INfcAdapter getServiceInterface() { 330 /* get a handle to NFC service */ 331 IBinder b = ServiceManager.getService("nfc"); 332 if (b == null) { 333 return null; 334 } 335 return INfcAdapter.Stub.asInterface(b); 336 } 337 338 /** 339 * Helper to get the default NFC Adapter. 340 * <p> 341 * Most Android devices will only have one NFC Adapter (NFC Controller). 342 * <p> 343 * This helper is the equivalent of: 344 * <pre>{@code 345 * NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); 346 * NfcAdapter adapter = manager.getDefaultAdapter(); 347 * }</pre> 348 * @param context the calling application's context 349 * 350 * @return the default NFC adapter, or null if no NFC adapter exists 351 */ 352 public static NfcAdapter getDefaultAdapter(Context context) { 353 /* use getSystemService() instead of just instantiating to take 354 * advantage of the context's cached NfcManager & NfcAdapter */ 355 NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE); 356 return manager.getDefaultAdapter(); 357 } 358 359 /** 360 * Get a handle to the default NFC Adapter on this Android device. 361 * <p> 362 * Most Android devices will only have one NFC Adapter (NFC Controller). 363 * 364 * @return the default NFC adapter, or null if no NFC adapter exists 365 * @deprecated use {@link #getDefaultAdapter(Context)} 366 */ 367 @Deprecated 368 public static NfcAdapter getDefaultAdapter() { 369 Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " + 370 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception()); 371 return new NfcAdapter(null); 372 } 373 374 /*package*/ NfcAdapter(Context context) { 375 if (setupService() == null) { 376 throw new UnsupportedOperationException(); 377 } 378 } 379 380 /** 381 * Returns the binder interface to the service. 382 * @hide 383 */ 384 public INfcAdapter getService() { 385 isEnabled(); // NOP call to recover sService if it is stale 386 return sService; 387 } 388 389 /** 390 * Returns the binder interface to the tag service. 391 * @hide 392 */ 393 public INfcTag getTagService() { 394 isEnabled(); // NOP call to recover sTagService if it is stale 395 return sTagService; 396 } 397 398 /** 399 * NFC service dead - attempt best effort recovery 400 * @hide 401 */ 402 public void attemptDeadServiceRecovery(Exception e) { 403 Log.e(TAG, "NFC service dead - attempting to recover", e); 404 INfcAdapter service = getServiceInterface(); 405 if (service == null) { 406 Log.e(TAG, "could not retrieve NFC service during service recovery"); 407 // nothing more can be done now, sService is still stale, we'll hit 408 // this recovery path again later 409 return; 410 } 411 // assigning to sService is not thread-safe, but this is best-effort code 412 // and on a well-behaved system should never happen 413 sService = service; 414 try { 415 sTagService = service.getNfcTagInterface(); 416 } catch (RemoteException ee) { 417 Log.e(TAG, "could not retrieve NFC tag service during service recovery"); 418 // nothing more can be done now, sService is still stale, we'll hit 419 // this recovery path again later 420 } 421 422 return; 423 } 424 425 /** 426 * Return true if this NFC Adapter has any features enabled. 427 * 428 * <p>Application may use this as a helper to suggest that the user 429 * should turn on NFC in Settings. 430 * <p>If this method returns false, the NFC hardware is guaranteed not to 431 * generate or respond to any NFC transactions. 432 * 433 * @return true if this NFC Adapter has any features enabled 434 */ 435 public boolean isEnabled() { 436 try { 437 return sService.isEnabled(); 438 } catch (RemoteException e) { 439 attemptDeadServiceRecovery(e); 440 return false; 441 } 442 } 443 444 /** 445 * Enable NFC hardware. 446 * <p> 447 * NOTE: may block for ~second or more. Poor API. Avoid 448 * calling from the UI thread. 449 * 450 * @hide 451 */ 452 public boolean enable() { 453 try { 454 return sService.enable(); 455 } catch (RemoteException e) { 456 attemptDeadServiceRecovery(e); 457 return false; 458 } 459 } 460 461 /** 462 * Disable NFC hardware. 463 * No NFC features will work after this call, and the hardware 464 * will not perform or respond to any NFC communication. 465 * <p> 466 * NOTE: may block for ~second or more. Poor API. Avoid 467 * calling from the UI thread. 468 * 469 * @hide 470 */ 471 public boolean disable() { 472 try { 473 return sService.disable(); 474 } catch (RemoteException e) { 475 attemptDeadServiceRecovery(e); 476 return false; 477 } 478 } 479 480 /** 481 * Enable foreground dispatch to the given Activity. 482 * 483 * <p>This will give give priority to the foreground activity when 484 * dispatching a discovered {@link Tag} to an application. 485 * 486 * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents 487 * for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and 488 * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED} 489 * relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled 490 * by passing in the tech lists separately. Each first level entry in the tech list represents 491 * an array of technologies that must all be present to match. If any of the first level sets 492 * match then the dispatch is routed through the given PendingIntent. In other words, the second 493 * level is ANDed together and the first level entries are ORed together. 494 * 495 * <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters 496 * that acts a wild card and will cause the foreground activity to receive all tags via the 497 * {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent. 498 * 499 * <p>This method must be called from the main thread, and only when the activity is in the 500 * foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before 501 * the completion of their {@link Activity#onPause} callback to disable foreground dispatch 502 * after it has been enabled. 503 * 504 * @param activity the Activity to dispatch to 505 * @param intent the PendingIntent to start for the dispatch 506 * @param filters the IntentFilters to override dispatching for, or null to always dispatch 507 * @param techLists the tech lists used to perform matching for dispatching of the 508 * {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent 509 * @throws IllegalStateException if the Activity is not currently in the foreground 510 */ 511 public void enableForegroundDispatch(Activity activity, PendingIntent intent, 512 IntentFilter[] filters, String[][] techLists) { 513 if (activity == null || intent == null) { 514 throw new NullPointerException(); 515 } 516 if (!activity.isResumed()) { 517 throw new IllegalStateException("Foregorund dispatching can only be enabled " + 518 "when your activity is resumed"); 519 } 520 try { 521 TechListParcel parcel = null; 522 if (techLists != null && techLists.length > 0) { 523 parcel = new TechListParcel(techLists); 524 } 525 ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity, 526 mForegroundDispatchListener); 527 sService.enableForegroundDispatch(activity.getComponentName(), intent, filters, 528 parcel); 529 } catch (RemoteException e) { 530 attemptDeadServiceRecovery(e); 531 } 532 } 533 534 /** 535 * Disable foreground dispatch to the given activity. 536 * 537 * <p>After calling {@link #enableForegroundDispatch}, an activity 538 * must call this method before its {@link Activity#onPause} callback 539 * completes. 540 * 541 * <p>This method must be called from the main thread. 542 * 543 * @param activity the Activity to disable dispatch to 544 * @throws IllegalStateException if the Activity has already been paused 545 */ 546 public void disableForegroundDispatch(Activity activity) { 547 ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity, 548 mForegroundDispatchListener); 549 disableForegroundDispatchInternal(activity, false); 550 } 551 552 OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() { 553 @Override 554 public void onPaused(Activity activity) { 555 disableForegroundDispatchInternal(activity, true); 556 } 557 }; 558 559 void disableForegroundDispatchInternal(Activity activity, boolean force) { 560 try { 561 sService.disableForegroundDispatch(activity.getComponentName()); 562 if (!force && !activity.isResumed()) { 563 throw new IllegalStateException("You must disable forgeground dispatching " + 564 "while your activity is still resumed"); 565 } 566 } catch (RemoteException e) { 567 attemptDeadServiceRecovery(e); 568 } 569 } 570 571 /** 572 * Enable NDEF message push over P2P while this Activity is in the foreground. 573 * 574 * <p>For this to function properly the other NFC device being scanned must 575 * support the "com.android.npp" NDEF push protocol. Support for this 576 * protocol is currently optional for Android NFC devices. 577 * 578 * <p>This method must be called from the main thread. 579 * 580 * <p><em>NOTE</em> While foreground NDEF push is active standard tag dispatch is disabled. 581 * Only the foreground activity may receive tag discovered dispatches via 582 * {@link #enableForegroundDispatch}. 583 * 584 * @param activity the foreground Activity 585 * @param msg a NDEF Message to push over P2P 586 * @throws IllegalStateException if the Activity is not currently in the foreground 587 * @throws OperationNotSupportedException if this Android device does not support NDEF push 588 */ 589 public void enableForegroundNdefPush(Activity activity, NdefMessage msg) { 590 if (activity == null || msg == null) { 591 throw new NullPointerException(); 592 } 593 if (!activity.isResumed()) { 594 throw new IllegalStateException("Foregorund NDEF push can only be enabled " + 595 "when your activity is resumed"); 596 } 597 try { 598 ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity, 599 mForegroundNdefPushListener); 600 sService.enableForegroundNdefPush(activity.getComponentName(), msg); 601 } catch (RemoteException e) { 602 attemptDeadServiceRecovery(e); 603 } 604 } 605 606 /** 607 * Disable NDEF message push over P2P. 608 * 609 * <p>After calling {@link #enableForegroundNdefPush}, an activity 610 * must call this method before its {@link Activity#onPause} callback 611 * completes. 612 * 613 * <p>This method must be called from the main thread. 614 * 615 * @param activity the Foreground activity 616 * @throws IllegalStateException if the Activity has already been paused 617 * @throws OperationNotSupportedException if this Android device does not support NDEF push 618 */ 619 public void disableForegroundNdefPush(Activity activity) { 620 ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity, 621 mForegroundNdefPushListener); 622 disableForegroundNdefPushInternal(activity, false); 623 } 624 625 OnActivityPausedListener mForegroundNdefPushListener = new OnActivityPausedListener() { 626 @Override 627 public void onPaused(Activity activity) { 628 disableForegroundNdefPushInternal(activity, true); 629 } 630 }; 631 632 void disableForegroundNdefPushInternal(Activity activity, boolean force) { 633 try { 634 sService.disableForegroundNdefPush(activity.getComponentName()); 635 if (!force && !activity.isResumed()) { 636 throw new IllegalStateException("You must disable forgeground NDEF push " + 637 "while your activity is still resumed"); 638 } 639 } catch (RemoteException e) { 640 attemptDeadServiceRecovery(e); 641 } 642 } 643 644 /** 645 * Set the NDEF Message that this NFC adapter should appear as to Tag 646 * readers. 647 * <p> 648 * Any Tag reader can read the contents of the local tag when it is in 649 * proximity, without any further user confirmation. 650 * <p> 651 * The implementation of this method must either 652 * <ul> 653 * <li>act as a passive tag containing this NDEF message 654 * <li>provide the NDEF message on over LLCP to peer NFC adapters 655 * </ul> 656 * The NDEF message is preserved across reboot. 657 * <p>Requires {@link android.Manifest.permission#NFC} permission. 658 * 659 * @param message NDEF message to make public 660 * @hide 661 */ 662 public void setLocalNdefMessage(NdefMessage message) { 663 try { 664 sService.localSet(message); 665 } catch (RemoteException e) { 666 attemptDeadServiceRecovery(e); 667 } 668 } 669 670 /** 671 * Get the NDEF Message that this adapter appears as to Tag readers. 672 * <p>Requires {@link android.Manifest.permission#NFC} permission. 673 * 674 * @return NDEF Message that is publicly readable 675 * @hide 676 */ 677 public NdefMessage getLocalNdefMessage() { 678 try { 679 return sService.localGet(); 680 } catch (RemoteException e) { 681 attemptDeadServiceRecovery(e); 682 return null; 683 } 684 } 685 686 /** 687 * Create an Nfc Secure Element Connection 688 * @hide 689 */ 690 public NfcSecureElement createNfcSecureElementConnection() { 691 try { 692 return new NfcSecureElement(sService.getNfcSecureElementInterface()); 693 } catch (RemoteException e) { 694 Log.e(TAG, "createNfcSecureElementConnection failed", e); 695 return null; 696 } 697 } 698} 699