NfcAdapter.java revision fdf9086e24f4720ee9fbc852b980041f126aa3c2
1/*
2 * Copyright (C) 2010 The Android Open Source Project Licensed under the Apache
3 * License, Version 2.0 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
6 * or agreed to in writing, software distributed under the License is
7 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 * KIND, either express or implied. See the License for the specific language
9 * governing permissions and limitations under the License.
10 */
11
12package android.nfc;
13
14import java.lang.UnsupportedOperationException;
15
16import android.annotation.SdkConstant;
17import android.annotation.SdkConstant.SdkConstantType;
18import android.app.ActivityThread;
19import android.content.Context;
20import android.content.pm.IPackageManager;
21import android.content.pm.PackageManager;
22import android.nfc.INfcAdapter;
23import android.os.IBinder;
24import android.os.RemoteException;
25import android.os.ServiceManager;
26import android.util.Log;
27
28/**
29 * Represents the device's local NFC adapter.
30 * <p>
31 * Use the static {@link #getDefaultAdapter} method to get the default NFC
32 * Adapter for this Android device. Most Android devices will have only one NFC
33 * Adapter, and {@link #getDefaultAdapter} returns the singleton object.
34 * <p>
35 * {@link NfcAdapter} can be used to create {@link RawTagConnection} or
36 * {@link NdefTagConnection} connections to modify or perform low level access
37 * to NFC Tags.
38 * <p class="note">
39 * <strong>Note:</strong> Some methods require the
40 * {@link android.Manifest.permission#NFC} permission.
41 */
42public final class NfcAdapter {
43    /**
44     * Intent to start an activity when a non-NDEF tag is discovered.
45     * TODO(npelly) finalize decision on using CATEGORY or DATA URI to provide a
46     * hint for applications to filter the tag type.
47     * TODO(npelly) probably combine these two intents since tags aren't that simple
48     */
49    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
50    public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
51
52    /**
53     * Intent to start an activity when a NDEF tag is discovered. TODO(npelly)
54     * finalize decision on using CATEGORY or DATA URI to provide a hint for
55     * applications to filter the tag type.
56     */
57    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
58    public static final String ACTION_NDEF_TAG_DISCOVERED =
59            "android.nfc.action.NDEF_TAG_DISCOVERED";
60
61    /**
62     * Mandatory Tag extra for the ACTION_TAG and ACTION_NDEF_TAG intents.
63     */
64    public static final String EXTRA_TAG = "android.nfc.extra.TAG";
65
66    /**
67     * Broadcast Action: a transaction with a secure element has been detected.
68     * <p>
69     * Always contains the extra field
70     * {@link android.nfc.NfcAdapter#EXTRA_AID}
71     * @hide
72     */
73    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
74    public static final String ACTION_TRANSACTION_DETECTED =
75            "android.nfc.action.TRANSACTION_DETECTED";
76
77    /**
78     * Mandatory byte array extra field in
79     * {@link android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED}.
80     * <p>
81     * Contains the AID of the applet involved in the transaction.
82     * @hide
83     */
84    public static final String EXTRA_AID = "android.nfc.extra.AID";
85
86    /**
87     * LLCP link status: The LLCP link is activated.
88     * @hide
89     */
90    public static final int LLCP_LINK_STATE_ACTIVATED = 0;
91
92    /**
93     * LLCP link status: The LLCP link is deactivated.
94     * @hide
95     */
96    public static final int LLCP_LINK_STATE_DEACTIVATED = 1;
97
98    /**
99     * Broadcast Action: the LLCP link state changed.
100     * <p>
101     * Always contains the extra field
102     * {@link android.nfc.NfcAdapter#EXTRA_LLCP_LINK_STATE_CHANGED}.
103     * @hide
104     */
105    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
106    public static final String ACTION_LLCP_LINK_STATE_CHANGED =
107            "android.nfc.action.LLCP_LINK_STATE_CHANGED";
108
109    /**
110     * Used as int extra field in
111     * {@link android.nfc.NfcAdapter#ACTION_LLCP_LINK_STATE_CHANGED}.
112     * <p>
113     * It contains the new state of the LLCP link.
114     * @hide
115     */
116    public static final String EXTRA_LLCP_LINK_STATE_CHANGED = "android.nfc.extra.LLCP_LINK_STATE";
117
118    /**
119     * Tag Reader Discovery mode
120     * @hide
121     */
122    private static final int DISCOVERY_MODE_TAG_READER = 0;
123
124    /**
125     * NFC-IP1 Peer-to-Peer mode Enables the manager to act as a peer in an
126     * NFC-IP1 communication. Implementations should not assume that the
127     * controller will end up behaving as an NFC-IP1 target or initiator and
128     * should handle both cases, depending on the type of the remote peer type.
129     * @hide
130     */
131    private static final int DISCOVERY_MODE_NFCIP1 = 1;
132
133    /**
134     * Card Emulation mode Enables the manager to act as an NFC tag. Provided
135     * that a Secure Element (an UICC for instance) is connected to the NFC
136     * controller through its SWP interface, it can be exposed to the outside
137     * NFC world and be addressed by external readers the same way they would
138     * with a tag.
139     * <p>
140     * Which Secure Element is exposed is implementation-dependent.
141     *
142     * @hide
143     */
144    private static final int DISCOVERY_MODE_CARD_EMULATION = 2;
145
146    private static final String TAG = "NFC";
147
148    private static boolean sIsInitialized = false;
149    private static NfcAdapter sAdapter;
150
151    private final INfcAdapter mService;
152
153    private NfcAdapter(INfcAdapter service) {
154        mService = service;
155    }
156
157    /**
158     * Helper to check if this device has FEATURE_NFC, but without using
159     * a context.
160     * Equivalent to
161     * context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)
162     */
163    private static boolean hasNfcFeature() {
164        IPackageManager pm = ActivityThread.getPackageManager();
165        if (pm == null) {
166            Log.e(TAG, "Cannot get package manager, assuming no NFC feature");
167            return false;
168        }
169        try {
170            return pm.hasSystemFeature(PackageManager.FEATURE_NFC);
171        } catch (RemoteException e) {
172            Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
173            return false;
174        }
175    }
176
177    /**
178     * Get a handle to the default NFC Adapter on this Android device.
179     * <p>
180     * Most Android devices will only have one NFC Adapter (NFC Controller).
181     *
182     * @return the default NFC adapter, or null if no NFC adapter exists
183     */
184    public static NfcAdapter getDefaultAdapter() {
185        synchronized (NfcAdapter.class) {
186            if (sIsInitialized) {
187                return sAdapter;
188            }
189            sIsInitialized = true;
190
191            /* is this device meant to have NFC */
192            if (!hasNfcFeature()) {
193                Log.v(TAG, "this device does not have NFC support");
194                return null;
195            }
196
197            /* get a handle to NFC service */
198            IBinder b = ServiceManager.getService("nfc");
199            if (b == null) {
200                Log.e(TAG, "could not retrieve NFC service");
201                return null;
202            }
203
204            sAdapter = new NfcAdapter(INfcAdapter.Stub.asInterface(b));
205            return sAdapter;
206        }
207    }
208
209    /**
210     * Return true if this NFC Adapter is enabled to discover new tags.
211     * <p>
212     * If this method returns false, then applications should request the user
213     * turn on NFC tag discovery in Settings.
214     *
215     * @return true if this NFC Adapter is enabled to discover new tags
216     */
217    public boolean isTagDiscoveryEnabled() {
218        try {
219            return mService.isEnabled();
220        } catch (RemoteException e) {
221            Log.e(TAG, "RemoteException in isEnabled()", e);
222            return false;
223        }
224    }
225
226    /**
227     * @hide
228     */
229    public boolean enableTagDiscovery() {
230        try {
231            return mService.enable();
232        } catch (RemoteException e) {
233            Log.e(TAG, "RemoteException in enable()", e);
234            return false;
235        }
236    }
237
238    /**
239     * @hide
240     */
241    public boolean disableTagDiscovery() {
242        try {
243            return mService.disable();
244        } catch (RemoteException e) {
245            Log.e(TAG, "RemoteException in disable()", e);
246            return false;
247        }
248    }
249
250    /**
251     * Set the NDEF Message that this NFC adapter should appear as to Tag
252     * readers.
253     * <p>
254     * Any Tag reader can read the contents of the local tag when it is in
255     * proximity, without any further user confirmation.
256     * <p>
257     * The implementation of this method must either
258     * <ul>
259     * <li>act as a passive tag containing this NDEF message
260     * <li>provide the NDEF message on over LLCP to peer NFC adapters
261     * </ul>
262     * The NDEF message is preserved across reboot.
263     * <p>Requires {@link android.Manifest.permission#NFC} permission.
264     *
265     * @param message NDEF message to make public
266     */
267    public void setLocalNdefMessage(NdefMessage message) {
268        try {
269            mService.localSet(message);
270        } catch (RemoteException e) {
271            Log.e(TAG, "NFC service died", e);
272        }
273    }
274
275    /**
276     * Get the NDEF Message that this adapter appears as to Tag readers.
277     * <p>Requires {@link android.Manifest.permission#NFC} permission.
278     *
279     * @return NDEF Message that is publicly readable
280     */
281    public NdefMessage getLocalNdefMessage() {
282        try {
283            return mService.localGet();
284        } catch (RemoteException e) {
285            Log.e(TAG, "NFC service died", e);
286            return null;
287        }
288    }
289
290    /**
291     * Create a raw tag connection to the default Target
292     * <p>Requires {@link android.Manifest.permission#NFC} permission.
293     */
294    public RawTagConnection createRawTagConnection(Tag tag) {
295        try {
296            return new RawTagConnection(mService, tag);
297        } catch (RemoteException e) {
298            Log.e(TAG, "NFC service died", e);
299            return null;
300        }
301    }
302
303    /**
304     * Create a raw tag connection to the specified Target
305     * <p>Requires {@link android.Manifest.permission#NFC} permission.
306     */
307    public RawTagConnection createRawTagConnection(Tag tag, String target) {
308        try {
309            return new RawTagConnection(mService, tag, target);
310        } catch (RemoteException e) {
311            Log.e(TAG, "NFC service died", e);
312            return null;
313        }
314    }
315
316    /**
317     * Create an NDEF tag connection to the default Target
318     * <p>Requires {@link android.Manifest.permission#NFC} permission.
319     */
320    public NdefTagConnection createNdefTagConnection(NdefTag tag) {
321        try {
322            return new NdefTagConnection(mService, tag);
323        } catch (RemoteException e) {
324            Log.e(TAG, "NFC service died", e);
325            return null;
326        }
327    }
328
329    /**
330     * Create an NDEF tag connection to the specified Target
331     * <p>Requires {@link android.Manifest.permission#NFC} permission.
332     */
333    public NdefTagConnection createNdefTagConnection(NdefTag tag, String target) {
334        try {
335            return new NdefTagConnection(mService, tag, target);
336        } catch (RemoteException e) {
337            Log.e(TAG, "NFC service died", e);
338            return null;
339        }
340    }
341}
342