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