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