NfcAdapter.java revision 28319c0cec94977682db32b949628a8e4b8183dc
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
17package android.nfc;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.app.Activity;
22import android.app.ActivityThread;
23import android.app.OnActivityPausedListener;
24import android.app.PendingIntent;
25import android.content.Context;
26import android.content.IntentFilter;
27import android.content.pm.IPackageManager;
28import android.content.pm.PackageManager;
29import android.nfc.tech.MifareClassic;
30import android.nfc.tech.Ndef;
31import android.nfc.tech.NfcA;
32import android.nfc.tech.NfcF;
33import android.os.IBinder;
34import android.os.RemoteException;
35import android.os.ServiceManager;
36import android.util.Log;
37
38/**
39 * Represents the local NFC adapter.
40 * <p>
41 * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC
42 * adapter for this Android device.
43 * <p>
44 */
45public final class NfcAdapter {
46    private static final String TAG = "NFC";
47
48    /**
49     * Intent to start an activity when a tag with NDEF payload is discovered.
50     *
51     * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and
52     * looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the
53     * intent will contain the URI in its data field. If a MIME record is found the intent will
54     * contain the MIME type in its type field. This allows activities to register
55     * {@link IntentFilter}s targeting specific content on tags. Activities should register the
56     * most specific intent filters possible to avoid the activity chooser dialog, which can
57     * disrupt the interaction with the tag as the user interacts with the screen.
58     *
59     * <p>If the tag has an NDEF payload this intent is started before
60     * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither
61     * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
62     */
63    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
64    public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
65
66    /**
67     * Intent to start an activity when a tag is discovered and activities are registered for the
68     * specific technologies on the tag.
69     *
70     * <p>To receive this intent an activity must include an intent filter
71     * for this action and specify the desired tech types in a
72     * manifest <code>meta-data</code> entry. Here is an example manfiest entry:
73     * <pre>
74     *   &lt;activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"&gt;
75     *       &lt;!-- Add a technology filter --&gt;
76     *       &lt;intent-filter&gt;
77     *           &lt;action android:name="android.nfc.action.TECH_DISCOVERED" /&gt;
78     *       &lt;/intent-filter&gt;
79     *
80     *       &lt;meta-data android:name="android.nfc.action.TECH_DISCOVERED"
81     *           android:resource="@xml/filter_nfc"
82     *       /&gt;
83     *   &lt;/activity&gt;
84     * </pre>
85     *
86     * <p>The meta-data XML file should contain one or more <code>tech-list</code> entries
87     * each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer
88     * to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA".
89     *
90     * <p>A tag matches if any of the
91     * <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each
92     * of the <code>tech-list</code>s is considered independently and the
93     * activity is considered a match is any single <code>tech-list</code> matches the tag that was
94     * discovered. This provides AND and OR semantics for filtering desired techs. Here is an
95     * example that will match any tag using {@link NfcF} or any tag using {@link NfcA},
96     * {@link MifareClassic}, and {@link Ndef}:
97     *
98     * <pre>
99     * &lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
100     *     &lt;!-- capture anything using NfcF --&gt;
101     *     &lt;tech-list&gt;
102     *         &lt;tech&gt;android.nfc.tech.NfcF&lt;/tech&gt;
103     *     &lt;/tech-list&gt;
104     *
105     *     &lt;!-- OR --&gt;
106     *
107     *     &lt;!-- capture all MIFARE Classics with NDEF payloads --&gt;
108     *     &lt;tech-list&gt;
109     *         &lt;tech&gt;android.nfc.tech.NfcA&lt;/tech&gt;
110     *         &lt;tech&gt;android.nfc.tech.MifareClassic&lt;/tech&gt;
111     *         &lt;tech&gt;android.nfc.tech.Ndef&lt;/tech&gt;
112     *     &lt;/tech-list&gt;
113     * &lt;/resources&gt;
114     * </pre>
115     *
116     * <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before
117     * {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED}
118     * this intent will not be started. If any activities respond to this intent
119     * {@link #ACTION_TAG_DISCOVERED} will not be started.
120     */
121    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
122    public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
123
124    /**
125     * Intent to start an activity when a tag is discovered.
126     *
127     * <p>This intent will not be started when a tag is discovered if any activities respond to
128     * {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag.
129     */
130    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
131    public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
132
133    /**
134     * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED
135     * @hide
136     */
137    public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST";
138
139    /**
140     * Mandatory extra containing the {@link Tag} that was discovered for the
141     * {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
142     * {@link #ACTION_TAG_DISCOVERED} intents.
143     */
144    public static final String EXTRA_TAG = "android.nfc.extra.TAG";
145
146    /**
147     * Optional extra containing an array of {@link NdefMessage} present on the discovered tag for
148     * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
149     * {@link #ACTION_TAG_DISCOVERED} intents.
150     */
151    public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
152
153    /**
154     * Optional extra containing a byte array containing the ID of the discovered tag for
155     * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
156     * {@link #ACTION_TAG_DISCOVERED} intents.
157     */
158    public static final String EXTRA_ID = "android.nfc.extra.ID";
159
160    /**
161     * Broadcast Action: a transaction with a secure element has been detected.
162     * <p>
163     * Always contains the extra field
164     * {@link android.nfc.NfcAdapter#EXTRA_AID}
165     * @hide
166     */
167    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
168    public static final String ACTION_TRANSACTION_DETECTED =
169            "android.nfc.action.TRANSACTION_DETECTED";
170
171    /**
172     * Broadcast Action: an RF field ON has been detected.
173     * @hide
174     */
175    public static final String ACTION_RF_FIELD_ON_DETECTED =
176            "android.nfc.action.RF_FIELD_ON_DETECTED";
177
178    /**
179     * Broadcast Action: an RF Field OFF has been detected.
180     * @hide
181     */
182    public static final String ACTION_RF_FIELD_OFF_DETECTED =
183            "android.nfc.action.RF_FIELD_OFF_DETECTED";
184
185    /**
186     * Broadcast Action: an adapter's state changed between enabled and disabled.
187     *
188     * The new value is stored in the extra EXTRA_NEW_BOOLEAN_STATE and just contains
189     * whether it's enabled or disabled, not including any information about whether it's
190     * actively enabling or disabling.
191     *
192     * @hide
193     */
194    public static final String ACTION_ADAPTER_STATE_CHANGE =
195            "android.nfc.action.ADAPTER_STATE_CHANGE";
196
197    /**
198     * The Intent extra for ACTION_ADAPTER_STATE_CHANGE, saying what the new state is.
199     *
200     * @hide
201     */
202    public static final String EXTRA_NEW_BOOLEAN_STATE = "android.nfc.isEnabled";
203
204    /**
205     * Mandatory byte array extra field in
206     * {@link android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED}.
207     * <p>
208     * Contains the AID of the applet involved in the transaction.
209     * @hide
210     */
211    public static final String EXTRA_AID = "android.nfc.extra.AID";
212
213    /**
214     * LLCP link status: The LLCP link is activated.
215     * @hide
216     */
217    public static final int LLCP_LINK_STATE_ACTIVATED = 0;
218
219    /**
220     * LLCP link status: The LLCP link is deactivated.
221     * @hide
222     */
223    public static final int LLCP_LINK_STATE_DEACTIVATED = 1;
224
225    /**
226     * Broadcast Action: the LLCP link state changed.
227     * <p>
228     * Always contains the extra field
229     * {@link android.nfc.NfcAdapter#EXTRA_LLCP_LINK_STATE_CHANGED}.
230     * @hide
231     */
232    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
233    public static final String ACTION_LLCP_LINK_STATE_CHANGED =
234            "android.nfc.action.LLCP_LINK_STATE_CHANGED";
235
236    /**
237     * Used as int extra field in
238     * {@link android.nfc.NfcAdapter#ACTION_LLCP_LINK_STATE_CHANGED}.
239     * <p>
240     * It contains the new state of the LLCP link.
241     * @hide
242     */
243    public static final String EXTRA_LLCP_LINK_STATE_CHANGED = "android.nfc.extra.LLCP_LINK_STATE";
244
245    /**
246     * Tag Reader Discovery mode
247     * @hide
248     */
249    private static final int DISCOVERY_MODE_TAG_READER = 0;
250
251    /**
252     * NFC-IP1 Peer-to-Peer mode Enables the manager to act as a peer in an
253     * NFC-IP1 communication. Implementations should not assume that the
254     * controller will end up behaving as an NFC-IP1 target or initiator and
255     * should handle both cases, depending on the type of the remote peer type.
256     * @hide
257     */
258    private static final int DISCOVERY_MODE_NFCIP1 = 1;
259
260    /**
261     * Card Emulation mode Enables the manager to act as an NFC tag. Provided
262     * that a Secure Element (an UICC for instance) is connected to the NFC
263     * controller through its SWP interface, it can be exposed to the outside
264     * NFC world and be addressed by external readers the same way they would
265     * with a tag.
266     * <p>
267     * Which Secure Element is exposed is implementation-dependent.
268     *
269     * @hide
270     */
271    private static final int DISCOVERY_MODE_CARD_EMULATION = 2;
272
273
274    // Guarded by NfcAdapter.class
275    private static boolean sIsInitialized = false;
276
277    // Final after first constructor, except for
278    // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
279    // recovery
280    private static INfcAdapter sService;
281    private static INfcTag sTagService;
282
283    /**
284     * Helper to check if this device has FEATURE_NFC, but without using
285     * a context.
286     * Equivalent to
287     * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)
288     */
289    private static boolean hasNfcFeature() {
290        IPackageManager pm = ActivityThread.getPackageManager();
291        if (pm == null) {
292            Log.e(TAG, "Cannot get package manager, assuming no NFC feature");
293            return false;
294        }
295        try {
296            return pm.hasSystemFeature(PackageManager.FEATURE_NFC);
297        } catch (RemoteException e) {
298            Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
299            return false;
300        }
301    }
302
303    private static synchronized INfcAdapter setupService() {
304        if (!sIsInitialized) {
305            sIsInitialized = true;
306
307            /* is this device meant to have NFC */
308            if (!hasNfcFeature()) {
309                Log.v(TAG, "this device does not have NFC support");
310                return null;
311            }
312
313            sService = getServiceInterface();
314            if (sService == null) {
315                Log.e(TAG, "could not retrieve NFC service");
316                return null;
317            }
318            try {
319                sTagService = sService.getNfcTagInterface();
320            } catch (RemoteException e) {
321                Log.e(TAG, "could not retrieve NFC Tag service");
322                return null;
323            }
324        }
325        return sService;
326    }
327
328    /** get handle to NFC service interface */
329    private static INfcAdapter getServiceInterface() {
330        /* get a handle to NFC service */
331        IBinder b = ServiceManager.getService("nfc");
332        if (b == null) {
333            return null;
334        }
335        return INfcAdapter.Stub.asInterface(b);
336    }
337
338    /**
339     * Helper to get the default NFC Adapter.
340     * <p>
341     * Most Android devices will only have one NFC Adapter (NFC Controller).
342     * <p>
343     * This helper is the equivalent of:
344     * <pre>{@code
345     * NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
346     * NfcAdapter adapter = manager.getDefaultAdapter();
347     * }</pre>
348     * @param context the calling application's context
349     *
350     * @return the default NFC adapter, or null if no NFC adapter exists
351     */
352    public static NfcAdapter getDefaultAdapter(Context context) {
353        /* use getSystemService() instead of just instantiating to take
354         * advantage of the context's cached NfcManager & NfcAdapter */
355        NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
356        return manager.getDefaultAdapter();
357    }
358
359    /**
360     * Get a handle to the default NFC Adapter on this Android device.
361     * <p>
362     * Most Android devices will only have one NFC Adapter (NFC Controller).
363     *
364     * @return the default NFC adapter, or null if no NFC adapter exists
365     * @deprecated use {@link #getDefaultAdapter(Context)}
366     */
367    @Deprecated
368    public static NfcAdapter getDefaultAdapter() {
369        Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
370                "NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
371        return new NfcAdapter(null);
372    }
373
374    /*package*/ NfcAdapter(Context context) {
375        if (setupService() == null) {
376            throw new UnsupportedOperationException();
377        }
378    }
379
380    /**
381     * Returns the binder interface to the service.
382     * @hide
383     */
384    public INfcAdapter getService() {
385        isEnabled();  // NOP call to recover sService if it is stale
386        return sService;
387    }
388
389    /**
390     * Returns the binder interface to the tag service.
391     * @hide
392     */
393    public INfcTag getTagService() {
394        isEnabled();  // NOP call to recover sTagService if it is stale
395        return sTagService;
396    }
397
398    /**
399     * NFC service dead - attempt best effort recovery
400     * @hide
401     */
402    public void attemptDeadServiceRecovery(Exception e) {
403        Log.e(TAG, "NFC service dead - attempting to recover", e);
404        INfcAdapter service = getServiceInterface();
405        if (service == null) {
406            Log.e(TAG, "could not retrieve NFC service during service recovery");
407            // nothing more can be done now, sService is still stale, we'll hit
408            // this recovery path again later
409            return;
410        }
411        // assigning to sService is not thread-safe, but this is best-effort code
412        // and on a well-behaved system should never happen
413        sService = service;
414        try {
415            sTagService = service.getNfcTagInterface();
416        } catch (RemoteException ee) {
417            Log.e(TAG, "could not retrieve NFC tag service during service recovery");
418            // nothing more can be done now, sService is still stale, we'll hit
419            // this recovery path again later
420        }
421
422        return;
423    }
424
425    /**
426     * Return true if this NFC Adapter has any features enabled.
427     *
428     * <p>Application may use this as a helper to suggest that the user
429     * should turn on NFC in Settings.
430     * <p>If this method returns false, the NFC hardware is guaranteed not to
431     * generate or respond to any NFC transactions.
432     *
433     * @return true if this NFC Adapter has any features enabled
434     */
435    public boolean isEnabled() {
436        try {
437            return sService.isEnabled();
438        } catch (RemoteException e) {
439            attemptDeadServiceRecovery(e);
440            return false;
441        }
442    }
443
444    /**
445     * Enable NFC hardware.
446     * <p>
447     * NOTE: may block for ~second or more.  Poor API.  Avoid
448     * calling from the UI thread.
449     *
450     * @hide
451     */
452    public boolean enable() {
453        try {
454            return sService.enable();
455        } catch (RemoteException e) {
456            attemptDeadServiceRecovery(e);
457            return false;
458        }
459    }
460
461    /**
462     * Disable NFC hardware.
463     * No NFC features will work after this call, and the hardware
464     * will not perform or respond to any NFC communication.
465     * <p>
466     * NOTE: may block for ~second or more.  Poor API.  Avoid
467     * calling from the UI thread.
468     *
469     * @hide
470     */
471    public boolean disable() {
472        try {
473            return sService.disable();
474        } catch (RemoteException e) {
475            attemptDeadServiceRecovery(e);
476            return false;
477        }
478    }
479
480    /**
481     * Enable foreground dispatch to the given Activity.
482     *
483     * <p>This will give give priority to the foreground activity when
484     * dispatching a discovered {@link Tag} to an application.
485     *
486     * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents
487     * for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and
488     * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED}
489     * relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled
490     * by passing in the tech lists separately. Each first level entry in the tech list represents
491     * an array of technologies that must all be present to match. If any of the first level sets
492     * match then the dispatch is routed through the given PendingIntent. In other words, the second
493     * level is ANDed together and the first level entries are ORed together.
494     *
495     * <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters
496     * that acts a wild card and will cause the foreground activity to receive all tags via the
497     * {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent.
498     *
499     * <p>This method must be called from the main thread, and only when the activity is in the
500     * foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before
501     * the completion of their {@link Activity#onPause} callback to disable foreground dispatch
502     * after it has been enabled.
503     *
504     * @param activity the Activity to dispatch to
505     * @param intent the PendingIntent to start for the dispatch
506     * @param filters the IntentFilters to override dispatching for, or null to always dispatch
507     * @param techLists the tech lists used to perform matching for dispatching of the
508     *      {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent
509     * @throws IllegalStateException if the Activity is not currently in the foreground
510     */
511    public void enableForegroundDispatch(Activity activity, PendingIntent intent,
512            IntentFilter[] filters, String[][] techLists) {
513        if (activity == null || intent == null) {
514            throw new NullPointerException();
515        }
516        if (!activity.isResumed()) {
517            throw new IllegalStateException("Foregorund dispatching can only be enabled " +
518                    "when your activity is resumed");
519        }
520        try {
521            TechListParcel parcel = null;
522            if (techLists != null && techLists.length > 0) {
523                parcel = new TechListParcel(techLists);
524            }
525            ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
526                    mForegroundDispatchListener);
527            sService.enableForegroundDispatch(activity.getComponentName(), intent, filters,
528                    parcel);
529        } catch (RemoteException e) {
530            attemptDeadServiceRecovery(e);
531        }
532    }
533
534    /**
535     * Disable foreground dispatch to the given activity.
536     *
537     * <p>After calling {@link #enableForegroundDispatch}, an activity
538     * must call this method before its {@link Activity#onPause} callback
539     * completes.
540     *
541     * <p>This method must be called from the main thread.
542     *
543     * @param activity the Activity to disable dispatch to
544     * @throws IllegalStateException if the Activity has already been paused
545     */
546    public void disableForegroundDispatch(Activity activity) {
547        ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
548                mForegroundDispatchListener);
549        disableForegroundDispatchInternal(activity, false);
550    }
551
552    OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() {
553        @Override
554        public void onPaused(Activity activity) {
555            disableForegroundDispatchInternal(activity, true);
556        }
557    };
558
559    void disableForegroundDispatchInternal(Activity activity, boolean force) {
560        try {
561            sService.disableForegroundDispatch(activity.getComponentName());
562            if (!force && !activity.isResumed()) {
563                throw new IllegalStateException("You must disable forgeground dispatching " +
564                        "while your activity is still resumed");
565            }
566        } catch (RemoteException e) {
567            attemptDeadServiceRecovery(e);
568        }
569    }
570
571    /**
572     * Enable NDEF message push over P2P while this Activity is in the foreground.
573     *
574     * <p>For this to function properly the other NFC device being scanned must
575     * support the "com.android.npp" NDEF push protocol. Support for this
576     * protocol is currently optional for Android NFC devices.
577     *
578     * <p>This method must be called from the main thread.
579     *
580     * <p><em>NOTE</em> While foreground NDEF push is active standard tag dispatch is disabled.
581     * Only the foreground activity may receive tag discovered dispatches via
582     * {@link #enableForegroundDispatch}.
583     *
584     * @param activity the foreground Activity
585     * @param msg a NDEF Message to push over P2P
586     * @throws IllegalStateException if the Activity is not currently in the foreground
587     * @throws OperationNotSupportedException if this Android device does not support NDEF push
588     */
589    public void enableForegroundNdefPush(Activity activity, NdefMessage msg) {
590        if (activity == null || msg == null) {
591            throw new NullPointerException();
592        }
593        if (!activity.isResumed()) {
594            throw new IllegalStateException("Foregorund NDEF push can only be enabled " +
595                    "when your activity is resumed");
596        }
597        try {
598            ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
599                    mForegroundNdefPushListener);
600            sService.enableForegroundNdefPush(activity.getComponentName(), msg);
601        } catch (RemoteException e) {
602            attemptDeadServiceRecovery(e);
603        }
604    }
605
606    /**
607     * Disable NDEF message push over P2P.
608     *
609     * <p>After calling {@link #enableForegroundNdefPush}, an activity
610     * must call this method before its {@link Activity#onPause} callback
611     * completes.
612     *
613     * <p>This method must be called from the main thread.
614     *
615     * @param activity the Foreground activity
616     * @throws IllegalStateException if the Activity has already been paused
617     * @throws OperationNotSupportedException if this Android device does not support NDEF push
618     */
619    public void disableForegroundNdefPush(Activity activity) {
620        ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
621                mForegroundNdefPushListener);
622        disableForegroundNdefPushInternal(activity, false);
623    }
624
625    OnActivityPausedListener mForegroundNdefPushListener = new OnActivityPausedListener() {
626        @Override
627        public void onPaused(Activity activity) {
628            disableForegroundNdefPushInternal(activity, true);
629        }
630    };
631
632    void disableForegroundNdefPushInternal(Activity activity, boolean force) {
633        try {
634            sService.disableForegroundNdefPush(activity.getComponentName());
635            if (!force && !activity.isResumed()) {
636                throw new IllegalStateException("You must disable forgeground NDEF push " +
637                        "while your activity is still resumed");
638            }
639        } catch (RemoteException e) {
640            attemptDeadServiceRecovery(e);
641        }
642    }
643
644    /**
645     * Set the NDEF Message that this NFC adapter should appear as to Tag
646     * readers.
647     * <p>
648     * Any Tag reader can read the contents of the local tag when it is in
649     * proximity, without any further user confirmation.
650     * <p>
651     * The implementation of this method must either
652     * <ul>
653     * <li>act as a passive tag containing this NDEF message
654     * <li>provide the NDEF message on over LLCP to peer NFC adapters
655     * </ul>
656     * The NDEF message is preserved across reboot.
657     * <p>Requires {@link android.Manifest.permission#NFC} permission.
658     *
659     * @param message NDEF message to make public
660     * @hide
661     */
662    public void setLocalNdefMessage(NdefMessage message) {
663        try {
664            sService.localSet(message);
665        } catch (RemoteException e) {
666            attemptDeadServiceRecovery(e);
667        }
668    }
669
670    /**
671     * Get the NDEF Message that this adapter appears as to Tag readers.
672     * <p>Requires {@link android.Manifest.permission#NFC} permission.
673     *
674     * @return NDEF Message that is publicly readable
675     * @hide
676     */
677    public NdefMessage getLocalNdefMessage() {
678        try {
679            return sService.localGet();
680        } catch (RemoteException e) {
681            attemptDeadServiceRecovery(e);
682            return null;
683        }
684    }
685
686    /**
687     * Create an Nfc Secure Element Connection
688     * @hide
689     */
690    public NfcSecureElement createNfcSecureElementConnection() {
691        try {
692            return new NfcSecureElement(sService.getNfcSecureElementInterface());
693        } catch (RemoteException e) {
694            Log.e(TAG, "createNfcSecureElementConnection failed", e);
695            return null;
696        }
697    }
698}
699