NfcAdapter.java revision 7ea5c45e8d89f59065f088d4e11cceeeed9d64d1
1/* 2 * Copyright (C) 2010 The Android Open Source Project Licensed under the Apache 3 * License, Version 2.0 (the "License"); you may not use this file except in 4 * compliance with the License. You may obtain a copy of the License at 5 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law 6 * or agreed to in writing, software distributed under the License is 7 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 8 * KIND, either express or implied. See the License for the specific language 9 * governing permissions and limitations under the License. 10 */ 11 12package android.nfc; 13 14import java.lang.UnsupportedOperationException; 15 16import android.annotation.SdkConstant; 17import android.annotation.SdkConstant.SdkConstantType; 18import android.app.ActivityThread; 19import android.content.Context; 20import android.content.pm.IPackageManager; 21import android.content.pm.PackageManager; 22import android.nfc.INfcAdapter; 23import android.os.IBinder; 24import android.os.RemoteException; 25import android.os.ServiceManager; 26import android.util.Log; 27 28/** 29 * Represents the device's local NFC adapter. 30 * <p> 31 * Use the static {@link #getDefaultAdapter} method to get the default NFC 32 * Adapter for this Android device. Most Android devices will have only one NFC 33 * Adapter, and {@link #getDefaultAdapter} returns the singleton object. 34 * <p> 35 * {@link NfcAdapter} can be used to create {@link RawTagConnection} or 36 * {@link NdefTagConnection} connections to modify or perform low level access 37 * to NFC Tags. 38 * <p class="note"> 39 * <strong>Note:</strong> Some methods require the 40 * {@link android.Manifest.permission#NFC} permission. 41 */ 42public final class NfcAdapter { 43 /** 44 * Intent to start an activity when a non-NDEF tag is discovered. 45 * TODO(npelly) finalize decision on using CATEGORY or DATA URI to provide a 46 * hint for applications to filter the tag type. 47 * TODO(npelly) probably combine these two intents since tags aren't that simple 48 */ 49 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 50 public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED"; 51 52 /** 53 * Intent to start an activity when a NDEF tag is discovered. TODO(npelly) 54 * finalize decision on using CATEGORY or DATA URI to provide a hint for 55 * applications to filter the tag type. 56 */ 57 @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) 58 public static final String ACTION_NDEF_TAG_DISCOVERED = 59 "android.nfc.action.NDEF_TAG_DISCOVERED"; 60 61 /** 62 * Mandatory Tag extra for the ACTION_TAG and ACTION_NDEF_TAG intents. 63 */ 64 public static final String EXTRA_TAG = "android.nfc.extra.TAG"; 65 66 /** 67 * Broadcast Action: a transaction with a secure element has been detected. 68 * <p> 69 * Always contains the extra field 70 * {@link android.nfc.NfcAdapter#EXTRA_AID} 71 * @hide 72 */ 73 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 74 public static final String ACTION_TRANSACTION_DETECTED = 75 "android.nfc.action.TRANSACTION_DETECTED"; 76 77 /** 78 * Broadcast Action: an adapter's state changed between enabled and disabled. 79 * 80 * The new value is stored in the extra EXTRA_NEW_BOOLEAN_STATE and just contains 81 * whether it's enabled or disabled, not including any information about whether it's 82 * actively enabling or disabling. 83 * 84 * @hide 85 */ 86 public static final String ACTION_ADAPTER_STATE_CHANGE = 87 "android.nfc.action.ADAPTER_STATE_CHANGE"; 88 89 /** 90 * The Intent extra for ACTION_ADAPTER_STATE_CHANGE, saying what the new state is. 91 * 92 * @hide 93 */ 94 public static final String EXTRA_NEW_BOOLEAN_STATE = "android.nfc.isEnabled"; 95 96 /** 97 * Mandatory byte array extra field in 98 * {@link android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED}. 99 * <p> 100 * Contains the AID of the applet involved in the transaction. 101 * @hide 102 */ 103 public static final String EXTRA_AID = "android.nfc.extra.AID"; 104 105 /** 106 * LLCP link status: The LLCP link is activated. 107 * @hide 108 */ 109 public static final int LLCP_LINK_STATE_ACTIVATED = 0; 110 111 /** 112 * LLCP link status: The LLCP link is deactivated. 113 * @hide 114 */ 115 public static final int LLCP_LINK_STATE_DEACTIVATED = 1; 116 117 /** 118 * Broadcast Action: the LLCP link state changed. 119 * <p> 120 * Always contains the extra field 121 * {@link android.nfc.NfcAdapter#EXTRA_LLCP_LINK_STATE_CHANGED}. 122 * @hide 123 */ 124 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 125 public static final String ACTION_LLCP_LINK_STATE_CHANGED = 126 "android.nfc.action.LLCP_LINK_STATE_CHANGED"; 127 128 /** 129 * Used as int extra field in 130 * {@link android.nfc.NfcAdapter#ACTION_LLCP_LINK_STATE_CHANGED}. 131 * <p> 132 * It contains the new state of the LLCP link. 133 * @hide 134 */ 135 public static final String EXTRA_LLCP_LINK_STATE_CHANGED = "android.nfc.extra.LLCP_LINK_STATE"; 136 137 /** 138 * Tag Reader Discovery mode 139 * @hide 140 */ 141 private static final int DISCOVERY_MODE_TAG_READER = 0; 142 143 /** 144 * NFC-IP1 Peer-to-Peer mode Enables the manager to act as a peer in an 145 * NFC-IP1 communication. Implementations should not assume that the 146 * controller will end up behaving as an NFC-IP1 target or initiator and 147 * should handle both cases, depending on the type of the remote peer type. 148 * @hide 149 */ 150 private static final int DISCOVERY_MODE_NFCIP1 = 1; 151 152 /** 153 * Card Emulation mode Enables the manager to act as an NFC tag. Provided 154 * that a Secure Element (an UICC for instance) is connected to the NFC 155 * controller through its SWP interface, it can be exposed to the outside 156 * NFC world and be addressed by external readers the same way they would 157 * with a tag. 158 * <p> 159 * Which Secure Element is exposed is implementation-dependent. 160 * 161 * @hide 162 */ 163 private static final int DISCOVERY_MODE_CARD_EMULATION = 2; 164 165 private static final String TAG = "NFC"; 166 167 // Both guarded by NfcAdapter.class: 168 private static boolean sIsInitialized = false; 169 private static NfcAdapter sAdapter; 170 171 private final INfcAdapter mService; 172 173 private NfcAdapter(INfcAdapter service) { 174 mService = service; 175 } 176 177 /** 178 * Helper to check if this device has FEATURE_NFC, but without using 179 * a context. 180 * Equivalent to 181 * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC) 182 */ 183 private static boolean hasNfcFeature() { 184 IPackageManager pm = ActivityThread.getPackageManager(); 185 if (pm == null) { 186 Log.e(TAG, "Cannot get package manager, assuming no NFC feature"); 187 return false; 188 } 189 try { 190 return pm.hasSystemFeature(PackageManager.FEATURE_NFC); 191 } catch (RemoteException e) { 192 Log.e(TAG, "Package manager query failed, assuming no NFC feature", e); 193 return false; 194 } 195 } 196 197 /** 198 * Get a handle to the default NFC Adapter on this Android device. 199 * <p> 200 * Most Android devices will only have one NFC Adapter (NFC Controller). 201 * 202 * @return the default NFC adapter, or null if no NFC adapter exists 203 */ 204 public static NfcAdapter getDefaultAdapter() { 205 synchronized (NfcAdapter.class) { 206 if (sIsInitialized) { 207 return sAdapter; 208 } 209 sIsInitialized = true; 210 211 /* is this device meant to have NFC */ 212 if (!hasNfcFeature()) { 213 Log.v(TAG, "this device does not have NFC support"); 214 return null; 215 } 216 217 /* get a handle to NFC service */ 218 IBinder b = ServiceManager.getService("nfc"); 219 if (b == null) { 220 Log.e(TAG, "could not retrieve NFC service"); 221 return null; 222 } 223 224 sAdapter = new NfcAdapter(INfcAdapter.Stub.asInterface(b)); 225 return sAdapter; 226 } 227 } 228 229 /** 230 * Return true if this NFC Adapter has any features enabled. 231 * <p> 232 * If this method returns false, then applications should request the user 233 * turn on NFC tag discovery in Settings. 234 * <p> 235 * If this method returns false, the NFC hardware is guaranteed not to 236 * perform or respond to any NFC communication. 237 * 238 * @return true if this NFC Adapter is enabled to discover new tags 239 */ 240 public boolean isEnabled() { 241 try { 242 return mService.isEnabled(); 243 } catch (RemoteException e) { 244 Log.e(TAG, "RemoteException in isEnabled()", e); 245 return false; 246 } 247 } 248 249 /** 250 * Enable NFC hardware. 251 * <p> 252 * NOTE: may block for ~second or more. Poor API. Avoid 253 * calling from the UI thread. 254 * 255 * @hide 256 */ 257 public boolean enable() { 258 try { 259 return mService.enable(); 260 } catch (RemoteException e) { 261 Log.e(TAG, "RemoteException in enable()", e); 262 return false; 263 } 264 } 265 266 /** 267 * Disable NFC hardware. 268 * No NFC features will work after this call, and the hardware 269 * will not perform or respond to any NFC communication. 270 * <p> 271 * NOTE: may block for ~second or more. Poor API. Avoid 272 * calling from the UI thread. 273 * 274 * @hide 275 */ 276 public boolean disable() { 277 try { 278 return mService.disable(); 279 } catch (RemoteException e) { 280 Log.e(TAG, "RemoteException in disable()", e); 281 return false; 282 } 283 } 284 285 /** 286 * Set the NDEF Message that this NFC adapter should appear as to Tag 287 * readers. 288 * <p> 289 * Any Tag reader can read the contents of the local tag when it is in 290 * proximity, without any further user confirmation. 291 * <p> 292 * The implementation of this method must either 293 * <ul> 294 * <li>act as a passive tag containing this NDEF message 295 * <li>provide the NDEF message on over LLCP to peer NFC adapters 296 * </ul> 297 * The NDEF message is preserved across reboot. 298 * <p>Requires {@link android.Manifest.permission#NFC} permission. 299 * 300 * @param message NDEF message to make public 301 */ 302 public void setLocalNdefMessage(NdefMessage message) { 303 try { 304 mService.localSet(message); 305 } catch (RemoteException e) { 306 Log.e(TAG, "NFC service died", e); 307 } 308 } 309 310 /** 311 * Get the NDEF Message that this adapter appears as to Tag readers. 312 * <p>Requires {@link android.Manifest.permission#NFC} permission. 313 * 314 * @return NDEF Message that is publicly readable 315 */ 316 public NdefMessage getLocalNdefMessage() { 317 try { 318 return mService.localGet(); 319 } catch (RemoteException e) { 320 Log.e(TAG, "NFC service died", e); 321 return null; 322 } 323 } 324 325 /** 326 * Create a raw tag connection to the default Target 327 * <p>Requires {@link android.Manifest.permission#NFC} permission. 328 */ 329 public RawTagConnection createRawTagConnection(Tag tag) { 330 try { 331 return new RawTagConnection(mService, tag); 332 } catch (RemoteException e) { 333 Log.e(TAG, "NFC service died", e); 334 return null; 335 } 336 } 337 338 /** 339 * Create a raw tag connection to the specified Target 340 * <p>Requires {@link android.Manifest.permission#NFC} permission. 341 */ 342 public RawTagConnection createRawTagConnection(Tag tag, String target) { 343 try { 344 return new RawTagConnection(mService, tag, target); 345 } catch (RemoteException e) { 346 Log.e(TAG, "NFC service died", e); 347 return null; 348 } 349 } 350 351 /** 352 * Create an NDEF tag connection to the default Target 353 * <p>Requires {@link android.Manifest.permission#NFC} permission. 354 */ 355 public NdefTagConnection createNdefTagConnection(NdefTag tag) { 356 try { 357 return new NdefTagConnection(mService, tag); 358 } catch (RemoteException e) { 359 Log.e(TAG, "NFC service died", e); 360 return null; 361 } 362 } 363 364 /** 365 * Create an NDEF tag connection to the specified Target 366 * <p>Requires {@link android.Manifest.permission#NFC} permission. 367 */ 368 public NdefTagConnection createNdefTagConnection(NdefTag tag, String target) { 369 try { 370 return new NdefTagConnection(mService, tag, target); 371 } catch (RemoteException e) { 372 Log.e(TAG, "NFC service died", e); 373 return null; 374 } 375 } 376} 377