• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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          */
onNdefPushComplete(NfcEvent event)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          */
createNdefMessage(NfcEvent event)300         public NdefMessage createNdefMessage(NfcEvent event);
301     }
302 
303 
304     // TODO javadoc
305     public interface CreateBeamUrisCallback {
createBeamUris(NfcEvent event)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      */
hasNfcFeature()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      */
getNfcAdapter(Context context)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 */
getServiceInterface()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      */
getDefaultAdapter(Context context)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
getDefaultAdapter()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 
NfcAdapter(Context context)431     NfcAdapter(Context context) {
432         mContext = context;
433         mNfcActivityManager = new NfcActivityManager(this);
434     }
435 
436     /**
437      * @hide
438      */
getContext()439     public Context getContext() {
440         return mContext;
441     }
442 
443     /**
444      * Returns the binder interface to the service.
445      * @hide
446      */
getService()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      */
getTagService()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      */
attemptDeadServiceRecovery(Exception e)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      */
isEnabled()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      */
getAdapterState()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      */
enable()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 
disable()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      */
setBeamPushUris(Uri[] uris, Activity activity)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      */
setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity)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      */
setNdefPushMessage(NdefMessage message, Activity activity, Activity ... activities)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      */
setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity, Activity ... activities)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      */
setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback, Activity activity, Activity ... activities)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      */
enableForegroundDispatch(Activity activity, PendingIntent intent, IntentFilter[] filters, String[][] techLists)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      */
disableForegroundDispatch(Activity activity)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 
disableForegroundDispatchInternal(Activity activity, boolean force)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
enableForegroundNdefPush(Activity activity, NdefMessage message)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
disableForegroundNdefPush(Activity activity)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      */
enableNdefPush()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      */
disableNdefPush()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      */
isNdefPushEnabled()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      */
dispatch(Tag tag)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      */
setP2pModes(int initiatorModes, int targetModes)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      */
getNfcAdapterExtrasInterface()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 
enforceResumed(Activity activity)1242     void enforceResumed(Activity activity) {
1243         if (!activity.isResumed()) {
1244             throw new IllegalStateException("API cannot be called while activity is paused");
1245         }
1246     }
1247 
getSdkVersion()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