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