Home | History | Annotate | Download | only in nfc
      1 /*
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.nfc;
     18 
     19 import java.util.HashMap;
     20 
     21 import android.annotation.SdkConstant;
     22 import android.annotation.SdkConstant.SdkConstantType;
     23 import android.annotation.SystemApi;
     24 import android.app.Activity;
     25 import android.app.ActivityThread;
     26 import android.app.OnActivityPausedListener;
     27 import android.app.PendingIntent;
     28 import android.content.Context;
     29 import android.content.IntentFilter;
     30 import android.content.pm.IPackageManager;
     31 import android.content.pm.PackageManager;
     32 import android.net.Uri;
     33 import android.nfc.tech.MifareClassic;
     34 import android.nfc.tech.Ndef;
     35 import android.nfc.tech.NfcA;
     36 import android.nfc.tech.NfcF;
     37 import android.os.Bundle;
     38 import android.os.Handler;
     39 import android.os.IBinder;
     40 import android.os.RemoteException;
     41 import android.os.ServiceManager;
     42 import android.util.Log;
     43 
     44 import java.io.IOException;
     45 
     46 /**
     47  * Represents the local NFC adapter.
     48  * <p>
     49  * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC
     50  * adapter for this Android device.
     51  *
     52  * <div class="special reference">
     53  * <h3>Developer Guides</h3>
     54  * <p>For more information about using NFC, read the
     55  * <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p>
     56  * <p>To perform basic file sharing between devices, read
     57  * <a href="{@docRoot}training/beam-files/index.html">Sharing Files with NFC</a>.
     58  * </div>
     59  */
     60 public final class NfcAdapter {
     61     static final String TAG = "NFC";
     62 
     63     /**
     64      * Intent to start an activity when a tag with NDEF payload is discovered.
     65      *
     66      * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and
     67      * looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the
     68      * intent will contain the URI in its data field. If a MIME record is found the intent will
     69      * contain the MIME type in its type field. This allows activities to register
     70      * {@link IntentFilter}s targeting specific content on tags. Activities should register the
     71      * most specific intent filters possible to avoid the activity chooser dialog, which can
     72      * disrupt the interaction with the tag as the user interacts with the screen.
     73      *
     74      * <p>If the tag has an NDEF payload this intent is started before
     75      * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither
     76      * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
     77      *
     78      * <p>The MIME type or data URI of this intent are normalized before dispatch -
     79      * so that MIME, URI scheme and URI host are always lower-case.
     80      */
     81     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     82     public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
     83 
     84     /**
     85      * Intent to start an activity when a tag is discovered and activities are registered for the
     86      * specific technologies on the tag.
     87      *
     88      * <p>To receive this intent an activity must include an intent filter
     89      * for this action and specify the desired tech types in a
     90      * manifest <code>meta-data</code> entry. Here is an example manfiest entry:
     91      * <pre>
     92      * &lt;activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"&gt;
     93      *     &lt;!-- Add a technology filter --&gt;
     94      *     &lt;intent-filter&gt;
     95      *         &lt;action android:name="android.nfc.action.TECH_DISCOVERED" /&gt;
     96      *     &lt;/intent-filter&gt;
     97      *
     98      *     &lt;meta-data android:name="android.nfc.action.TECH_DISCOVERED"
     99      *         android:resource="@xml/filter_nfc"
    100      *     /&gt;
    101      * &lt;/activity&gt;</pre>
    102      *
    103      * <p>The meta-data XML file should contain one or more <code>tech-list</code> entries
    104      * each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer
    105      * to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA".
    106      *
    107      * <p>A tag matches if any of the
    108      * <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each
    109      * of the <code>tech-list</code>s is considered independently and the
    110      * activity is considered a match is any single <code>tech-list</code> matches the tag that was
    111      * discovered. This provides AND and OR semantics for filtering desired techs. Here is an
    112      * example that will match any tag using {@link NfcF} or any tag using {@link NfcA},
    113      * {@link MifareClassic}, and {@link Ndef}:
    114      *
    115      * <pre>
    116      * &lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
    117      *     &lt;!-- capture anything using NfcF --&gt;
    118      *     &lt;tech-list&gt;
    119      *         &lt;tech&gt;android.nfc.tech.NfcF&lt;/tech&gt;
    120      *     &lt;/tech-list&gt;
    121      *
    122      *     &lt;!-- OR --&gt;
    123      *
    124      *     &lt;!-- capture all MIFARE Classics with NDEF payloads --&gt;
    125      *     &lt;tech-list&gt;
    126      *         &lt;tech&gt;android.nfc.tech.NfcA&lt;/tech&gt;
    127      *         &lt;tech&gt;android.nfc.tech.MifareClassic&lt;/tech&gt;
    128      *         &lt;tech&gt;android.nfc.tech.Ndef&lt;/tech&gt;
    129      *     &lt;/tech-list&gt;
    130      * &lt;/resources&gt;</pre>
    131      *
    132      * <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before
    133      * {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED}
    134      * this intent will not be started. If any activities respond to this intent
    135      * {@link #ACTION_TAG_DISCOVERED} will not be started.
    136      */
    137     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    138     public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
    139 
    140     /**
    141      * Intent to start an activity when a tag is discovered.
    142      *
    143      * <p>This intent will not be started when a tag is discovered if any activities respond to
    144      * {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag.
    145      */
    146     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
    147     public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
    148 
    149     /**
    150      * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED
    151      * @hide
    152      */
    153     public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST";
    154 
    155     /**
    156      * Mandatory extra containing the {@link Tag} that was discovered for the
    157      * {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
    158      * {@link #ACTION_TAG_DISCOVERED} intents.
    159      */
    160     public static final String EXTRA_TAG = "android.nfc.extra.TAG";
    161 
    162     /**
    163      * Extra containing an array of {@link NdefMessage} present on the discovered tag.<p>
    164      * This extra is mandatory for {@link #ACTION_NDEF_DISCOVERED} intents,
    165      * and optional for {@link #ACTION_TECH_DISCOVERED}, and
    166      * {@link #ACTION_TAG_DISCOVERED} intents.<p>
    167      * When this extra is present there will always be at least one
    168      * {@link NdefMessage} element. Most NDEF tags have only one NDEF message,
    169      * but we use an array for future compatibility.
    170      */
    171     public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
    172 
    173     /**
    174      * Optional extra containing a byte array containing the ID of the discovered tag for
    175      * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
    176      * {@link #ACTION_TAG_DISCOVERED} intents.
    177      */
    178     public static final String EXTRA_ID = "android.nfc.extra.ID";
    179 
    180     /**
    181      * Broadcast Action: The state of the local NFC adapter has been
    182      * changed.
    183      * <p>For example, NFC has been turned on or off.
    184      * <p>Always contains the extra field {@link #EXTRA_ADAPTER_STATE}
    185      */
    186     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    187     public static final String ACTION_ADAPTER_STATE_CHANGED =
    188             "android.nfc.action.ADAPTER_STATE_CHANGED";
    189 
    190     /**
    191      * Used as an int extra field in {@link #ACTION_ADAPTER_STATE_CHANGED}
    192      * intents to request the current power state. Possible values are:
    193      * {@link #STATE_OFF},
    194      * {@link #STATE_TURNING_ON},
    195      * {@link #STATE_ON},
    196      * {@link #STATE_TURNING_OFF},
    197      */
    198     public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
    199 
    200     public static final int STATE_OFF = 1;
    201     public static final int STATE_TURNING_ON = 2;
    202     public static final int STATE_ON = 3;
    203     public static final int STATE_TURNING_OFF = 4;
    204 
    205     /**
    206      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
    207      * <p>
    208      * Setting this flag enables polling for Nfc-A technology.
    209      */
    210     public static final int FLAG_READER_NFC_A = 0x1;
    211 
    212     /**
    213      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
    214      * <p>
    215      * Setting this flag enables polling for Nfc-B technology.
    216      */
    217     public static final int FLAG_READER_NFC_B = 0x2;
    218 
    219     /**
    220      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
    221      * <p>
    222      * Setting this flag enables polling for Nfc-F technology.
    223      */
    224     public static final int FLAG_READER_NFC_F = 0x4;
    225 
    226     /**
    227      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
    228      * <p>
    229      * Setting this flag enables polling for Nfc-V (ISO15693) technology.
    230      */
    231     public static final int FLAG_READER_NFC_V = 0x8;
    232 
    233     /**
    234      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
    235      * <p>
    236      * Setting this flag enables polling for NfcBarcode technology.
    237      */
    238     public static final int FLAG_READER_NFC_BARCODE = 0x10;
    239 
    240     /**
    241      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
    242      * <p>
    243      * Setting this flag allows the caller to prevent the
    244      * platform from performing an NDEF check on the tags it
    245      * finds.
    246      */
    247     public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80;
    248 
    249     /**
    250      * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
    251      * <p>
    252      * Setting this flag allows the caller to prevent the
    253      * platform from playing sounds when it discovers a tag.
    254      */
    255     public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100;
    256 
    257     /**
    258      * Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
    259      * <p>
    260      * Setting this integer extra allows the calling application to specify
    261      * the delay that the platform will use for performing presence checks
    262      * on any discovered tag.
    263      */
    264     public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
    265 
    266     /** @hide */
    267     @SystemApi
    268     public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
    269 
    270     /** @hide */
    271     public static final String ACTION_HANDOVER_TRANSFER_STARTED =
    272             "android.nfc.action.HANDOVER_TRANSFER_STARTED";
    273 
    274     /** @hide */
    275     public static final String ACTION_HANDOVER_TRANSFER_DONE =
    276             "android.nfc.action.HANDOVER_TRANSFER_DONE";
    277 
    278     /** @hide */
    279     public static final String EXTRA_HANDOVER_TRANSFER_STATUS =
    280             "android.nfc.extra.HANDOVER_TRANSFER_STATUS";
    281 
    282     /** @hide */
    283     public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
    284     /** @hide */
    285     public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
    286 
    287     /** @hide */
    288     public static final String EXTRA_HANDOVER_TRANSFER_URI =
    289             "android.nfc.extra.HANDOVER_TRANSFER_URI";
    290 
    291     // Guarded by NfcAdapter.class
    292     static boolean sIsInitialized = false;
    293     static boolean sHasNfcFeature;
    294 
    295     // Final after first constructor, except for
    296     // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
    297     // recovery
    298     static INfcAdapter sService;
    299     static INfcTag sTagService;
    300     static INfcCardEmulation sCardEmulationService;
    301     static INfcFCardEmulation sNfcFCardEmulationService;
    302 
    303     /**
    304      * The NfcAdapter object for each application context.
    305      * There is a 1-1 relationship between application context and
    306      * NfcAdapter object.
    307      */
    308     static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class
    309 
    310     /**
    311      * NfcAdapter used with a null context. This ctor was deprecated but we have
    312      * to support it for backwards compatibility. New methods that require context
    313      * might throw when called on the null-context NfcAdapter.
    314      */
    315     static NfcAdapter sNullContextNfcAdapter;  // protected by NfcAdapter.class
    316 
    317     final NfcActivityManager mNfcActivityManager;
    318     final Context mContext;
    319     final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
    320     final Object mLock;
    321 
    322     ITagRemovedCallback mTagRemovedListener; // protected by mLock
    323 
    324     /**
    325      * A callback to be invoked when the system finds a tag while the foreground activity is
    326      * operating in reader mode.
    327      * <p>Register your {@code ReaderCallback} implementation with {@link
    328      * NfcAdapter#enableReaderMode} and disable it with {@link
    329      * NfcAdapter#disableReaderMode}.
    330      * @see NfcAdapter#enableReaderMode
    331      */
    332     public interface ReaderCallback {
    333         public void onTagDiscovered(Tag tag);
    334     }
    335 
    336     /**
    337      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
    338      * to another device.
    339      * @see #setOnNdefPushCompleteCallback
    340      */
    341     public interface OnNdefPushCompleteCallback {
    342         /**
    343          * Called on successful NDEF push.
    344          *
    345          * <p>This callback is usually made on a binder thread (not the UI thread).
    346          *
    347          * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
    348          * @see #setNdefPushMessageCallback
    349          */
    350         public void onNdefPushComplete(NfcEvent event);
    351     }
    352 
    353     /**
    354      * A callback to be invoked when another NFC device capable of NDEF push (Android Beam)
    355      * is within range.
    356      * <p>Implement this interface and pass it to {@link
    357      * NfcAdapter#setNdefPushMessageCallback setNdefPushMessageCallback()} in order to create an
    358      * {@link NdefMessage} at the moment that another device is within range for NFC. Using this
    359      * callback allows you to create a message with data that might vary based on the
    360      * content currently visible to the user. Alternatively, you can call {@link
    361      * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
    362      * same data.
    363      */
    364     public interface CreateNdefMessageCallback {
    365         /**
    366          * Called to provide a {@link NdefMessage} to push.
    367          *
    368          * <p>This callback is usually made on a binder thread (not the UI thread).
    369          *
    370          * <p>Called when this device is in range of another device
    371          * that might support NDEF push. It allows the application to
    372          * create the NDEF message only when it is required.
    373          *
    374          * <p>NDEF push cannot occur until this method returns, so do not
    375          * block for too long.
    376          *
    377          * <p>The Android operating system will usually show a system UI
    378          * on top of your activity during this time, so do not try to request
    379          * input from the user to complete the callback, or provide custom NDEF
    380          * push UI. The user probably will not see it.
    381          *
    382          * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
    383          * @return NDEF message to push, or null to not provide a message
    384          */
    385         public NdefMessage createNdefMessage(NfcEvent event);
    386     }
    387 
    388 
    389     // TODO javadoc
    390     public interface CreateBeamUrisCallback {
    391         public Uri[] createBeamUris(NfcEvent event);
    392     }
    393 
    394     /**
    395      * A callback that is invoked when a tag is removed from the field.
    396      * @see NfcAdapter#ignore
    397      */
    398     public interface OnTagRemovedListener {
    399         void onTagRemoved();
    400     }
    401 
    402     /**
    403      * A callback to be invoked when an application has registered as a
    404      * handler to unlock the device given an NFC tag at the lockscreen.
    405      * @hide
    406      */
    407     @SystemApi
    408     public interface NfcUnlockHandler {
    409         /**
    410          * Called at the lock screen to attempt to unlock the device with the given tag.
    411          * @param tag the detected tag, to be used to unlock the device
    412          * @return true if the device was successfully unlocked
    413          */
    414         public boolean onUnlockAttempted(Tag tag);
    415     }
    416 
    417 
    418     /**
    419      * Helper to check if this device has FEATURE_NFC, but without using
    420      * a context.
    421      * Equivalent to
    422      * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)
    423      */
    424     private static boolean hasNfcFeature() {
    425         IPackageManager pm = ActivityThread.getPackageManager();
    426         if (pm == null) {
    427             Log.e(TAG, "Cannot get package manager, assuming no NFC feature");
    428             return false;
    429         }
    430         try {
    431             return pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0);
    432         } catch (RemoteException e) {
    433             Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
    434             return false;
    435         }
    436     }
    437 
    438     /**
    439      * Helper to check if this device is NFC HCE capable, by checking for
    440      * FEATURE_NFC_HOST_CARD_EMULATION and/or FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
    441      * but without using a context.
    442      */
    443     private static boolean hasNfcHceFeature() {
    444         IPackageManager pm = ActivityThread.getPackageManager();
    445         if (pm == null) {
    446             Log.e(TAG, "Cannot get package manager, assuming no NFC feature");
    447             return false;
    448         }
    449         try {
    450             return pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)
    451                 || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 0);
    452         } catch (RemoteException e) {
    453             Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
    454             return false;
    455         }
    456     }
    457 
    458     /**
    459      * Returns the NfcAdapter for application context,
    460      * or throws if NFC is not available.
    461      * @hide
    462      */
    463     public static synchronized NfcAdapter getNfcAdapter(Context context) {
    464         if (!sIsInitialized) {
    465             sHasNfcFeature = hasNfcFeature();
    466             boolean hasHceFeature = hasNfcHceFeature();
    467             /* is this device meant to have NFC */
    468             if (!sHasNfcFeature && !hasHceFeature) {
    469                 Log.v(TAG, "this device does not have NFC support");
    470                 throw new UnsupportedOperationException();
    471             }
    472             sService = getServiceInterface();
    473             if (sService == null) {
    474                 Log.e(TAG, "could not retrieve NFC service");
    475                 throw new UnsupportedOperationException();
    476             }
    477             if (sHasNfcFeature) {
    478                 try {
    479                     sTagService = sService.getNfcTagInterface();
    480                 } catch (RemoteException e) {
    481                     Log.e(TAG, "could not retrieve NFC Tag service");
    482                     throw new UnsupportedOperationException();
    483                 }
    484             }
    485             if (hasHceFeature) {
    486                 try {
    487                     sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
    488                 } catch (RemoteException e) {
    489                     Log.e(TAG, "could not retrieve NFC-F card emulation service");
    490                     throw new UnsupportedOperationException();
    491                 }
    492                 try {
    493                     sCardEmulationService = sService.getNfcCardEmulationInterface();
    494                 } catch (RemoteException e) {
    495                     Log.e(TAG, "could not retrieve card emulation service");
    496                     throw new UnsupportedOperationException();
    497                 }
    498             }
    499 
    500             sIsInitialized = true;
    501         }
    502         if (context == null) {
    503             if (sNullContextNfcAdapter == null) {
    504                 sNullContextNfcAdapter = new NfcAdapter(null);
    505             }
    506             return sNullContextNfcAdapter;
    507         }
    508         NfcAdapter adapter = sNfcAdapters.get(context);
    509         if (adapter == null) {
    510             adapter = new NfcAdapter(context);
    511             sNfcAdapters.put(context, adapter);
    512         }
    513         return adapter;
    514     }
    515 
    516     /** get handle to NFC service interface */
    517     private static INfcAdapter getServiceInterface() {
    518         /* get a handle to NFC service */
    519         IBinder b = ServiceManager.getService("nfc");
    520         if (b == null) {
    521             return null;
    522         }
    523         return INfcAdapter.Stub.asInterface(b);
    524     }
    525 
    526     /**
    527      * Helper to get the default NFC Adapter.
    528      * <p>
    529      * Most Android devices will only have one NFC Adapter (NFC Controller).
    530      * <p>
    531      * This helper is the equivalent of:
    532      * <pre>
    533      * NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
    534      * NfcAdapter adapter = manager.getDefaultAdapter();</pre>
    535      * @param context the calling application's context
    536      *
    537      * @return the default NFC adapter, or null if no NFC adapter exists
    538      */
    539     public static NfcAdapter getDefaultAdapter(Context context) {
    540         if (context == null) {
    541             throw new IllegalArgumentException("context cannot be null");
    542         }
    543         context = context.getApplicationContext();
    544         if (context == null) {
    545             throw new IllegalArgumentException(
    546                     "context not associated with any application (using a mock context?)");
    547         }
    548         /* use getSystemService() for consistency */
    549         NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
    550         if (manager == null) {
    551             // NFC not available
    552             return null;
    553         }
    554         return manager.getDefaultAdapter();
    555     }
    556 
    557     /**
    558      * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
    559      * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
    560      * for many NFC API methods. Those methods will fail when called on an NfcAdapter
    561      * object created from this method.<p>
    562      * @deprecated use {@link #getDefaultAdapter(Context)}
    563      * @hide
    564      */
    565     @Deprecated
    566     public static NfcAdapter getDefaultAdapter() {
    567         // introduced in API version 9 (GB 2.3)
    568         // deprecated in API version 10 (GB 2.3.3)
    569         // removed from public API in version 16 (ICS MR2)
    570         // should maintain as a hidden API for binary compatibility for a little longer
    571         Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
    572                 "NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
    573 
    574         return NfcAdapter.getNfcAdapter(null);
    575     }
    576 
    577     NfcAdapter(Context context) {
    578         mContext = context;
    579         mNfcActivityManager = new NfcActivityManager(this);
    580         mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
    581         mTagRemovedListener = null;
    582         mLock = new Object();
    583     }
    584 
    585     /**
    586      * @hide
    587      */
    588     public Context getContext() {
    589         return mContext;
    590     }
    591 
    592     /**
    593      * Returns the binder interface to the service.
    594      * @hide
    595      */
    596     public INfcAdapter getService() {
    597         isEnabled();  // NOP call to recover sService if it is stale
    598         return sService;
    599     }
    600 
    601     /**
    602      * Returns the binder interface to the tag service.
    603      * @hide
    604      */
    605     public INfcTag getTagService() {
    606         isEnabled();  // NOP call to recover sTagService if it is stale
    607         return sTagService;
    608     }
    609 
    610     /**
    611      * Returns the binder interface to the card emulation service.
    612      * @hide
    613      */
    614     public INfcCardEmulation getCardEmulationService() {
    615         isEnabled();
    616         return sCardEmulationService;
    617     }
    618 
    619     /**
    620      * Returns the binder interface to the NFC-F card emulation service.
    621      * @hide
    622      */
    623     public INfcFCardEmulation getNfcFCardEmulationService() {
    624         isEnabled();
    625         return sNfcFCardEmulationService;
    626     }
    627 
    628     /**
    629      * NFC service dead - attempt best effort recovery
    630      * @hide
    631      */
    632     public void attemptDeadServiceRecovery(Exception e) {
    633         Log.e(TAG, "NFC service dead - attempting to recover", e);
    634         INfcAdapter service = getServiceInterface();
    635         if (service == null) {
    636             Log.e(TAG, "could not retrieve NFC service during service recovery");
    637             // nothing more can be done now, sService is still stale, we'll hit
    638             // this recovery path again later
    639             return;
    640         }
    641         // assigning to sService is not thread-safe, but this is best-effort code
    642         // and on a well-behaved system should never happen
    643         sService = service;
    644         try {
    645             sTagService = service.getNfcTagInterface();
    646         } catch (RemoteException ee) {
    647             Log.e(TAG, "could not retrieve NFC tag service during service recovery");
    648             // nothing more can be done now, sService is still stale, we'll hit
    649             // this recovery path again later
    650             return;
    651         }
    652 
    653         try {
    654             sCardEmulationService = service.getNfcCardEmulationInterface();
    655         } catch (RemoteException ee) {
    656             Log.e(TAG, "could not retrieve NFC card emulation service during service recovery");
    657         }
    658 
    659         try {
    660             sNfcFCardEmulationService = service.getNfcFCardEmulationInterface();
    661         } catch (RemoteException ee) {
    662             Log.e(TAG, "could not retrieve NFC-F card emulation service during service recovery");
    663         }
    664 
    665         return;
    666     }
    667 
    668     /**
    669      * Return true if this NFC Adapter has any features enabled.
    670      *
    671      * <p>If this method returns false, the NFC hardware is guaranteed not to
    672      * generate or respond to any NFC communication over its NFC radio.
    673      * <p>Applications can use this to check if NFC is enabled. Applications
    674      * can request Settings UI allowing the user to toggle NFC using:
    675      * <p><pre>startActivity(new Intent(Settings.ACTION_NFC_SETTINGS))</pre>
    676      *
    677      * @see android.provider.Settings#ACTION_NFC_SETTINGS
    678      * @return true if this NFC Adapter has any features enabled
    679      */
    680     public boolean isEnabled() {
    681         try {
    682             return sService.getState() == STATE_ON;
    683         } catch (RemoteException e) {
    684             attemptDeadServiceRecovery(e);
    685             return false;
    686         }
    687     }
    688 
    689     /**
    690      * Return the state of this NFC Adapter.
    691      *
    692      * <p>Returns one of {@link #STATE_ON}, {@link #STATE_TURNING_ON},
    693      * {@link #STATE_OFF}, {@link #STATE_TURNING_OFF}.
    694      *
    695      * <p>{@link #isEnabled()} is equivalent to
    696      * <code>{@link #getAdapterState()} == {@link #STATE_ON}</code>
    697      *
    698      * @return the current state of this NFC adapter
    699      *
    700      * @hide
    701      */
    702     public int getAdapterState() {
    703         try {
    704             return sService.getState();
    705         } catch (RemoteException e) {
    706             attemptDeadServiceRecovery(e);
    707             return NfcAdapter.STATE_OFF;
    708         }
    709     }
    710 
    711     /**
    712      * Enable NFC hardware.
    713      *
    714      * <p>This call is asynchronous. Listen for
    715      * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
    716      * operation is complete.
    717      *
    718      * <p>If this returns true, then either NFC is already on, or
    719      * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
    720      * to indicate a state transition. If this returns false, then
    721      * there is some problem that prevents an attempt to turn
    722      * NFC on (for example we are in airplane mode and NFC is not
    723      * toggleable in airplane mode on this platform).
    724      *
    725      * @hide
    726      */
    727     @SystemApi
    728     public boolean enable() {
    729         try {
    730             return sService.enable();
    731         } catch (RemoteException e) {
    732             attemptDeadServiceRecovery(e);
    733             return false;
    734         }
    735     }
    736 
    737     /**
    738      * Disable NFC hardware.
    739      *
    740      * <p>No NFC features will work after this call, and the hardware
    741      * will not perform or respond to any NFC communication.
    742      *
    743      * <p>This call is asynchronous. Listen for
    744      * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
    745      * operation is complete.
    746      *
    747      * <p>If this returns true, then either NFC is already off, or
    748      * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
    749      * to indicate a state transition. If this returns false, then
    750      * there is some problem that prevents an attempt to turn
    751      * NFC off.
    752      *
    753      * @hide
    754      */
    755     @SystemApi
    756     public boolean disable() {
    757         try {
    758             return sService.disable(true);
    759         } catch (RemoteException e) {
    760             attemptDeadServiceRecovery(e);
    761             return false;
    762         }
    763     }
    764 
    765     /**
    766      * Disable NFC hardware.
    767      * @hide
    768     */
    769     @SystemApi
    770     public boolean disable(boolean persist) {
    771         try {
    772             return sService.disable(persist);
    773         } catch (RemoteException e) {
    774             attemptDeadServiceRecovery(e);
    775             return false;
    776         }
    777     }
    778 
    779     /**
    780      * Pauses polling for a {@code timeoutInMs} millis. If polling must be resumed before timeout,
    781      * use {@link #resumePolling()}.
    782      * @hide
    783      */
    784     public void pausePolling(int timeoutInMs) {
    785         try {
    786             sService.pausePolling(timeoutInMs);
    787         } catch (RemoteException e) {
    788             attemptDeadServiceRecovery(e);
    789         }
    790     }
    791 
    792     /**
    793      * Resumes default polling for the current device state if polling is paused. Calling
    794      * this while polling is not paused is a no-op.
    795      *
    796      * @hide
    797      */
    798     public void resumePolling() {
    799         try {
    800             sService.resumePolling();
    801         } catch (RemoteException e) {
    802             attemptDeadServiceRecovery(e);
    803         }
    804     }
    805 
    806     /**
    807      * Set one or more {@link Uri}s to send using Android Beam (TM). Every
    808      * Uri you provide must have either scheme 'file' or scheme 'content'.
    809      *
    810      * <p>For the data provided through this method, Android Beam tries to
    811      * switch to alternate transports such as Bluetooth to achieve a fast
    812      * transfer speed. Hence this method is very suitable
    813      * for transferring large files such as pictures or songs.
    814      *
    815      * <p>The receiving side will store the content of each Uri in
    816      * a file and present a notification to the user to open the file
    817      * with a {@link android.content.Intent} with action
    818      * {@link android.content.Intent#ACTION_VIEW}.
    819      * If multiple URIs are sent, the {@link android.content.Intent} will refer
    820      * to the first of the stored files.
    821      *
    822      * <p>This method may be called at any time before {@link Activity#onDestroy},
    823      * but the URI(s) are only made available for Android Beam when the
    824      * specified activity(s) are in resumed (foreground) state. The recommended
    825      * approach is to call this method during your Activity's
    826      * {@link Activity#onCreate} - see sample
    827      * code below. This method does not immediately perform any I/O or blocking work,
    828      * so is safe to call on your main thread.
    829      *
    830      * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
    831      * have priority over both {@link #setNdefPushMessage} and
    832      * {@link #setNdefPushMessageCallback}.
    833      *
    834      * <p>If {@link #setBeamPushUris} is called with a null Uri array,
    835      * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
    836      * then the Uri push will be completely disabled for the specified activity(s).
    837      *
    838      * <p>Code example:
    839      * <pre>
    840      * protected void onCreate(Bundle savedInstanceState) {
    841      *     super.onCreate(savedInstanceState);
    842      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    843      *     if (nfcAdapter == null) return;  // NFC not available on this device
    844      *     nfcAdapter.setBeamPushUris(new Uri[] {uri1, uri2}, this);
    845      * }</pre>
    846      * And that is it. Only one call per activity is necessary. The Android
    847      * OS will automatically release its references to the Uri(s) and the
    848      * Activity object when it is destroyed if you follow this pattern.
    849      *
    850      * <p>If your Activity wants to dynamically supply Uri(s),
    851      * then set a callback using {@link #setBeamPushUrisCallback} instead
    852      * of using this method.
    853      *
    854      * <p class="note">Do not pass in an Activity that has already been through
    855      * {@link Activity#onDestroy}. This is guaranteed if you call this API
    856      * during {@link Activity#onCreate}.
    857      *
    858      * <p class="note">If this device does not support alternate transports
    859      * such as Bluetooth or WiFI, calling this method does nothing.
    860      *
    861      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
    862      *
    863      * @param uris an array of Uri(s) to push over Android Beam
    864      * @param activity activity for which the Uri(s) will be pushed
    865      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
    866      */
    867     public void setBeamPushUris(Uri[] uris, Activity activity) {
    868         synchronized (NfcAdapter.class) {
    869             if (!sHasNfcFeature) {
    870                 throw new UnsupportedOperationException();
    871             }
    872         }
    873         if (activity == null) {
    874             throw new NullPointerException("activity cannot be null");
    875         }
    876         if (uris != null) {
    877             for (Uri uri : uris) {
    878                 if (uri == null) throw new NullPointerException("Uri not " +
    879                         "allowed to be null");
    880                 String scheme = uri.getScheme();
    881                 if (scheme == null || (!scheme.equalsIgnoreCase("file") &&
    882                         !scheme.equalsIgnoreCase("content"))) {
    883                     throw new IllegalArgumentException("URI needs to have " +
    884                             "either scheme file or scheme content");
    885                 }
    886             }
    887         }
    888         mNfcActivityManager.setNdefPushContentUri(activity, uris);
    889     }
    890 
    891     /**
    892      * Set a callback that will dynamically generate one or more {@link Uri}s
    893      * to send using Android Beam (TM). Every Uri the callback provides
    894      * must have either scheme 'file' or scheme 'content'.
    895      *
    896      * <p>For the data provided through this callback, Android Beam tries to
    897      * switch to alternate transports such as Bluetooth to achieve a fast
    898      * transfer speed. Hence this method is very suitable
    899      * for transferring large files such as pictures or songs.
    900      *
    901      * <p>The receiving side will store the content of each Uri in
    902      * a file and present a notification to the user to open the file
    903      * with a {@link android.content.Intent} with action
    904      * {@link android.content.Intent#ACTION_VIEW}.
    905      * If multiple URIs are sent, the {@link android.content.Intent} will refer
    906      * to the first of the stored files.
    907      *
    908      * <p>This method may be called at any time before {@link Activity#onDestroy},
    909      * but the URI(s) are only made available for Android Beam when the
    910      * specified activity(s) are in resumed (foreground) state. The recommended
    911      * approach is to call this method during your Activity's
    912      * {@link Activity#onCreate} - see sample
    913      * code below. This method does not immediately perform any I/O or blocking work,
    914      * so is safe to call on your main thread.
    915      *
    916      * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
    917      * have priority over both {@link #setNdefPushMessage} and
    918      * {@link #setNdefPushMessageCallback}.
    919      *
    920      * <p>If {@link #setBeamPushUris} is called with a null Uri array,
    921      * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
    922      * then the Uri push will be completely disabled for the specified activity(s).
    923      *
    924      * <p>Code example:
    925      * <pre>
    926      * protected void onCreate(Bundle savedInstanceState) {
    927      *     super.onCreate(savedInstanceState);
    928      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
    929      *     if (nfcAdapter == null) return;  // NFC not available on this device
    930      *     nfcAdapter.setBeamPushUrisCallback(callback, this);
    931      * }</pre>
    932      * And that is it. Only one call per activity is necessary. The Android
    933      * OS will automatically release its references to the Uri(s) and the
    934      * Activity object when it is destroyed if you follow this pattern.
    935      *
    936      * <p class="note">Do not pass in an Activity that has already been through
    937      * {@link Activity#onDestroy}. This is guaranteed if you call this API
    938      * during {@link Activity#onCreate}.
    939      *
    940      * <p class="note">If this device does not support alternate transports
    941      * such as Bluetooth or WiFI, calling this method does nothing.
    942      *
    943      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
    944      *
    945      * @param callback callback, or null to disable
    946      * @param activity activity for which the Uri(s) will be pushed
    947      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
    948      */
    949     public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
    950         synchronized (NfcAdapter.class) {
    951             if (!sHasNfcFeature) {
    952                 throw new UnsupportedOperationException();
    953             }
    954         }
    955         if (activity == null) {
    956             throw new NullPointerException("activity cannot be null");
    957         }
    958         mNfcActivityManager.setNdefPushContentUriCallback(activity, callback);
    959     }
    960 
    961     /**
    962      * Set a static {@link NdefMessage} to send using Android Beam (TM).
    963      *
    964      * <p>This method may be called at any time before {@link Activity#onDestroy},
    965      * but the NDEF message is only made available for NDEF push when the
    966      * specified activity(s) are in resumed (foreground) state. The recommended
    967      * approach is to call this method during your Activity's
    968      * {@link Activity#onCreate} - see sample
    969      * code below. This method does not immediately perform any I/O or blocking work,
    970      * so is safe to call on your main thread.
    971      *
    972      * <p>Only one NDEF message can be pushed by the currently resumed activity.
    973      * If both {@link #setNdefPushMessage} and
    974      * {@link #setNdefPushMessageCallback} are set, then
    975      * the callback will take priority.
    976      *
    977      * <p>If neither {@link #setNdefPushMessage} or
    978      * {@link #setNdefPushMessageCallback} have been called for your activity, then
    979      * the Android OS may choose to send a default NDEF message on your behalf,
    980      * such as a URI for your application.
    981      *
    982      * <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
    983      * and/or {@link #setNdefPushMessageCallback} is called with a null callback,
    984      * then NDEF push will be completely disabled for the specified activity(s).
    985      * This also disables any default NDEF message the Android OS would have
    986      * otherwise sent on your behalf for those activity(s).
    987      *
    988      * <p>If you want to prevent the Android OS from sending default NDEF
    989      * messages completely (for all activities), you can include a
    990      * {@code <meta-data>} element inside the {@code <application>}
    991      * element of your AndroidManifest.xml file, like this:
    992      * <pre>
    993      * &lt;application ...>
    994      *     &lt;meta-data android:name="android.nfc.disable_beam_default"
    995      *         android:value="true" />
    996      * &lt;/application></pre>
    997      *
    998      * <p>The API allows for multiple activities to be specified at a time,
    999      * but it is strongly recommended to just register one at a time,
   1000      * and to do so during the activity's {@link Activity#onCreate}. For example:
   1001      * <pre>
   1002      * protected void onCreate(Bundle savedInstanceState) {
   1003      *     super.onCreate(savedInstanceState);
   1004      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
   1005      *     if (nfcAdapter == null) return;  // NFC not available on this device
   1006      *     nfcAdapter.setNdefPushMessage(ndefMessage, this);
   1007      * }</pre>
   1008      * And that is it. Only one call per activity is necessary. The Android
   1009      * OS will automatically release its references to the NDEF message and the
   1010      * Activity object when it is destroyed if you follow this pattern.
   1011      *
   1012      * <p>If your Activity wants to dynamically generate an NDEF message,
   1013      * then set a callback using {@link #setNdefPushMessageCallback} instead
   1014      * of a static message.
   1015      *
   1016      * <p class="note">Do not pass in an Activity that has already been through
   1017      * {@link Activity#onDestroy}. This is guaranteed if you call this API
   1018      * during {@link Activity#onCreate}.
   1019      *
   1020      * <p class="note">For sending large content such as pictures and songs,
   1021      * consider using {@link #setBeamPushUris}, which switches to alternate transports
   1022      * such as Bluetooth to achieve a fast transfer rate.
   1023      *
   1024      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
   1025      *
   1026      * @param message NDEF message to push over NFC, or null to disable
   1027      * @param activity activity for which the NDEF message will be pushed
   1028      * @param activities optional additional activities, however we strongly recommend
   1029      *        to only register one at a time, and to do so in that activity's
   1030      *        {@link Activity#onCreate}
   1031      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1032      */
   1033     public void setNdefPushMessage(NdefMessage message, Activity activity,
   1034             Activity ... activities) {
   1035         synchronized (NfcAdapter.class) {
   1036             if (!sHasNfcFeature) {
   1037                 throw new UnsupportedOperationException();
   1038             }
   1039         }
   1040         int targetSdkVersion = getSdkVersion();
   1041         try {
   1042             if (activity == null) {
   1043                 throw new NullPointerException("activity cannot be null");
   1044             }
   1045             mNfcActivityManager.setNdefPushMessage(activity, message, 0);
   1046             for (Activity a : activities) {
   1047                 if (a == null) {
   1048                     throw new NullPointerException("activities cannot contain null");
   1049                 }
   1050                 mNfcActivityManager.setNdefPushMessage(a, message, 0);
   1051             }
   1052         } catch (IllegalStateException e) {
   1053             if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
   1054                 // Less strict on old applications - just log the error
   1055                 Log.e(TAG, "Cannot call API with Activity that has already " +
   1056                         "been destroyed", e);
   1057             } else {
   1058                 // Prevent new applications from making this mistake, re-throw
   1059                 throw(e);
   1060             }
   1061         }
   1062     }
   1063 
   1064     /**
   1065      * @hide
   1066      */
   1067     @SystemApi
   1068     public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
   1069         synchronized (NfcAdapter.class) {
   1070             if (!sHasNfcFeature) {
   1071                 throw new UnsupportedOperationException();
   1072             }
   1073         }
   1074         if (activity == null) {
   1075             throw new NullPointerException("activity cannot be null");
   1076         }
   1077         mNfcActivityManager.setNdefPushMessage(activity, message, flags);
   1078     }
   1079 
   1080     /**
   1081      * Set a callback that dynamically generates NDEF messages to send using Android Beam (TM).
   1082      *
   1083      * <p>This method may be called at any time before {@link Activity#onDestroy},
   1084      * but the NDEF message callback can only occur when the
   1085      * specified activity(s) are in resumed (foreground) state. The recommended
   1086      * approach is to call this method during your Activity's
   1087      * {@link Activity#onCreate} - see sample
   1088      * code below. This method does not immediately perform any I/O or blocking work,
   1089      * so is safe to call on your main thread.
   1090      *
   1091      * <p>Only one NDEF message can be pushed by the currently resumed activity.
   1092      * If both {@link #setNdefPushMessage} and
   1093      * {@link #setNdefPushMessageCallback} are set, then
   1094      * the callback will take priority.
   1095      *
   1096      * <p>If neither {@link #setNdefPushMessage} or
   1097      * {@link #setNdefPushMessageCallback} have been called for your activity, then
   1098      * the Android OS may choose to send a default NDEF message on your behalf,
   1099      * such as a URI for your application.
   1100      *
   1101      * <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
   1102      * and/or {@link #setNdefPushMessageCallback} is called with a null callback,
   1103      * then NDEF push will be completely disabled for the specified activity(s).
   1104      * This also disables any default NDEF message the Android OS would have
   1105      * otherwise sent on your behalf for those activity(s).
   1106      *
   1107      * <p>If you want to prevent the Android OS from sending default NDEF
   1108      * messages completely (for all activities), you can include a
   1109      * {@code <meta-data>} element inside the {@code <application>}
   1110      * element of your AndroidManifest.xml file, like this:
   1111      * <pre>
   1112      * &lt;application ...>
   1113      *     &lt;meta-data android:name="android.nfc.disable_beam_default"
   1114      *         android:value="true" />
   1115      * &lt;/application></pre>
   1116      *
   1117      * <p>The API allows for multiple activities to be specified at a time,
   1118      * but it is strongly recommended to just register one at a time,
   1119      * and to do so during the activity's {@link Activity#onCreate}. For example:
   1120      * <pre>
   1121      * protected void onCreate(Bundle savedInstanceState) {
   1122      *     super.onCreate(savedInstanceState);
   1123      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
   1124      *     if (nfcAdapter == null) return;  // NFC not available on this device
   1125      *     nfcAdapter.setNdefPushMessageCallback(callback, this);
   1126      * }</pre>
   1127      * And that is it. Only one call per activity is necessary. The Android
   1128      * OS will automatically release its references to the callback and the
   1129      * Activity object when it is destroyed if you follow this pattern.
   1130      *
   1131      * <p class="note">Do not pass in an Activity that has already been through
   1132      * {@link Activity#onDestroy}. This is guaranteed if you call this API
   1133      * during {@link Activity#onCreate}.
   1134      * <p class="note">For sending large content such as pictures and songs,
   1135      * consider using {@link #setBeamPushUris}, which switches to alternate transports
   1136      * such as Bluetooth to achieve a fast transfer rate.
   1137      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
   1138      *
   1139      * @param callback callback, or null to disable
   1140      * @param activity activity for which the NDEF message will be pushed
   1141      * @param activities optional additional activities, however we strongly recommend
   1142      *        to only register one at a time, and to do so in that activity's
   1143      *        {@link Activity#onCreate}
   1144      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1145      */
   1146     public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
   1147             Activity ... activities) {
   1148         synchronized (NfcAdapter.class) {
   1149             if (!sHasNfcFeature) {
   1150                 throw new UnsupportedOperationException();
   1151             }
   1152         }
   1153         int targetSdkVersion = getSdkVersion();
   1154         try {
   1155             if (activity == null) {
   1156                 throw new NullPointerException("activity cannot be null");
   1157             }
   1158             mNfcActivityManager.setNdefPushMessageCallback(activity, callback, 0);
   1159             for (Activity a : activities) {
   1160                 if (a == null) {
   1161                     throw new NullPointerException("activities cannot contain null");
   1162                 }
   1163                 mNfcActivityManager.setNdefPushMessageCallback(a, callback, 0);
   1164             }
   1165         } catch (IllegalStateException e) {
   1166             if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
   1167                 // Less strict on old applications - just log the error
   1168                 Log.e(TAG, "Cannot call API with Activity that has already " +
   1169                         "been destroyed", e);
   1170             } else {
   1171                 // Prevent new applications from making this mistake, re-throw
   1172                 throw(e);
   1173             }
   1174         }
   1175     }
   1176 
   1177     /**
   1178      * @hide
   1179      */
   1180     public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
   1181             int flags) {
   1182         if (activity == null) {
   1183             throw new NullPointerException("activity cannot be null");
   1184         }
   1185         mNfcActivityManager.setNdefPushMessageCallback(activity, callback, flags);
   1186     }
   1187 
   1188     /**
   1189      * Set a callback on successful Android Beam (TM).
   1190      *
   1191      * <p>This method may be called at any time before {@link Activity#onDestroy},
   1192      * but the callback can only occur when the
   1193      * specified activity(s) are in resumed (foreground) state. The recommended
   1194      * approach is to call this method during your Activity's
   1195      * {@link Activity#onCreate} - see sample
   1196      * code below. This method does not immediately perform any I/O or blocking work,
   1197      * so is safe to call on your main thread.
   1198      *
   1199      * <p>The API allows for multiple activities to be specified at a time,
   1200      * but it is strongly recommended to just register one at a time,
   1201      * and to do so during the activity's {@link Activity#onCreate}. For example:
   1202      * <pre>
   1203      * protected void onCreate(Bundle savedInstanceState) {
   1204      *     super.onCreate(savedInstanceState);
   1205      *     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
   1206      *     if (nfcAdapter == null) return;  // NFC not available on this device
   1207      *     nfcAdapter.setOnNdefPushCompleteCallback(callback, this);
   1208      * }</pre>
   1209      * And that is it. Only one call per activity is necessary. The Android
   1210      * OS will automatically release its references to the callback and the
   1211      * Activity object when it is destroyed if you follow this pattern.
   1212      *
   1213      * <p class="note">Do not pass in an Activity that has already been through
   1214      * {@link Activity#onDestroy}. This is guaranteed if you call this API
   1215      * during {@link Activity#onCreate}.
   1216      *
   1217      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
   1218      *
   1219      * @param callback callback, or null to disable
   1220      * @param activity activity for which the NDEF message will be pushed
   1221      * @param activities optional additional activities, however we strongly recommend
   1222      *        to only register one at a time, and to do so in that activity's
   1223      *        {@link Activity#onCreate}
   1224      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1225      */
   1226     public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
   1227             Activity activity, Activity ... activities) {
   1228         synchronized (NfcAdapter.class) {
   1229             if (!sHasNfcFeature) {
   1230                 throw new UnsupportedOperationException();
   1231             }
   1232         }
   1233         int targetSdkVersion = getSdkVersion();
   1234         try {
   1235             if (activity == null) {
   1236                 throw new NullPointerException("activity cannot be null");
   1237             }
   1238             mNfcActivityManager.setOnNdefPushCompleteCallback(activity, callback);
   1239             for (Activity a : activities) {
   1240                 if (a == null) {
   1241                     throw new NullPointerException("activities cannot contain null");
   1242                 }
   1243                 mNfcActivityManager.setOnNdefPushCompleteCallback(a, callback);
   1244             }
   1245         } catch (IllegalStateException e) {
   1246             if (targetSdkVersion < android.os.Build.VERSION_CODES.JELLY_BEAN) {
   1247                 // Less strict on old applications - just log the error
   1248                 Log.e(TAG, "Cannot call API with Activity that has already " +
   1249                         "been destroyed", e);
   1250             } else {
   1251                 // Prevent new applications from making this mistake, re-throw
   1252                 throw(e);
   1253             }
   1254         }
   1255     }
   1256 
   1257     /**
   1258      * Enable foreground dispatch to the given Activity.
   1259      *
   1260      * <p>This will give give priority to the foreground activity when
   1261      * dispatching a discovered {@link Tag} to an application.
   1262      *
   1263      * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents
   1264      * for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and
   1265      * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED}
   1266      * relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled
   1267      * by passing in the tech lists separately. Each first level entry in the tech list represents
   1268      * an array of technologies that must all be present to match. If any of the first level sets
   1269      * match then the dispatch is routed through the given PendingIntent. In other words, the second
   1270      * level is ANDed together and the first level entries are ORed together.
   1271      *
   1272      * <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters
   1273      * that acts a wild card and will cause the foreground activity to receive all tags via the
   1274      * {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent.
   1275      *
   1276      * <p>This method must be called from the main thread, and only when the activity is in the
   1277      * foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before
   1278      * the completion of their {@link Activity#onPause} callback to disable foreground dispatch
   1279      * after it has been enabled.
   1280      *
   1281      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
   1282      *
   1283      * @param activity the Activity to dispatch to
   1284      * @param intent the PendingIntent to start for the dispatch
   1285      * @param filters the IntentFilters to override dispatching for, or null to always dispatch
   1286      * @param techLists the tech lists used to perform matching for dispatching of the
   1287      *      {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent
   1288      * @throws IllegalStateException if the Activity is not currently in the foreground
   1289      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1290      */
   1291     public void enableForegroundDispatch(Activity activity, PendingIntent intent,
   1292             IntentFilter[] filters, String[][] techLists) {
   1293         synchronized (NfcAdapter.class) {
   1294             if (!sHasNfcFeature) {
   1295                 throw new UnsupportedOperationException();
   1296             }
   1297         }
   1298         if (activity == null || intent == null) {
   1299             throw new NullPointerException();
   1300         }
   1301         if (!activity.isResumed()) {
   1302             throw new IllegalStateException("Foreground dispatch can only be enabled " +
   1303                     "when your activity is resumed");
   1304         }
   1305         try {
   1306             TechListParcel parcel = null;
   1307             if (techLists != null && techLists.length > 0) {
   1308                 parcel = new TechListParcel(techLists);
   1309             }
   1310             ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
   1311                     mForegroundDispatchListener);
   1312             sService.setForegroundDispatch(intent, filters, parcel);
   1313         } catch (RemoteException e) {
   1314             attemptDeadServiceRecovery(e);
   1315         }
   1316     }
   1317 
   1318     /**
   1319      * Disable foreground dispatch to the given activity.
   1320      *
   1321      * <p>After calling {@link #enableForegroundDispatch}, an activity
   1322      * must call this method before its {@link Activity#onPause} callback
   1323      * completes.
   1324      *
   1325      * <p>This method must be called from the main thread.
   1326      *
   1327      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
   1328      *
   1329      * @param activity the Activity to disable dispatch to
   1330      * @throws IllegalStateException if the Activity has already been paused
   1331      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1332      */
   1333     public void disableForegroundDispatch(Activity activity) {
   1334         synchronized (NfcAdapter.class) {
   1335             if (!sHasNfcFeature) {
   1336                 throw new UnsupportedOperationException();
   1337             }
   1338         }
   1339         ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
   1340                 mForegroundDispatchListener);
   1341         disableForegroundDispatchInternal(activity, false);
   1342     }
   1343 
   1344     OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() {
   1345         @Override
   1346         public void onPaused(Activity activity) {
   1347             disableForegroundDispatchInternal(activity, true);
   1348         }
   1349     };
   1350 
   1351     void disableForegroundDispatchInternal(Activity activity, boolean force) {
   1352         try {
   1353             sService.setForegroundDispatch(null, null, null);
   1354             if (!force && !activity.isResumed()) {
   1355                 throw new IllegalStateException("You must disable foreground dispatching " +
   1356                         "while your activity is still resumed");
   1357             }
   1358         } catch (RemoteException e) {
   1359             attemptDeadServiceRecovery(e);
   1360         }
   1361     }
   1362 
   1363     /**
   1364      * Limit the NFC controller to reader mode while this Activity is in the foreground.
   1365      *
   1366      * <p>In this mode the NFC controller will only act as an NFC tag reader/writer,
   1367      * thus disabling any peer-to-peer (Android Beam) and card-emulation modes of
   1368      * the NFC adapter on this device.
   1369      *
   1370      * <p>Use {@link #FLAG_READER_SKIP_NDEF_CHECK} to prevent the platform from
   1371      * performing any NDEF checks in reader mode. Note that this will prevent the
   1372      * {@link Ndef} tag technology from being enumerated on the tag, and that
   1373      * NDEF-based tag dispatch will not be functional.
   1374      *
   1375      * <p>For interacting with tags that are emulated on another Android device
   1376      * using Android's host-based card-emulation, the recommended flags are
   1377      * {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}.
   1378      *
   1379      * @param activity the Activity that requests the adapter to be in reader mode
   1380      * @param callback the callback to be called when a tag is discovered
   1381      * @param flags Flags indicating poll technologies and other optional parameters
   1382      * @param extras Additional extras for configuring reader mode.
   1383      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1384      */
   1385     public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
   1386             Bundle extras) {
   1387         synchronized (NfcAdapter.class) {
   1388             if (!sHasNfcFeature) {
   1389                 throw new UnsupportedOperationException();
   1390             }
   1391         }
   1392         mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
   1393     }
   1394 
   1395     /**
   1396      * Restore the NFC adapter to normal mode of operation: supporting
   1397      * peer-to-peer (Android Beam), card emulation, and polling for
   1398      * all supported tag technologies.
   1399      *
   1400      * @param activity the Activity that currently has reader mode enabled
   1401      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1402      */
   1403     public void disableReaderMode(Activity activity) {
   1404         synchronized (NfcAdapter.class) {
   1405             if (!sHasNfcFeature) {
   1406                 throw new UnsupportedOperationException();
   1407             }
   1408         }
   1409         mNfcActivityManager.disableReaderMode(activity);
   1410     }
   1411 
   1412     /**
   1413      * Manually invoke Android Beam to share data.
   1414      *
   1415      * <p>The Android Beam animation is normally only shown when two NFC-capable
   1416      * devices come into range.
   1417      * By calling this method, an Activity can invoke the Beam animation directly
   1418      * even if no other NFC device is in range yet. The Beam animation will then
   1419      * prompt the user to tap another NFC-capable device to complete the data
   1420      * transfer.
   1421      *
   1422      * <p>The main advantage of using this method is that it avoids the need for the
   1423      * user to tap the screen to complete the transfer, as this method already
   1424      * establishes the direction of the transfer and the consent of the user to
   1425      * share data. Callers are responsible for making sure that the user has
   1426      * consented to sharing data on NFC tap.
   1427      *
   1428      * <p>Note that to use this method, the passed in Activity must have already
   1429      * set data to share over Beam by using method calls such as
   1430      * {@link #setNdefPushMessageCallback} or
   1431      * {@link #setBeamPushUrisCallback}.
   1432      *
   1433      * @param activity the current foreground Activity that has registered data to share
   1434      * @return whether the Beam animation was successfully invoked
   1435      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1436      */
   1437     public boolean invokeBeam(Activity activity) {
   1438         synchronized (NfcAdapter.class) {
   1439             if (!sHasNfcFeature) {
   1440                 throw new UnsupportedOperationException();
   1441             }
   1442         }
   1443         if (activity == null) {
   1444             throw new NullPointerException("activity may not be null.");
   1445         }
   1446         enforceResumed(activity);
   1447         try {
   1448             sService.invokeBeam();
   1449             return true;
   1450         } catch (RemoteException e) {
   1451             Log.e(TAG, "invokeBeam: NFC process has died.");
   1452             attemptDeadServiceRecovery(e);
   1453             return false;
   1454         }
   1455     }
   1456 
   1457     /**
   1458      * @hide
   1459      */
   1460     public boolean invokeBeam(BeamShareData shareData) {
   1461         try {
   1462             Log.e(TAG, "invokeBeamInternal()");
   1463             sService.invokeBeamInternal(shareData);
   1464             return true;
   1465         } catch (RemoteException e) {
   1466             Log.e(TAG, "invokeBeam: NFC process has died.");
   1467             attemptDeadServiceRecovery(e);
   1468             return false;
   1469         }
   1470     }
   1471 
   1472     /**
   1473      * Enable NDEF message push over NFC while this Activity is in the foreground.
   1474      *
   1475      * <p>You must explicitly call this method every time the activity is
   1476      * resumed, and you must call {@link #disableForegroundNdefPush} before
   1477      * your activity completes {@link Activity#onPause}.
   1478      *
   1479      * <p>Strongly recommend to use the new {@link #setNdefPushMessage}
   1480      * instead: it automatically hooks into your activity life-cycle,
   1481      * so you do not need to call enable/disable in your onResume/onPause.
   1482      *
   1483      * <p>For NDEF push to function properly the other NFC device must
   1484      * support either NFC Forum's SNEP (Simple Ndef Exchange Protocol), or
   1485      * Android's "com.android.npp" (Ndef Push Protocol). This was optional
   1486      * on Gingerbread level Android NFC devices, but SNEP is mandatory on
   1487      * Ice-Cream-Sandwich and beyond.
   1488      *
   1489      * <p>This method must be called from the main thread.
   1490      *
   1491      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
   1492      *
   1493      * @param activity foreground activity
   1494      * @param message a NDEF Message to push over NFC
   1495      * @throws IllegalStateException if the activity is not currently in the foreground
   1496      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1497      * @deprecated use {@link #setNdefPushMessage} instead
   1498      */
   1499     @Deprecated
   1500     public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
   1501         synchronized (NfcAdapter.class) {
   1502             if (!sHasNfcFeature) {
   1503                 throw new UnsupportedOperationException();
   1504             }
   1505         }
   1506         if (activity == null || message == null) {
   1507             throw new NullPointerException();
   1508         }
   1509         enforceResumed(activity);
   1510         mNfcActivityManager.setNdefPushMessage(activity, message, 0);
   1511     }
   1512 
   1513     /**
   1514      * Disable NDEF message push over P2P.
   1515      *
   1516      * <p>After calling {@link #enableForegroundNdefPush}, an activity
   1517      * must call this method before its {@link Activity#onPause} callback
   1518      * completes.
   1519      *
   1520      * <p>Strongly recommend to use the new {@link #setNdefPushMessage}
   1521      * instead: it automatically hooks into your activity life-cycle,
   1522      * so you do not need to call enable/disable in your onResume/onPause.
   1523      *
   1524      * <p>This method must be called from the main thread.
   1525      *
   1526      * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
   1527      *
   1528      * @param activity the Foreground activity
   1529      * @throws IllegalStateException if the Activity has already been paused
   1530      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1531      * @deprecated use {@link #setNdefPushMessage} instead
   1532      */
   1533     @Deprecated
   1534     public void disableForegroundNdefPush(Activity activity) {
   1535         synchronized (NfcAdapter.class) {
   1536             if (!sHasNfcFeature) {
   1537                 throw new UnsupportedOperationException();
   1538             }
   1539         }
   1540         if (activity == null) {
   1541             throw new NullPointerException();
   1542         }
   1543         enforceResumed(activity);
   1544         mNfcActivityManager.setNdefPushMessage(activity, null, 0);
   1545         mNfcActivityManager.setNdefPushMessageCallback(activity, null, 0);
   1546         mNfcActivityManager.setOnNdefPushCompleteCallback(activity, null);
   1547     }
   1548 
   1549     /**
   1550      * Enable NDEF Push feature.
   1551      * <p>This API is for the Settings application.
   1552      * @hide
   1553      */
   1554     @SystemApi
   1555     public boolean enableNdefPush() {
   1556         if (!sHasNfcFeature) {
   1557             throw new UnsupportedOperationException();
   1558         }
   1559         try {
   1560             return sService.enableNdefPush();
   1561         } catch (RemoteException e) {
   1562             attemptDeadServiceRecovery(e);
   1563             return false;
   1564         }
   1565     }
   1566 
   1567     /**
   1568      * Disable NDEF Push feature.
   1569      * <p>This API is for the Settings application.
   1570      * @hide
   1571      */
   1572     @SystemApi
   1573     public boolean disableNdefPush() {
   1574         synchronized (NfcAdapter.class) {
   1575             if (!sHasNfcFeature) {
   1576                 throw new UnsupportedOperationException();
   1577             }
   1578         }
   1579         try {
   1580             return sService.disableNdefPush();
   1581         } catch (RemoteException e) {
   1582             attemptDeadServiceRecovery(e);
   1583             return false;
   1584         }
   1585     }
   1586 
   1587     /**
   1588      * Return true if the NDEF Push (Android Beam) feature is enabled.
   1589      * <p>This function will return true only if both NFC is enabled, and the
   1590      * NDEF Push feature is enabled.
   1591      * <p>Note that if NFC is enabled but NDEF Push is disabled then this
   1592      * device can still <i>receive</i> NDEF messages, it just cannot send them.
   1593      * <p>Applications cannot directly toggle the NDEF Push feature, but they
   1594      * can request Settings UI allowing the user to toggle NDEF Push using
   1595      * <code>startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS))</code>
   1596      * <p>Example usage in an Activity that requires NDEF Push:
   1597      * <p><pre>
   1598      * protected void onResume() {
   1599      *     super.onResume();
   1600      *     if (!nfcAdapter.isEnabled()) {
   1601      *         startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
   1602      *     } else if (!nfcAdapter.isNdefPushEnabled()) {
   1603      *         startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS));
   1604      *     }
   1605      * }</pre>
   1606      *
   1607      * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
   1608      * @return true if NDEF Push feature is enabled
   1609      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
   1610      */
   1611     public boolean isNdefPushEnabled() {
   1612         synchronized (NfcAdapter.class) {
   1613             if (!sHasNfcFeature) {
   1614                 throw new UnsupportedOperationException();
   1615             }
   1616         }
   1617         try {
   1618             return sService.isNdefPushEnabled();
   1619         } catch (RemoteException e) {
   1620             attemptDeadServiceRecovery(e);
   1621             return false;
   1622         }
   1623     }
   1624 
   1625     /**
   1626      * Signals that you are no longer interested in communicating with an NFC tag
   1627      * for as long as it remains in range.
   1628      *
   1629      * All future attempted communication to this tag will fail with {@link IOException}.
   1630      * The NFC controller will be put in a low-power polling mode, allowing the device
   1631      * to save power in cases where it's "attached" to a tag all the time (e.g. a tag in
   1632      * car dock).
   1633      *
   1634      * Additionally the debounceMs parameter allows you to specify for how long the tag needs
   1635      * to have gone out of range, before it will be dispatched again.
   1636      *
   1637      * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms).
   1638      * This means that if the tag repeatedly goes in and out of range (for example, in
   1639      * case of a flaky connection), and the controller happens to poll every time the
   1640      * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag
   1641      * having been "in range" during the interval.
   1642      *
   1643      * Note 2: if a tag with another UID is detected after this API is called, its effect
   1644      * will be cancelled; if this tag shows up before the amount of time specified in
   1645      * debounceMs, it will be dispatched again.
   1646      *
   1647      * Note 3: some tags have a random UID, in which case this API won't work reliably.
   1648      *
   1649      * @param tag        the {@link android.nfc.Tag Tag} to ignore.
   1650      * @param debounceMs minimum amount of time the tag needs to be out of range before being
   1651      *                   dispatched again.
   1652      * @param tagRemovedListener listener to be called when the tag is removed from the field.
   1653      *                           Note that this will only be called if the tag has been out of range
   1654      *                           for at least debounceMs, or if another tag came into range before
   1655      *                           debounceMs. May be null in case you don't want a callback.
   1656      * @param handler the {@link android.os.Handler Handler} that will be used for delivering
   1657      *                the callback. if the handler is null, then the thread used for delivering
   1658      *                the callback is unspecified.
   1659      * @return false if the tag couldn't be found (or has already gone out of range), true otherwise
   1660      */
   1661     public boolean ignore(final Tag tag, int debounceMs,
   1662                           final OnTagRemovedListener tagRemovedListener, final Handler handler) {
   1663         ITagRemovedCallback.Stub iListener = null;
   1664         if (tagRemovedListener != null) {
   1665             iListener = new ITagRemovedCallback.Stub() {
   1666                 @Override
   1667                 public void onTagRemoved() throws RemoteException {
   1668                     if (handler != null) {
   1669                         handler.post(new Runnable() {
   1670                             @Override
   1671                             public void run() {
   1672                                 tagRemovedListener.onTagRemoved();
   1673                             }
   1674                         });
   1675                     } else {
   1676                         tagRemovedListener.onTagRemoved();
   1677                     }
   1678                     synchronized (mLock) {
   1679                         mTagRemovedListener = null;
   1680                     }
   1681                 }
   1682             };
   1683         }
   1684         synchronized (mLock) {
   1685             mTagRemovedListener = iListener;
   1686         }
   1687         try {
   1688             return sService.ignore(tag.getServiceHandle(), debounceMs, iListener);
   1689         } catch (RemoteException e) {
   1690             return false;
   1691         }
   1692     }
   1693 
   1694     /**
   1695      * Inject a mock NFC tag.<p>
   1696      * Used for testing purposes.
   1697      * <p class="note">Requires the
   1698      * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
   1699      * @hide
   1700      */
   1701     public void dispatch(Tag tag) {
   1702         if (tag == null) {
   1703             throw new NullPointerException("tag cannot be null");
   1704         }
   1705         try {
   1706             sService.dispatch(tag);
   1707         } catch (RemoteException e) {
   1708             attemptDeadServiceRecovery(e);
   1709         }
   1710     }
   1711 
   1712     /**
   1713      * @hide
   1714      */
   1715     public void setP2pModes(int initiatorModes, int targetModes) {
   1716         try {
   1717             sService.setP2pModes(initiatorModes, targetModes);
   1718         } catch (RemoteException e) {
   1719             attemptDeadServiceRecovery(e);
   1720         }
   1721     }
   1722 
   1723     /**
   1724      * Registers a new NFC unlock handler with the NFC service.
   1725      *
   1726      * <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted
   1727      * NFC device. The handler should return true if it successfully authenticates the user and
   1728      * unlocks the keyguard.
   1729      *
   1730      * <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for
   1731      * at the lockscreen. Polling for less tag technologies reduces latency, and so it is
   1732      * strongly recommended to only provide the Tag technologies that the handler is expected to
   1733      * receive. There must be at least one tag technology provided, otherwise the unlock handler
   1734      * is ignored.
   1735      *
   1736      * @hide
   1737      */
   1738     @SystemApi
   1739     public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
   1740                                        String[] tagTechnologies) {
   1741         synchronized (NfcAdapter.class) {
   1742             if (!sHasNfcFeature) {
   1743                 throw new UnsupportedOperationException();
   1744             }
   1745         }
   1746         // If there are no tag technologies, don't bother adding unlock handler
   1747         if (tagTechnologies.length == 0) {
   1748             return false;
   1749         }
   1750 
   1751         try {
   1752             synchronized (mLock) {
   1753                 if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
   1754                     // update the tag technologies
   1755                     sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
   1756                     mNfcUnlockHandlers.remove(unlockHandler);
   1757                 }
   1758 
   1759                 INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
   1760                     @Override
   1761                     public boolean onUnlockAttempted(Tag tag) throws RemoteException {
   1762                         return unlockHandler.onUnlockAttempted(tag);
   1763                     }
   1764                 };
   1765 
   1766                 sService.addNfcUnlockHandler(iHandler,
   1767                         Tag.getTechCodesFromStrings(tagTechnologies));
   1768                 mNfcUnlockHandlers.put(unlockHandler, iHandler);
   1769             }
   1770         } catch (RemoteException e) {
   1771             attemptDeadServiceRecovery(e);
   1772             return false;
   1773         } catch (IllegalArgumentException e) {
   1774             Log.e(TAG, "Unable to register LockscreenDispatch", e);
   1775             return false;
   1776         }
   1777 
   1778         return true;
   1779     }
   1780 
   1781     /**
   1782      * Removes a previously registered unlock handler. Also removes the tag technologies
   1783      * associated with the removed unlock handler.
   1784      *
   1785      * @hide
   1786      */
   1787     @SystemApi
   1788     public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) {
   1789         synchronized (NfcAdapter.class) {
   1790             if (!sHasNfcFeature) {
   1791                 throw new UnsupportedOperationException();
   1792             }
   1793         }
   1794         try {
   1795             synchronized (mLock) {
   1796                 if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
   1797                     sService.removeNfcUnlockHandler(mNfcUnlockHandlers.remove(unlockHandler));
   1798                 }
   1799 
   1800                 return true;
   1801             }
   1802         } catch (RemoteException e) {
   1803             attemptDeadServiceRecovery(e);
   1804             return false;
   1805         }
   1806     }
   1807 
   1808     /**
   1809      * @hide
   1810      */
   1811     public INfcAdapterExtras getNfcAdapterExtrasInterface() {
   1812         if (mContext == null) {
   1813             throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
   1814                     + " NFC extras APIs");
   1815         }
   1816         try {
   1817             return sService.getNfcAdapterExtrasInterface(mContext.getPackageName());
   1818         } catch (RemoteException e) {
   1819             attemptDeadServiceRecovery(e);
   1820             return null;
   1821         }
   1822     }
   1823 
   1824     void enforceResumed(Activity activity) {
   1825         if (!activity.isResumed()) {
   1826             throw new IllegalStateException("API cannot be called while activity is paused");
   1827         }
   1828     }
   1829 
   1830     int getSdkVersion() {
   1831         if (mContext == null) {
   1832             return android.os.Build.VERSION_CODES.GINGERBREAD; // best guess
   1833         } else {
   1834             return mContext.getApplicationInfo().targetSdkVersion;
   1835         }
   1836     }
   1837 }
   1838