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