NfcService.java revision 1a9eca5f84036d7dd3e28000290caa2f641856de
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 com.android.nfc;
18
19import com.android.internal.nfc.LlcpServiceSocket;
20import com.android.internal.nfc.LlcpSocket;
21import com.android.nfc.ndefpush.NdefPushClient;
22import com.android.nfc.ndefpush.NdefPushServer;
23
24import android.app.Activity;
25import android.app.ActivityManagerNative;
26import android.app.IActivityManager;
27import android.app.Application;
28import android.app.PendingIntent;
29import android.app.StatusBarManager;
30import android.app.PendingIntent.CanceledException;
31import android.content.ActivityNotFoundException;
32import android.content.BroadcastReceiver;
33import android.content.ComponentName;
34import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.content.SharedPreferences;
38import android.net.Uri;
39import android.nfc.ErrorCodes;
40import android.nfc.FormatException;
41import android.nfc.ILlcpConnectionlessSocket;
42import android.nfc.ILlcpServiceSocket;
43import android.nfc.ILlcpSocket;
44import android.nfc.INfcAdapter;
45import android.nfc.INfcSecureElement;
46import android.nfc.INfcTag;
47import android.nfc.IP2pInitiator;
48import android.nfc.IP2pTarget;
49import android.nfc.LlcpPacket;
50import android.nfc.NdefMessage;
51import android.nfc.NdefRecord;
52import android.nfc.NfcAdapter;
53import android.nfc.Tag;
54import android.nfc.TransceiveResult;
55import android.os.AsyncTask;
56import android.os.Bundle;
57import android.os.Handler;
58import android.os.Message;
59import android.os.PowerManager;
60import android.os.RemoteException;
61import android.os.ServiceManager;
62import android.util.Log;
63
64import java.io.ByteArrayOutputStream;
65import java.io.FileInputStream;
66import java.io.FileNotFoundException;
67import java.io.FileOutputStream;
68import java.io.IOException;
69import java.nio.charset.Charsets;
70import java.util.Arrays;
71import java.util.HashMap;
72import java.util.Timer;
73import java.util.TimerTask;
74
75public class NfcService extends Application {
76    static final boolean DBG = false;
77
78    private static final String MY_TAG_FILE_NAME = "mytag";
79
80    static {
81        System.loadLibrary("nfc_jni");
82    }
83
84    /**
85     * NFC Forum "URI Record Type Definition"
86     *
87     * This is a mapping of "URI Identifier Codes" to URI string prefixes,
88     * per section 3.2.2 of the NFC Forum URI Record Type Definition document.
89     */
90    private static final String[] URI_PREFIX_MAP = new String[] {
91            "", // 0x00
92            "http://www.", // 0x01
93            "https://www.", // 0x02
94            "http://", // 0x03
95            "https://", // 0x04
96            "tel:", // 0x05
97            "mailto:", // 0x06
98            "ftp://anonymous:anonymous@", // 0x07
99            "ftp://ftp.", // 0x08
100            "ftps://", // 0x09
101            "sftp://", // 0x0A
102            "smb://", // 0x0B
103            "nfs://", // 0x0C
104            "ftp://", // 0x0D
105            "dav://", // 0x0E
106            "news:", // 0x0F
107            "telnet://", // 0x10
108            "imap:", // 0x11
109            "rtsp://", // 0x12
110            "urn:", // 0x13
111            "pop:", // 0x14
112            "sip:", // 0x15
113            "sips:", // 0x16
114            "tftp:", // 0x17
115            "btspp://", // 0x18
116            "btl2cap://", // 0x19
117            "btgoep://", // 0x1A
118            "tcpobex://", // 0x1B
119            "irdaobex://", // 0x1C
120            "file://", // 0x1D
121            "urn:epc:id:", // 0x1E
122            "urn:epc:tag:", // 0x1F
123            "urn:epc:pat:", // 0x20
124            "urn:epc:raw:", // 0x21
125            "urn:epc:", // 0x22
126    };
127
128    public static final String SERVICE_NAME = "nfc";
129
130    private static final String TAG = "NfcService";
131
132    private static final String NFC_PERM = android.Manifest.permission.NFC;
133    private static final String NFC_PERM_ERROR = "NFC permission required";
134    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
135    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
136
137    private static final String PREF = "NfcServicePrefs";
138
139    private static final String PREF_NFC_ON = "nfc_on";
140    private static final boolean NFC_ON_DEFAULT = true;
141
142    private static final String PREF_SECURE_ELEMENT_ON = "secure_element_on";
143    private static final boolean SECURE_ELEMENT_ON_DEFAULT = false;
144
145    private static final String PREF_SECURE_ELEMENT_ID = "secure_element_id";
146    private static final int SECURE_ELEMENT_ID_DEFAULT = 0;
147
148    private static final String PREF_LLCP_LTO = "llcp_lto";
149    private static final int LLCP_LTO_DEFAULT = 150;
150    private static final int LLCP_LTO_MAX = 255;
151
152    /** Maximum Information Unit */
153    private static final String PREF_LLCP_MIU = "llcp_miu";
154    private static final int LLCP_MIU_DEFAULT = 128;
155    private static final int LLCP_MIU_MAX = 2176;
156
157    /** Well Known Service List */
158    private static final String PREF_LLCP_WKS = "llcp_wks";
159    private static final int LLCP_WKS_DEFAULT = 1;
160    private static final int LLCP_WKS_MAX = 15;
161
162    private static final String PREF_LLCP_OPT = "llcp_opt";
163    private static final int LLCP_OPT_DEFAULT = 0;
164    private static final int LLCP_OPT_MAX = 3;
165
166    private static final String PREF_DISCOVERY_A = "discovery_a";
167    private static final boolean DISCOVERY_A_DEFAULT = true;
168
169    private static final String PREF_DISCOVERY_B = "discovery_b";
170    private static final boolean DISCOVERY_B_DEFAULT = true;
171
172    private static final String PREF_DISCOVERY_F = "discovery_f";
173    private static final boolean DISCOVERY_F_DEFAULT = true;
174
175    private static final String PREF_DISCOVERY_15693 = "discovery_15693";
176    private static final boolean DISCOVERY_15693_DEFAULT = true;
177
178    private static final String PREF_DISCOVERY_NFCIP = "discovery_nfcip";
179    private static final boolean DISCOVERY_NFCIP_DEFAULT = true;
180
181    /** NFC Reader Discovery mode for enableDiscovery() */
182    private static final int DISCOVERY_MODE_READER = 0;
183
184    private static final int PROPERTY_LLCP_LTO = 0;
185    private static final String PROPERTY_LLCP_LTO_VALUE = "llcp.lto";
186    private static final int PROPERTY_LLCP_MIU = 1;
187    private static final String PROPERTY_LLCP_MIU_VALUE = "llcp.miu";
188    private static final int PROPERTY_LLCP_WKS = 2;
189    private static final String PROPERTY_LLCP_WKS_VALUE = "llcp.wks";
190    private static final int PROPERTY_LLCP_OPT = 3;
191    private static final String PROPERTY_LLCP_OPT_VALUE = "llcp.opt";
192    private static final int PROPERTY_NFC_DISCOVERY_A = 4;
193    private static final String PROPERTY_NFC_DISCOVERY_A_VALUE = "discovery.iso14443A";
194    private static final int PROPERTY_NFC_DISCOVERY_B = 5;
195    private static final String PROPERTY_NFC_DISCOVERY_B_VALUE = "discovery.iso14443B";
196    private static final int PROPERTY_NFC_DISCOVERY_F = 6;
197    private static final String PROPERTY_NFC_DISCOVERY_F_VALUE = "discovery.felica";
198    private static final int PROPERTY_NFC_DISCOVERY_15693 = 7;
199    private static final String PROPERTY_NFC_DISCOVERY_15693_VALUE = "discovery.iso15693";
200    private static final int PROPERTY_NFC_DISCOVERY_NFCIP = 8;
201    private static final String PROPERTY_NFC_DISCOVERY_NFCIP_VALUE = "discovery.nfcip";
202
203    static final int MSG_NDEF_TAG = 0;
204    static final int MSG_CARD_EMULATION = 1;
205    static final int MSG_LLCP_LINK_ACTIVATION = 2;
206    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
207    static final int MSG_TARGET_DESELECTED = 4;
208    static final int MSG_SHOW_MY_TAG_ICON = 5;
209    static final int MSG_HIDE_MY_TAG_ICON = 6;
210    static final int MSG_MOCK_NDEF = 7;
211    static final int MSG_SE_FIELD_ACTIVATED = 8;
212    static final int MSG_SE_FIELD_DEACTIVATED = 9;
213
214    // Locked on mNfcAdapter
215    IntentFilter[] mDispatchOverrideFilters;
216    PendingIntent mDispatchOverrideIntent;
217
218    // TODO: none of these appear to be synchronized but are
219    // read/written from different threads (notably Binder threads)...
220    private int mGeneratedSocketHandle = 0;
221    private volatile boolean mIsNfcEnabled = false;
222    private int mSelectedSeId = 0;
223    private boolean mNfcSecureElementState;
224
225    // Secure element
226    private Timer mTimerOpenSmx;
227    private boolean isClosed = false;
228    private boolean isOpened = false;
229    private boolean mOpenSmxPending = false;
230    private NativeNfcSecureElement mSecureElement;
231    private int mSecureElementHandle;
232
233    // fields below are used in multiple threads and protected by synchronized(this)
234    private final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
235    private final HashMap<Integer, Object> mSocketMap = new HashMap<Integer, Object>();
236    private boolean mScreenOn;
237
238    // fields below are final after onCreate()
239    Context mContext;
240    private NativeNfcManager mManager;
241    private SharedPreferences mPrefs;
242    private SharedPreferences.Editor mPrefsEditor;
243    private PowerManager.WakeLock mWakeLock;
244    private IActivityManager mIActivityManager;
245    NdefPushClient mNdefPushClient;
246    NdefPushServer mNdefPushServer;
247
248    private static NfcService sService;
249
250    public static NfcService getInstance() {
251        return sService;
252    }
253
254    @Override
255    public void onCreate() {
256        super.onCreate();
257
258        Log.i(TAG, "Starting NFC service");
259
260        sService = this;
261
262        mContext = this;
263        mManager = new NativeNfcManager(mContext, this);
264        mManager.initializeNativeStructure();
265
266        mNdefPushClient = new NdefPushClient(this);
267        mNdefPushServer = new NdefPushServer();
268
269        mSecureElement = new NativeNfcSecureElement();
270
271        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
272        mPrefsEditor = mPrefs.edit();
273
274        mIsNfcEnabled = false;  // real preference read later
275
276        PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
277        mScreenOn = pm.isScreenOn();
278        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
279
280        mIActivityManager = ActivityManagerNative.getDefault();
281
282        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
283
284        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
285        filter.addAction(Intent.ACTION_SCREEN_OFF);
286        filter.addAction(Intent.ACTION_SCREEN_ON);
287        mContext.registerReceiver(mReceiver, filter);
288
289        Thread t = new Thread() {
290            @Override
291            public void run() {
292                boolean nfc_on = mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT);
293                if (nfc_on) {
294                    _enable(false);
295                }
296            }
297        };
298        t.start();
299    }
300
301    @Override
302    public void onTerminate() {
303        super.onTerminate();
304        // NFC application is persistent, it should not be destroyed by framework
305        Log.wtf(TAG, "NFC service is under attack!");
306    }
307
308    private final INfcAdapter.Stub mNfcAdapter = new INfcAdapter.Stub() {
309        /** Protected by "this" */
310        NdefMessage mLocalMessage = null;
311
312        @Override
313        public boolean enable() throws RemoteException {
314            mContext.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
315
316            boolean isSuccess = false;
317            boolean previouslyEnabled = isEnabled();
318            if (!previouslyEnabled) {
319                reset();
320                isSuccess = _enable(previouslyEnabled);
321            }
322            return isSuccess;
323        }
324
325        @Override
326        public boolean disable() throws RemoteException {
327            boolean isSuccess = false;
328            mContext.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
329            boolean previouslyEnabled = isEnabled();
330            if (DBG) Log.d(TAG, "Disabling NFC.  previous=" + previouslyEnabled);
331
332            if (previouslyEnabled) {
333                /* tear down the my tag server */
334                mNdefPushServer.stop();
335                isSuccess = mManager.deinitialize();
336                if (DBG) Log.d(TAG, "NFC success of deinitialize = " + isSuccess);
337                if (isSuccess) {
338                    mIsNfcEnabled = false;
339                    synchronized (this) {
340                        // Clear out any old dispatch overrides
341                        mDispatchOverrideFilters = null;
342                        mDispatchOverrideIntent = null;
343                    }
344                }
345            }
346
347            updateNfcOnSetting(previouslyEnabled);
348
349            return isSuccess;
350        }
351
352        @Override
353        public void enableForegroundDispatch(ComponentName activity, PendingIntent intent,
354                IntentFilter[] filters) {
355            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
356            if (activity == null || filters == null || filters.length == 0 || intent == null) {
357                throw new IllegalArgumentException();
358            }
359            synchronized (this) {
360                if (mDispatchOverrideFilters != null) {
361                    Log.e(TAG, "Replacing active dispatch overrides");
362                }
363                mDispatchOverrideFilters = filters;
364                mDispatchOverrideIntent = intent;
365            }
366        }
367
368        @Override
369        public void disableForegroundDispatch(ComponentName activity) {
370            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
371            synchronized (this) {
372                if (mDispatchOverrideFilters == null && mDispatchOverrideIntent == null) {
373                    Log.e(TAG, "No active foreground dispatching");
374                }
375                mDispatchOverrideFilters = null;
376                mDispatchOverrideIntent = null;
377            }
378        }
379
380        @Override
381        public void enableForegroundNdefPush(ComponentName activity, NdefMessage msg) {
382            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
383            if (activity == null || msg == null) {
384                throw new IllegalArgumentException();
385            }
386            if (mNdefPushClient.setForegroundMessage(msg)) {
387                Log.e(TAG, "Replacing active NDEF push message");
388            }
389        }
390
391        @Override
392        public void disableForegroundNdefPush(ComponentName activity) {
393            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
394            if (!mNdefPushClient.setForegroundMessage(null)) {
395                Log.e(TAG, "No active foreground NDEF push message");
396            }
397        }
398
399        @Override
400        public int createLlcpConnectionlessSocket(int sap) throws RemoteException {
401            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
402
403            // Check if NFC is enabled
404            if (!mIsNfcEnabled) {
405                return ErrorCodes.ERROR_NOT_INITIALIZED;
406            }
407
408            /* Check SAP is not already used */
409
410            /* Store the socket handle */
411            int sockeHandle = mGeneratedSocketHandle;
412            NativeLlcpConnectionlessSocket socket;
413
414            socket = mManager.doCreateLlcpConnectionlessSocket(sap);
415            if (socket != null) {
416                synchronized(NfcService.this) {
417                    /* update socket handle generation */
418                    mGeneratedSocketHandle++;
419
420                    /* Add the socket into the socket map */
421                    mSocketMap.put(mGeneratedSocketHandle, socket);
422                   return mGeneratedSocketHandle;
423                }
424            } else {
425                /* Get Error Status */
426                int errorStatus = mManager.doGetLastError();
427
428                switch (errorStatus) {
429                    case ErrorCodes.ERROR_BUFFER_TO_SMALL:
430                        return ErrorCodes.ERROR_BUFFER_TO_SMALL;
431                    case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
432                        return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
433                    default:
434                        return ErrorCodes.ERROR_SOCKET_CREATION;
435                }
436            }
437        }
438
439        @Override
440        public int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength)
441                throws RemoteException {
442            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
443
444            // Check if NFC is enabled
445            if (!mIsNfcEnabled) {
446                return ErrorCodes.ERROR_NOT_INITIALIZED;
447            }
448
449            NativeLlcpServiceSocket socket;
450
451            socket = mManager.doCreateLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength);
452            if (socket != null) {
453                synchronized(NfcService.this) {
454                    /* update socket handle generation */
455                    mGeneratedSocketHandle++;
456
457                    /* Add the socket into the socket map */
458                    mSocketMap.put(mGeneratedSocketHandle, socket);
459                   return mGeneratedSocketHandle;
460                }
461            } else {
462                /* Get Error Status */
463                int errorStatus = mManager.doGetLastError();
464
465                switch (errorStatus) {
466                    case ErrorCodes.ERROR_BUFFER_TO_SMALL:
467                        return ErrorCodes.ERROR_BUFFER_TO_SMALL;
468                    case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
469                        return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
470                    default:
471                        return ErrorCodes.ERROR_SOCKET_CREATION;
472                }
473            }
474        }
475
476        @Override
477        public int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
478                throws RemoteException {
479            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
480
481            // Check if NFC is enabled
482            if (!mIsNfcEnabled) {
483                return ErrorCodes.ERROR_NOT_INITIALIZED;
484            }
485
486            if (DBG) Log.d(TAG, "creating llcp socket");
487            NativeLlcpSocket socket;
488
489            socket = mManager.doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
490
491            if (socket != null) {
492                synchronized(NfcService.this) {
493                    /* update socket handle generation */
494                    mGeneratedSocketHandle++;
495
496                    /* Add the socket into the socket map */
497                    mSocketMap.put(mGeneratedSocketHandle, socket);
498                   return mGeneratedSocketHandle;
499                }
500            } else {
501                /* Get Error Status */
502                int errorStatus = mManager.doGetLastError();
503
504                Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(errorStatus));
505
506                switch (errorStatus) {
507                    case ErrorCodes.ERROR_BUFFER_TO_SMALL:
508                        return ErrorCodes.ERROR_BUFFER_TO_SMALL;
509                    case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
510                        return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
511                    default:
512                        return ErrorCodes.ERROR_SOCKET_CREATION;
513                }
514            }
515        }
516
517        @Override
518        public int deselectSecureElement() throws RemoteException {
519            mContext.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
520
521            // Check if NFC is enabled
522            if (!mIsNfcEnabled) {
523                return ErrorCodes.ERROR_NOT_INITIALIZED;
524            }
525
526            if (mSelectedSeId == 0) {
527                return ErrorCodes.ERROR_NO_SE_CONNECTED;
528            }
529
530            mManager.doDeselectSecureElement(mSelectedSeId);
531            mNfcSecureElementState = false;
532            mSelectedSeId = 0;
533
534            /* store preference */
535            mPrefsEditor.putBoolean(PREF_SECURE_ELEMENT_ON, false);
536            mPrefsEditor.putInt(PREF_SECURE_ELEMENT_ID, 0);
537            mPrefsEditor.apply();
538
539            return ErrorCodes.SUCCESS;
540        }
541
542        @Override
543        public ILlcpConnectionlessSocket getLlcpConnectionlessInterface() throws RemoteException {
544            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
545            return mLlcpConnectionlessSocketService;
546        }
547
548        @Override
549        public ILlcpSocket getLlcpInterface() throws RemoteException {
550            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
551            return mLlcpSocket;
552        }
553
554        @Override
555        public ILlcpServiceSocket getLlcpServiceInterface() throws RemoteException {
556            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
557            return mLlcpServerSocketService;
558        }
559
560        @Override
561        public INfcTag getNfcTagInterface() throws RemoteException {
562            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
563            return mNfcTagService;
564        }
565
566        @Override
567        public IP2pInitiator getP2pInitiatorInterface() throws RemoteException {
568            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
569            return mP2pInitiatorService;
570        }
571
572        @Override
573        public IP2pTarget getP2pTargetInterface() throws RemoteException {
574            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
575            return mP2pTargetService;
576        }
577
578        public INfcSecureElement getNfcSecureElementInterface() {
579            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
580            return mSecureElementService;
581        }
582
583        @Override
584        public String getProperties(String param) throws RemoteException {
585            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
586
587            if (param == null) {
588                return null;
589            }
590
591            if (param.equals(PROPERTY_LLCP_LTO_VALUE)) {
592                return Integer.toString(mPrefs.getInt(PREF_LLCP_LTO, LLCP_LTO_DEFAULT));
593            } else if (param.equals(PROPERTY_LLCP_MIU_VALUE)) {
594                return Integer.toString(mPrefs.getInt(PREF_LLCP_MIU, LLCP_MIU_DEFAULT));
595            } else if (param.equals(PROPERTY_LLCP_WKS_VALUE)) {
596                return Integer.toString(mPrefs.getInt(PREF_LLCP_WKS, LLCP_WKS_DEFAULT));
597            } else if (param.equals(PROPERTY_LLCP_OPT_VALUE)) {
598                return Integer.toString(mPrefs.getInt(PREF_LLCP_OPT, LLCP_OPT_DEFAULT));
599            } else if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)) {
600                return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_A, DISCOVERY_A_DEFAULT));
601            } else if (param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)) {
602                return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_B, DISCOVERY_B_DEFAULT));
603            } else if (param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)) {
604                return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_F, DISCOVERY_F_DEFAULT));
605            } else if (param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)) {
606                return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_NFCIP, DISCOVERY_NFCIP_DEFAULT));
607            } else if (param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) {
608                return Boolean.toString(mPrefs.getBoolean(PREF_DISCOVERY_15693, DISCOVERY_15693_DEFAULT));
609            } else {
610                return "Unknown property";
611            }
612        }
613
614        @Override
615        public int[] getSecureElementList() throws RemoteException {
616            mContext.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
617
618            int[] list = null;
619            if (mIsNfcEnabled == true) {
620                list = mManager.doGetSecureElementList();
621            }
622            return list;
623        }
624
625        @Override
626        public int getSelectedSecureElement() throws RemoteException {
627            mContext.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
628
629            return mSelectedSeId;
630        }
631
632        @Override
633        public boolean isEnabled() throws RemoteException {
634            return mIsNfcEnabled;
635        }
636
637        @Override
638        public void openTagConnection(Tag tag) throws RemoteException {
639            // TODO: Remove obsolete code
640        }
641
642        @Override
643        public int selectSecureElement(int seId) throws RemoteException {
644            mContext.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
645
646            // Check if NFC is enabled
647            if (!mIsNfcEnabled) {
648                return ErrorCodes.ERROR_NOT_INITIALIZED;
649            }
650
651            if (mSelectedSeId == seId) {
652                return ErrorCodes.ERROR_SE_ALREADY_SELECTED;
653            }
654
655            if (mSelectedSeId != 0) {
656                return ErrorCodes.ERROR_SE_CONNECTED;
657            }
658
659            mSelectedSeId = seId;
660            mManager.doSelectSecureElement(mSelectedSeId);
661
662            /* store */
663            mPrefsEditor.putBoolean(PREF_SECURE_ELEMENT_ON, true);
664            mPrefsEditor.putInt(PREF_SECURE_ELEMENT_ID, mSelectedSeId);
665            mPrefsEditor.apply();
666
667            mNfcSecureElementState = true;
668
669            return ErrorCodes.SUCCESS;
670
671        }
672
673        @Override
674        public int setProperties(String param, String value) throws RemoteException {
675            mContext.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
676
677            if (isEnabled()) {
678                return ErrorCodes.ERROR_NFC_ON;
679            }
680
681            int val;
682
683            /* Check params validity */
684            if (param == null || value == null) {
685                return ErrorCodes.ERROR_INVALID_PARAM;
686            }
687
688            if (param.equals(PROPERTY_LLCP_LTO_VALUE)) {
689                val = Integer.parseInt(value);
690
691                /* Check params */
692                if (val > LLCP_LTO_MAX)
693                    return ErrorCodes.ERROR_INVALID_PARAM;
694
695                /* Store value */
696                mPrefsEditor.putInt(PREF_LLCP_LTO, val);
697                mPrefsEditor.apply();
698
699                /* Update JNI */
700                mManager.doSetProperties(PROPERTY_LLCP_LTO, val);
701
702            } else if (param.equals(PROPERTY_LLCP_MIU_VALUE)) {
703                val = Integer.parseInt(value);
704
705                /* Check params */
706                if ((val < LLCP_MIU_DEFAULT) || (val > LLCP_MIU_MAX))
707                    return ErrorCodes.ERROR_INVALID_PARAM;
708
709                /* Store value */
710                mPrefsEditor.putInt(PREF_LLCP_MIU, val);
711                mPrefsEditor.apply();
712
713                /* Update JNI */
714                mManager.doSetProperties(PROPERTY_LLCP_MIU, val);
715
716            } else if (param.equals(PROPERTY_LLCP_WKS_VALUE)) {
717                val = Integer.parseInt(value);
718
719                /* Check params */
720                if (val > LLCP_WKS_MAX)
721                    return ErrorCodes.ERROR_INVALID_PARAM;
722
723                /* Store value */
724                mPrefsEditor.putInt(PREF_LLCP_WKS, val);
725                mPrefsEditor.apply();
726
727                /* Update JNI */
728                mManager.doSetProperties(PROPERTY_LLCP_WKS, val);
729
730            } else if (param.equals(PROPERTY_LLCP_OPT_VALUE)) {
731                val = Integer.parseInt(value);
732
733                /* Check params */
734                if (val > LLCP_OPT_MAX)
735                    return ErrorCodes.ERROR_INVALID_PARAM;
736
737                /* Store value */
738                mPrefsEditor.putInt(PREF_LLCP_OPT, val);
739                mPrefsEditor.apply();
740
741                /* Update JNI */
742                mManager.doSetProperties(PROPERTY_LLCP_OPT, val);
743
744            } else if (param.equals(PROPERTY_NFC_DISCOVERY_A_VALUE)) {
745                boolean b = Boolean.parseBoolean(value);
746
747                /* Store value */
748                mPrefsEditor.putBoolean(PREF_DISCOVERY_A, b);
749                mPrefsEditor.apply();
750
751                /* Update JNI */
752                mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_A, b ? 1 : 0);
753
754            } else if (param.equals(PROPERTY_NFC_DISCOVERY_B_VALUE)) {
755                boolean b = Boolean.parseBoolean(value);
756
757                /* Store value */
758                mPrefsEditor.putBoolean(PREF_DISCOVERY_B, b);
759                mPrefsEditor.apply();
760
761                /* Update JNI */
762                mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_B, b ? 1 : 0);
763
764            } else if (param.equals(PROPERTY_NFC_DISCOVERY_F_VALUE)) {
765                boolean b = Boolean.parseBoolean(value);
766
767                /* Store value */
768                mPrefsEditor.putBoolean(PREF_DISCOVERY_F, b);
769                mPrefsEditor.apply();
770
771                /* Update JNI */
772                mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_F, b ? 1 : 0);
773
774            } else if (param.equals(PROPERTY_NFC_DISCOVERY_15693_VALUE)) {
775                boolean b = Boolean.parseBoolean(value);
776
777                /* Store value */
778                mPrefsEditor.putBoolean(PREF_DISCOVERY_15693, b);
779                mPrefsEditor.apply();
780
781                /* Update JNI */
782                mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_15693, b ? 1 : 0);
783
784            } else if (param.equals(PROPERTY_NFC_DISCOVERY_NFCIP_VALUE)) {
785                boolean b = Boolean.parseBoolean(value);
786
787                /* Store value */
788                mPrefsEditor.putBoolean(PREF_DISCOVERY_NFCIP, b);
789                mPrefsEditor.apply();
790
791                /* Update JNI */
792                mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_NFCIP, b ? 1 : 0);
793
794            } else {
795                return ErrorCodes.ERROR_INVALID_PARAM;
796            }
797
798            return ErrorCodes.SUCCESS;
799        }
800
801        @Override
802        public NdefMessage localGet() throws RemoteException {
803            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
804
805            synchronized (this) {
806                return mLocalMessage;
807            }
808        }
809
810        @Override
811        public void localSet(NdefMessage message) throws RemoteException {
812            mContext.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
813
814            synchronized (this) {
815                mLocalMessage = message;
816                Context context = NfcService.this.getApplicationContext();
817
818                // Send a message to the UI thread to show or hide the icon so the requests are
819                // serialized and the icon can't get out of sync with reality.
820                if (message != null) {
821                    FileOutputStream out = null;
822
823                    try {
824                        out = context.openFileOutput(MY_TAG_FILE_NAME, Context.MODE_PRIVATE);
825                        byte[] bytes = message.toByteArray();
826                        if (bytes.length == 0) {
827                            Log.w(TAG, "Setting a empty mytag");
828                        }
829
830                        out.write(bytes);
831                    } catch (IOException e) {
832                        Log.e(TAG, "Could not write mytag file", e);
833                    } finally {
834                        try {
835                            if (out != null) {
836                                out.flush();
837                                out.close();
838                            }
839                        } catch (IOException e) {
840                            // Ignore
841                        }
842                    }
843
844                    // Only show the icon if NFC is enabled.
845                    if (mIsNfcEnabled) {
846                        sendMessage(MSG_SHOW_MY_TAG_ICON, null);
847                    }
848                } else {
849                    context.deleteFile(MY_TAG_FILE_NAME);
850                    sendMessage(MSG_HIDE_MY_TAG_ICON, null);
851                }
852            }
853        }
854    };
855
856    private final ILlcpSocket mLlcpSocket = new ILlcpSocket.Stub() {
857
858        private NativeLlcpSocket findSocket(int nativeHandle) {
859            Object socket = NfcService.this.findSocket(nativeHandle);
860            if (!(socket instanceof NativeLlcpSocket)) {
861                return null;
862            }
863            return (NativeLlcpSocket) socket;
864        }
865
866        @Override
867        public int close(int nativeHandle) throws RemoteException {
868            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
869
870            NativeLlcpSocket socket = null;
871
872            // Check if NFC is enabled
873            if (!mIsNfcEnabled) {
874                return ErrorCodes.ERROR_NOT_INITIALIZED;
875            }
876
877            /* find the socket in the hmap */
878            socket = findSocket(nativeHandle);
879            if (socket != null) {
880                socket.doClose();
881                /* Remove the socket closed from the hmap */
882                RemoveSocket(nativeHandle);
883                return ErrorCodes.SUCCESS;
884            } else {
885                return ErrorCodes.ERROR_IO;
886            }
887        }
888
889        @Override
890        public int connect(int nativeHandle, int sap) throws RemoteException {
891            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
892
893            NativeLlcpSocket socket = null;
894            boolean isSuccess = false;
895
896            // Check if NFC is enabled
897            if (!mIsNfcEnabled) {
898                return ErrorCodes.ERROR_NOT_INITIALIZED;
899            }
900
901            /* find the socket in the hmap */
902            socket = findSocket(nativeHandle);
903            if (socket != null) {
904                isSuccess = socket.doConnect(sap);
905                if (isSuccess) {
906                    return ErrorCodes.SUCCESS;
907                } else {
908                    return ErrorCodes.ERROR_IO;
909                }
910            } else {
911                return ErrorCodes.ERROR_IO;
912            }
913
914        }
915
916        @Override
917        public int connectByName(int nativeHandle, String sn) throws RemoteException {
918            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
919
920            NativeLlcpSocket socket = null;
921            boolean isSuccess = false;
922
923            // Check if NFC is enabled
924            if (!mIsNfcEnabled) {
925                return ErrorCodes.ERROR_NOT_INITIALIZED;
926            }
927
928            /* find the socket in the hmap */
929            socket = findSocket(nativeHandle);
930            if (socket != null) {
931                isSuccess = socket.doConnectBy(sn);
932                if (isSuccess) {
933                    return ErrorCodes.SUCCESS;
934                } else {
935                    return ErrorCodes.ERROR_IO;
936                }
937            } else {
938                return ErrorCodes.ERROR_IO;
939            }
940
941        }
942
943        @Override
944        public int getLocalSap(int nativeHandle) throws RemoteException {
945            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
946
947            NativeLlcpSocket socket = null;
948
949            // Check if NFC is enabled
950            if (!mIsNfcEnabled) {
951                return ErrorCodes.ERROR_NOT_INITIALIZED;
952            }
953
954            /* find the socket in the hmap */
955            socket = findSocket(nativeHandle);
956            if (socket != null) {
957                return socket.getSap();
958            } else {
959                return 0;
960            }
961        }
962
963        @Override
964        public int getLocalSocketMiu(int nativeHandle) throws RemoteException {
965            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
966
967            NativeLlcpSocket socket = null;
968
969            // Check if NFC is enabled
970            if (!mIsNfcEnabled) {
971                return ErrorCodes.ERROR_NOT_INITIALIZED;
972            }
973
974            /* find the socket in the hmap */
975            socket = findSocket(nativeHandle);
976            if (socket != null) {
977                return socket.getMiu();
978            } else {
979                return 0;
980            }
981        }
982
983        @Override
984        public int getLocalSocketRw(int nativeHandle) throws RemoteException {
985            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
986
987            NativeLlcpSocket socket = null;
988
989            // Check if NFC is enabled
990            if (!mIsNfcEnabled) {
991                return ErrorCodes.ERROR_NOT_INITIALIZED;
992            }
993
994            /* find the socket in the hmap */
995            socket = findSocket(nativeHandle);
996            if (socket != null) {
997                return socket.getRw();
998            } else {
999                return 0;
1000            }
1001        }
1002
1003        @Override
1004        public int getRemoteSocketMiu(int nativeHandle) throws RemoteException {
1005            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1006
1007            NativeLlcpSocket socket = null;
1008
1009            // Check if NFC is enabled
1010            if (!mIsNfcEnabled) {
1011                return ErrorCodes.ERROR_NOT_INITIALIZED;
1012            }
1013
1014            /* find the socket in the hmap */
1015            socket = findSocket(nativeHandle);
1016            if (socket != null) {
1017                if (socket.doGetRemoteSocketMiu() != 0) {
1018                    return socket.doGetRemoteSocketMiu();
1019                } else {
1020                    return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
1021                }
1022            } else {
1023                return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
1024            }
1025        }
1026
1027        @Override
1028        public int getRemoteSocketRw(int nativeHandle) throws RemoteException {
1029            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1030
1031            NativeLlcpSocket socket = null;
1032
1033            // Check if NFC is enabled
1034            if (!mIsNfcEnabled) {
1035                return ErrorCodes.ERROR_NOT_INITIALIZED;
1036            }
1037
1038            /* find the socket in the hmap */
1039            socket = findSocket(nativeHandle);
1040            if (socket != null) {
1041                if (socket.doGetRemoteSocketRw() != 0) {
1042                    return socket.doGetRemoteSocketRw();
1043                } else {
1044                    return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
1045                }
1046            } else {
1047                return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
1048            }
1049        }
1050
1051        @Override
1052        public int receive(int nativeHandle, byte[] receiveBuffer) throws RemoteException {
1053            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1054
1055            NativeLlcpSocket socket = null;
1056
1057            // Check if NFC is enabled
1058            if (!mIsNfcEnabled) {
1059                return ErrorCodes.ERROR_NOT_INITIALIZED;
1060            }
1061
1062            /* find the socket in the hmap */
1063            socket = findSocket(nativeHandle);
1064            if (socket != null) {
1065                return socket.doReceive(receiveBuffer);
1066            } else {
1067                return 0;
1068            }
1069        }
1070
1071        @Override
1072        public int send(int nativeHandle, byte[] data) throws RemoteException {
1073            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1074
1075            NativeLlcpSocket socket = null;
1076            boolean isSuccess = false;
1077
1078            // Check if NFC is enabled
1079            if (!mIsNfcEnabled) {
1080                return ErrorCodes.ERROR_NOT_INITIALIZED;
1081            }
1082
1083            /* find the socket in the hmap */
1084            socket = findSocket(nativeHandle);
1085            if (socket != null) {
1086                isSuccess = socket.doSend(data);
1087                if (isSuccess) {
1088                    return ErrorCodes.SUCCESS;
1089                } else {
1090                    return ErrorCodes.ERROR_IO;
1091                }
1092            } else {
1093                return ErrorCodes.ERROR_IO;
1094            }
1095        }
1096    };
1097
1098    private final ILlcpServiceSocket mLlcpServerSocketService = new ILlcpServiceSocket.Stub() {
1099
1100        private NativeLlcpServiceSocket findSocket(int nativeHandle) {
1101            Object socket = NfcService.this.findSocket(nativeHandle);
1102            if (!(socket instanceof NativeLlcpServiceSocket)) {
1103                return null;
1104            }
1105            return (NativeLlcpServiceSocket) socket;
1106        }
1107
1108        @Override
1109        public int accept(int nativeHandle) throws RemoteException {
1110            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1111
1112            NativeLlcpServiceSocket socket = null;
1113            NativeLlcpSocket clientSocket = null;
1114
1115            // Check if NFC is enabled
1116            if (!mIsNfcEnabled) {
1117                return ErrorCodes.ERROR_NOT_INITIALIZED;
1118            }
1119
1120                /* find the socket in the hmap */
1121                socket = findSocket(nativeHandle);
1122                if (socket != null) {
1123                    clientSocket = socket.doAccept(socket.getMiu(),
1124                            socket.getRw(), socket.getLinearBufferLength());
1125                    if (clientSocket != null) {
1126                        /* Add the socket into the socket map */
1127                        synchronized(this) {
1128                            mGeneratedSocketHandle++;
1129                            mSocketMap.put(mGeneratedSocketHandle, clientSocket);
1130                            return mGeneratedSocketHandle;
1131                        }
1132                    } else {
1133                        return ErrorCodes.ERROR_IO;
1134                    }
1135                } else {
1136                    return ErrorCodes.ERROR_IO;
1137                }
1138        }
1139
1140        @Override
1141        public void close(int nativeHandle) throws RemoteException {
1142            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1143
1144            NativeLlcpServiceSocket socket = null;
1145
1146            // Check if NFC is enabled
1147            if (!mIsNfcEnabled) {
1148                return;
1149            }
1150
1151            /* find the socket in the hmap */
1152            socket = findSocket(nativeHandle);
1153            if (socket != null) {
1154                socket.doClose();
1155                synchronized (this) {
1156                    /* Remove the socket closed from the hmap */
1157                    RemoveSocket(nativeHandle);
1158                }
1159            }
1160        }
1161    };
1162
1163    private final ILlcpConnectionlessSocket mLlcpConnectionlessSocketService = new ILlcpConnectionlessSocket.Stub() {
1164
1165        private NativeLlcpConnectionlessSocket findSocket(int nativeHandle) {
1166            Object socket = NfcService.this.findSocket(nativeHandle);
1167            if (!(socket instanceof NativeLlcpConnectionlessSocket)) {
1168                return null;
1169            }
1170            return (NativeLlcpConnectionlessSocket) socket;
1171        }
1172
1173        @Override
1174        public void close(int nativeHandle) throws RemoteException {
1175            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1176
1177            NativeLlcpConnectionlessSocket socket = null;
1178
1179            // Check if NFC is enabled
1180            if (!mIsNfcEnabled) {
1181                return;
1182            }
1183
1184            /* find the socket in the hmap */
1185            socket = findSocket(nativeHandle);
1186            if (socket != null) {
1187                socket.doClose();
1188                /* Remove the socket closed from the hmap */
1189                RemoveSocket(nativeHandle);
1190            }
1191        }
1192
1193        @Override
1194        public int getSap(int nativeHandle) throws RemoteException {
1195            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1196
1197            NativeLlcpConnectionlessSocket socket = null;
1198
1199            // Check if NFC is enabled
1200            if (!mIsNfcEnabled) {
1201                return ErrorCodes.ERROR_NOT_INITIALIZED;
1202            }
1203
1204            /* find the socket in the hmap */
1205            socket = findSocket(nativeHandle);
1206            if (socket != null) {
1207                return socket.getSap();
1208            } else {
1209                return 0;
1210            }
1211        }
1212
1213        @Override
1214        public LlcpPacket receiveFrom(int nativeHandle) throws RemoteException {
1215            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1216
1217            NativeLlcpConnectionlessSocket socket = null;
1218            LlcpPacket packet;
1219
1220            // Check if NFC is enabled
1221            if (!mIsNfcEnabled) {
1222                return null;
1223            }
1224
1225            /* find the socket in the hmap */
1226            socket = findSocket(nativeHandle);
1227            if (socket != null) {
1228                packet = socket.doReceiveFrom(socket.getLinkMiu());
1229                if (packet != null) {
1230                    return packet;
1231                }
1232                return null;
1233            } else {
1234                return null;
1235            }
1236        }
1237
1238        @Override
1239        public int sendTo(int nativeHandle, LlcpPacket packet) throws RemoteException {
1240            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1241
1242            NativeLlcpConnectionlessSocket socket = null;
1243            boolean isSuccess = false;
1244
1245            // Check if NFC is enabled
1246            if (!mIsNfcEnabled) {
1247                return ErrorCodes.ERROR_NOT_INITIALIZED;
1248            }
1249
1250            /* find the socket in the hmap */
1251            socket = findSocket(nativeHandle);
1252            if (socket != null) {
1253                isSuccess = socket.doSendTo(packet.getRemoteSap(), packet.getDataBuffer());
1254                if (isSuccess) {
1255                    return ErrorCodes.SUCCESS;
1256                } else {
1257                    return ErrorCodes.ERROR_IO;
1258                }
1259            } else {
1260                return ErrorCodes.ERROR_IO;
1261            }
1262        }
1263    };
1264
1265    private final INfcTag mNfcTagService = new INfcTag.Stub() {
1266
1267        @Override
1268        public int close(int nativeHandle) throws RemoteException {
1269            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1270
1271            NativeNfcTag tag = null;
1272
1273            // Check if NFC is enabled
1274            if (!mIsNfcEnabled) {
1275                return ErrorCodes.ERROR_NOT_INITIALIZED;
1276            }
1277
1278            /* find the tag in the hmap */
1279            tag = (NativeNfcTag) findObject(nativeHandle);
1280            if (tag != null) {
1281                /* Remove the device from the hmap */
1282                unregisterObject(nativeHandle);
1283                tag.disconnect();
1284                return ErrorCodes.SUCCESS;
1285            }
1286            /* Restart polling loop for notification */
1287            maybeEnableDiscovery();
1288            return ErrorCodes.ERROR_DISCONNECT;
1289        }
1290
1291        @Override
1292        public int connect(int nativeHandle, int technology) throws RemoteException {
1293            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1294
1295            NativeNfcTag tag = null;
1296
1297            // Check if NFC is enabled
1298            if (!mIsNfcEnabled) {
1299                return ErrorCodes.ERROR_NOT_INITIALIZED;
1300            }
1301
1302            /* find the tag in the hmap */
1303            tag = (NativeNfcTag) findObject(nativeHandle);
1304            if (tag == null) {
1305                return ErrorCodes.ERROR_DISCONNECT;
1306            }
1307
1308            // Note that on most tags, all technologies are behind a single
1309            // handle. This means that the connect at the lower levels
1310            // will do nothing, as the tag is already connected to that handle.
1311            if (tag.connect(technology)) {
1312                return ErrorCodes.SUCCESS;
1313            } else {
1314                return ErrorCodes.ERROR_DISCONNECT;
1315            }
1316        }
1317
1318        @Override
1319        public int reconnect(int nativeHandle) throws RemoteException {
1320            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1321
1322            NativeNfcTag tag = null;
1323
1324            // Check if NFC is enabled
1325            if (!mIsNfcEnabled) {
1326                return ErrorCodes.ERROR_NOT_INITIALIZED;
1327            }
1328
1329            /* find the tag in the hmap */
1330            tag = (NativeNfcTag) findObject(nativeHandle);
1331            if (tag != null) {
1332                if (tag.reconnect()) {
1333                    return ErrorCodes.SUCCESS;
1334                } else {
1335                    return ErrorCodes.ERROR_DISCONNECT;
1336                }
1337            }
1338            return ErrorCodes.ERROR_DISCONNECT;
1339        }
1340
1341        @Override
1342        public int[] getTechList(int nativeHandle) throws RemoteException {
1343            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1344
1345            // Check if NFC is enabled
1346            if (!mIsNfcEnabled) {
1347                return null;
1348            }
1349
1350            /* find the tag in the hmap */
1351            NativeNfcTag tag = (NativeNfcTag) findObject(nativeHandle);
1352            if (tag != null) {
1353                return tag.getTechList();
1354            }
1355            return null;
1356        }
1357
1358        @Override
1359        public byte[] getUid(int nativeHandle) throws RemoteException {
1360            NativeNfcTag tag = null;
1361            byte[] uid;
1362
1363            // Check if NFC is enabled
1364            if (!mIsNfcEnabled) {
1365                return null;
1366            }
1367
1368            /* find the tag in the hmap */
1369            tag = (NativeNfcTag) findObject(nativeHandle);
1370            if (tag != null) {
1371                uid = tag.getUid();
1372                return uid;
1373            }
1374            return null;
1375        }
1376
1377        @Override
1378        public boolean isPresent(int nativeHandle) throws RemoteException {
1379            NativeNfcTag tag = null;
1380
1381            // Check if NFC is enabled
1382            if (!mIsNfcEnabled) {
1383                return false;
1384            }
1385
1386            /* find the tag in the hmap */
1387            tag = (NativeNfcTag) findObject(nativeHandle);
1388            if (tag == null) {
1389                return false;
1390            }
1391
1392            return tag.presenceCheck();
1393        }
1394
1395        @Override
1396        public boolean isNdef(int nativeHandle) throws RemoteException {
1397            NativeNfcTag tag = null;
1398            boolean isSuccess = false;
1399
1400            // Check if NFC is enabled
1401            if (!mIsNfcEnabled) {
1402                return isSuccess;
1403            }
1404
1405            /* find the tag in the hmap */
1406            tag = (NativeNfcTag) findObject(nativeHandle);
1407            int[] ndefInfo = new int[2];
1408            if (tag != null) {
1409                isSuccess = tag.checkNdef(ndefInfo);
1410            }
1411            return isSuccess;
1412        }
1413
1414        @Override
1415        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
1416                throws RemoteException {
1417            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1418
1419            NativeNfcTag tag = null;
1420            byte[] response;
1421
1422            // Check if NFC is enabled
1423            if (!mIsNfcEnabled) {
1424                return null;
1425            }
1426
1427            /* find the tag in the hmap */
1428            tag = (NativeNfcTag) findObject(nativeHandle);
1429            if (tag != null) {
1430                int[] targetLost = new int[1];
1431                response = tag.transceive(data, raw, targetLost);
1432                TransceiveResult transResult = new TransceiveResult(
1433                        (response != null) ? true : false,
1434                        (targetLost[0] == 1) ? true : false,
1435                        response);
1436                return transResult;
1437            }
1438            return null;
1439        }
1440
1441        @Override
1442        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1443            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1444
1445            NativeNfcTag tag;
1446
1447            // Check if NFC is enabled
1448            if (!mIsNfcEnabled) {
1449                return null;
1450            }
1451
1452            /* find the tag in the hmap */
1453            tag = (NativeNfcTag) findObject(nativeHandle);
1454            if (tag != null) {
1455                byte[] buf = tag.read();
1456                if (buf == null)
1457                    return null;
1458
1459                /* Create an NdefMessage */
1460                try {
1461                    return new NdefMessage(buf);
1462                } catch (FormatException e) {
1463                    return null;
1464                }
1465            }
1466            return null;
1467        }
1468
1469        @Override
1470        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1471            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1472
1473            NativeNfcTag tag;
1474
1475            // Check if NFC is enabled
1476            if (!mIsNfcEnabled) {
1477                return ErrorCodes.ERROR_NOT_INITIALIZED;
1478            }
1479
1480            /* find the tag in the hmap */
1481            tag = (NativeNfcTag) findObject(nativeHandle);
1482            if (tag == null) {
1483                return ErrorCodes.ERROR_IO;
1484            }
1485
1486            if (tag.write(msg.toByteArray())) {
1487                return ErrorCodes.SUCCESS;
1488            }
1489            else {
1490                return ErrorCodes.ERROR_IO;
1491            }
1492
1493        }
1494
1495        @Override
1496        public int getLastError(int nativeHandle) throws RemoteException {
1497            return(mManager.doGetLastError());
1498        }
1499
1500        @Override
1501        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
1502            throw new UnsupportedOperationException();
1503        }
1504
1505        @Override
1506        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
1507            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1508
1509            NativeNfcTag tag;
1510
1511            // Check if NFC is enabled
1512            if (!mIsNfcEnabled) {
1513                return ErrorCodes.ERROR_NOT_INITIALIZED;
1514            }
1515
1516            /* find the tag in the hmap */
1517            tag = (NativeNfcTag) findObject(nativeHandle);
1518            if (tag == null) {
1519                return ErrorCodes.ERROR_IO;
1520            }
1521
1522            if (tag.makeReadonly()) {
1523                return ErrorCodes.SUCCESS;
1524            }
1525            else {
1526                return ErrorCodes.ERROR_IO;
1527            }
1528        }
1529
1530        @Override
1531        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
1532            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1533
1534            NativeNfcTag tag;
1535
1536            // Check if NFC is enabled
1537            if (!mIsNfcEnabled) {
1538                return ErrorCodes.ERROR_NOT_INITIALIZED;
1539            }
1540
1541            /* find the tag in the hmap */
1542            tag = (NativeNfcTag) findObject(nativeHandle);
1543            if (tag == null) {
1544                return ErrorCodes.ERROR_IO;
1545            }
1546
1547            if (tag.formatNdef(key)) {
1548                return ErrorCodes.SUCCESS;
1549            }
1550            else {
1551                return ErrorCodes.ERROR_IO;
1552            }
1553        }
1554
1555        @Override
1556        public void setIsoDepTimeout(int timeout) throws RemoteException {
1557            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1558
1559            mManager.setIsoDepTimeout(timeout);
1560        }
1561
1562        @Override
1563        public void resetIsoDepTimeout() throws RemoteException {
1564            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1565
1566            mManager.resetIsoDepTimeout();
1567        }
1568    };
1569
1570    private final IP2pInitiator mP2pInitiatorService = new IP2pInitiator.Stub() {
1571
1572        @Override
1573        public byte[] getGeneralBytes(int nativeHandle) throws RemoteException {
1574            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1575
1576            NativeP2pDevice device;
1577
1578            // Check if NFC is enabled
1579            if (!mIsNfcEnabled) {
1580                return null;
1581            }
1582
1583            /* find the device in the hmap */
1584            device = (NativeP2pDevice) findObject(nativeHandle);
1585            if (device != null) {
1586                byte[] buff = device.getGeneralBytes();
1587                if (buff == null)
1588                    return null;
1589                return buff;
1590            }
1591            return null;
1592        }
1593
1594        @Override
1595        public int getMode(int nativeHandle) throws RemoteException {
1596            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1597
1598            NativeP2pDevice device;
1599
1600            // Check if NFC is enabled
1601            if (!mIsNfcEnabled) {
1602                return ErrorCodes.ERROR_NOT_INITIALIZED;
1603            }
1604
1605            /* find the device in the hmap */
1606            device = (NativeP2pDevice) findObject(nativeHandle);
1607            if (device != null) {
1608                return device.getMode();
1609            }
1610            return ErrorCodes.ERROR_INVALID_PARAM;
1611        }
1612
1613        @Override
1614        public byte[] receive(int nativeHandle) throws RemoteException {
1615            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1616
1617            NativeP2pDevice device;
1618
1619            // Check if NFC is enabled
1620            if (!mIsNfcEnabled) {
1621                return null;
1622            }
1623
1624            /* find the device in the hmap */
1625            device = (NativeP2pDevice) findObject(nativeHandle);
1626            if (device != null) {
1627                byte[] buff = device.doReceive();
1628                if (buff == null)
1629                    return null;
1630                return buff;
1631            }
1632            /* Restart polling loop for notification */
1633            maybeEnableDiscovery();
1634            return null;
1635        }
1636
1637        @Override
1638        public boolean send(int nativeHandle, byte[] data) throws RemoteException {
1639            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1640
1641            NativeP2pDevice device;
1642            boolean isSuccess = false;
1643
1644            // Check if NFC is enabled
1645            if (!mIsNfcEnabled) {
1646                return isSuccess;
1647            }
1648
1649            /* find the device in the hmap */
1650            device = (NativeP2pDevice) findObject(nativeHandle);
1651            if (device != null) {
1652                isSuccess = device.doSend(data);
1653            }
1654            return isSuccess;
1655        }
1656    };
1657
1658    private final IP2pTarget mP2pTargetService = new IP2pTarget.Stub() {
1659
1660        @Override
1661        public int connect(int nativeHandle) throws RemoteException {
1662            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1663
1664            NativeP2pDevice device;
1665
1666            // Check if NFC is enabled
1667            if (!mIsNfcEnabled) {
1668                return ErrorCodes.ERROR_NOT_INITIALIZED;
1669            }
1670
1671            /* find the device in the hmap */
1672            device = (NativeP2pDevice) findObject(nativeHandle);
1673            if (device != null) {
1674                if (device.doConnect()) {
1675                    return ErrorCodes.SUCCESS;
1676                }
1677            }
1678            return ErrorCodes.ERROR_CONNECT;
1679        }
1680
1681        @Override
1682        public boolean disconnect(int nativeHandle) throws RemoteException {
1683            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1684
1685            NativeP2pDevice device;
1686            boolean isSuccess = false;
1687
1688            // Check if NFC is enabled
1689            if (!mIsNfcEnabled) {
1690                return isSuccess;
1691            }
1692
1693            /* find the device in the hmap */
1694            device = (NativeP2pDevice) findObject(nativeHandle);
1695            if (device != null) {
1696                if (isSuccess = device.doDisconnect()) {
1697                    /* remove the device from the hmap */
1698                    unregisterObject(nativeHandle);
1699                    /* Restart polling loop for notification */
1700                    maybeEnableDiscovery();
1701                }
1702            }
1703            return isSuccess;
1704
1705        }
1706
1707        @Override
1708        public byte[] getGeneralBytes(int nativeHandle) throws RemoteException {
1709            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1710
1711            NativeP2pDevice device;
1712
1713            // Check if NFC is enabled
1714            if (!mIsNfcEnabled) {
1715                return null;
1716            }
1717
1718            /* find the device in the hmap */
1719            device = (NativeP2pDevice) findObject(nativeHandle);
1720            if (device != null) {
1721                byte[] buff = device.getGeneralBytes();
1722                if (buff == null)
1723                    return null;
1724                return buff;
1725            }
1726            return null;
1727        }
1728
1729        @Override
1730        public int getMode(int nativeHandle) throws RemoteException {
1731            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1732
1733            NativeP2pDevice device;
1734
1735            // Check if NFC is enabled
1736            if (!mIsNfcEnabled) {
1737                return ErrorCodes.ERROR_NOT_INITIALIZED;
1738            }
1739
1740            /* find the device in the hmap */
1741            device = (NativeP2pDevice) findObject(nativeHandle);
1742            if (device != null) {
1743                return device.getMode();
1744            }
1745            return ErrorCodes.ERROR_INVALID_PARAM;
1746        }
1747
1748        @Override
1749        public byte[] transceive(int nativeHandle, byte[] data)
1750                throws RemoteException {
1751            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1752
1753            NativeP2pDevice device;
1754
1755            // Check if NFC is enabled
1756            if (!mIsNfcEnabled) {
1757                return null;
1758            }
1759
1760            /* find the device in the hmap */
1761            device = (NativeP2pDevice) findObject(nativeHandle);
1762            if (device != null) {
1763                byte[] buff = device.doTransceive(data);
1764                if (buff == null)
1765                    return null;
1766                return buff;
1767            }
1768            return null;
1769        }
1770    };
1771
1772    private INfcSecureElement mSecureElementService = new INfcSecureElement.Stub() {
1773
1774        public int openSecureElementConnection() throws RemoteException {
1775            Log.d(TAG, "openSecureElementConnection");
1776            int handle;
1777
1778            // Check if NFC is enabled
1779            if (!mIsNfcEnabled) {
1780                return 0;
1781            }
1782
1783            // Check in an open is already pending
1784            if (mOpenSmxPending) {
1785                return 0;
1786            }
1787
1788            handle = mSecureElement.doOpenSecureElementConnection();
1789
1790            if (handle == 0) {
1791                mOpenSmxPending = false;
1792            } else {
1793                mSecureElementHandle = handle;
1794
1795                /* Start timer */
1796                mTimerOpenSmx = new Timer();
1797                mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
1798
1799                /* Update state */
1800                isOpened = true;
1801                isClosed = false;
1802                mOpenSmxPending = true;
1803            }
1804
1805            return handle;
1806        }
1807
1808        public int closeSecureElementConnection(int nativeHandle)
1809                throws RemoteException {
1810
1811            // Check if NFC is enabled
1812            if (!mIsNfcEnabled) {
1813                return ErrorCodes.ERROR_NOT_INITIALIZED;
1814            }
1815
1816            // Check if the SE connection is closed
1817            if (isClosed) {
1818                return -1;
1819            }
1820
1821            // Check if the SE connection is opened
1822            if (!isOpened) {
1823                return -1;
1824            }
1825
1826            if (mSecureElement.doDisconnect(nativeHandle)) {
1827
1828                /* Stop timer */
1829                mTimerOpenSmx.cancel();
1830
1831                /* Restart polling loop for notification */
1832                mManager.enableDiscovery(DISCOVERY_MODE_READER);
1833
1834                /* Update state */
1835                isOpened = false;
1836                isClosed = true;
1837                mOpenSmxPending = false;
1838
1839                return ErrorCodes.SUCCESS;
1840            } else {
1841
1842                /* Stop timer */
1843                mTimerOpenSmx.cancel();
1844
1845                /* Restart polling loop for notification */
1846                mManager.enableDiscovery(DISCOVERY_MODE_READER);
1847
1848                /* Update state */
1849                isOpened = false;
1850                isClosed = true;
1851                mOpenSmxPending = false;
1852
1853                return ErrorCodes.ERROR_DISCONNECT;
1854            }
1855        }
1856
1857        public int[] getSecureElementTechList(int nativeHandle)
1858                throws RemoteException {
1859            // Check if NFC is enabled
1860            if (!mIsNfcEnabled) {
1861                return null;
1862            }
1863
1864            // Check if the SE connection is closed
1865            if (isClosed) {
1866                return null;
1867            }
1868
1869            // Check if the SE connection is opened
1870            if (!isOpened) {
1871                return null;
1872            }
1873
1874            int[] techList = mSecureElement.doGetTechList(nativeHandle);
1875
1876            /* Stop and Restart timer */
1877            mTimerOpenSmx.cancel();
1878            mTimerOpenSmx = new Timer();
1879            mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
1880
1881            return techList;
1882        }
1883
1884        public byte[] getSecureElementUid(int nativeHandle)
1885                throws RemoteException {
1886            byte[] uid;
1887
1888            // Check if NFC is enabled
1889            if (!mIsNfcEnabled) {
1890                return null;
1891            }
1892
1893            // Check if the SE connection is closed
1894            if (isClosed) {
1895                return null;
1896            }
1897
1898            // Check if the SE connection is opened
1899            if (!isOpened) {
1900                return null;
1901            }
1902
1903            uid = mSecureElement.doGetUid(nativeHandle);
1904
1905            /* Stop and Restart timer */
1906            mTimerOpenSmx.cancel();
1907            mTimerOpenSmx = new Timer();
1908            mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
1909
1910            return uid;
1911        }
1912
1913        public byte[] exchangeAPDU(int nativeHandle, byte[] data)
1914                throws RemoteException {
1915            byte[] response;
1916
1917            // Check if NFC is enabled
1918            if (!mIsNfcEnabled) {
1919                return null;
1920            }
1921
1922            // Check if the SE connection is closed
1923            if (isClosed) {
1924                return null;
1925            }
1926
1927            // Check if the SE connection is opened
1928            if (!isOpened) {
1929                return null;
1930            }
1931
1932            response = mSecureElement.doTransceive(nativeHandle, data);
1933
1934            /* Stop and Restart timer */
1935            mTimerOpenSmx.cancel();
1936            mTimerOpenSmx = new Timer();
1937            mTimerOpenSmx.schedule(new TimerOpenSecureElement(), 30000);
1938
1939            return response;
1940
1941        }
1942    };
1943
1944    class TimerOpenSecureElement extends TimerTask {
1945
1946        @Override
1947        public void run() {
1948            if (mSecureElementHandle != 0) {
1949                Log.d(TAG, "Open SMX timer expired");
1950                try {
1951                    mSecureElementService
1952                            .closeSecureElementConnection(mSecureElementHandle);
1953                } catch (RemoteException e) {
1954                }
1955            }
1956
1957        }
1958
1959    }
1960
1961    private boolean _enable(boolean oldEnabledState) {
1962        applyProperties();
1963
1964        boolean isSuccess = mManager.initialize();
1965        if (isSuccess) {
1966            /* Check Secure Element setting */
1967            mNfcSecureElementState = mPrefs.getBoolean(PREF_SECURE_ELEMENT_ON,
1968                    SECURE_ELEMENT_ON_DEFAULT);
1969
1970            if (mNfcSecureElementState) {
1971                int secureElementId = mPrefs.getInt(PREF_SECURE_ELEMENT_ID,
1972                        SECURE_ELEMENT_ID_DEFAULT);
1973                int[] Se_list = mManager.doGetSecureElementList();
1974                if (Se_list != null) {
1975                    for (int i = 0; i < Se_list.length; i++) {
1976                        if (Se_list[i] == secureElementId) {
1977                            mManager.doSelectSecureElement(Se_list[i]);
1978                            mSelectedSeId = Se_list[i];
1979                            break;
1980                        }
1981                    }
1982                }
1983            }
1984
1985            mIsNfcEnabled = true;
1986
1987            /* Start polling loop */
1988            maybeEnableDiscovery();
1989
1990            /* bring up the my tag server */
1991            mNdefPushServer.start();
1992
1993        } else {
1994            mIsNfcEnabled = false;
1995        }
1996
1997        updateNfcOnSetting(oldEnabledState);
1998
1999        return isSuccess;
2000    }
2001
2002    /** Enable active tag discovery if screen is on and NFC is enabled */
2003    private synchronized void maybeEnableDiscovery() {
2004        if (mScreenOn && mIsNfcEnabled) {
2005            mManager.enableDiscovery(DISCOVERY_MODE_READER);
2006        }
2007    }
2008
2009    /** Disable active tag discovery if necessary */
2010    private synchronized void maybeDisableDiscovery() {
2011        if (mIsNfcEnabled) {
2012            mManager.disableDiscovery();
2013        }
2014    }
2015
2016    private void applyProperties() {
2017        mManager.doSetProperties(PROPERTY_LLCP_LTO, mPrefs.getInt(PREF_LLCP_LTO, LLCP_LTO_DEFAULT));
2018        mManager.doSetProperties(PROPERTY_LLCP_MIU, mPrefs.getInt(PREF_LLCP_MIU, LLCP_MIU_DEFAULT));
2019        mManager.doSetProperties(PROPERTY_LLCP_WKS, mPrefs.getInt(PREF_LLCP_WKS, LLCP_WKS_DEFAULT));
2020        mManager.doSetProperties(PROPERTY_LLCP_OPT, mPrefs.getInt(PREF_LLCP_OPT, LLCP_OPT_DEFAULT));
2021        mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_A,
2022                mPrefs.getBoolean(PREF_DISCOVERY_A, DISCOVERY_A_DEFAULT) ? 1 : 0);
2023        mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_B,
2024                mPrefs.getBoolean(PREF_DISCOVERY_B, DISCOVERY_B_DEFAULT) ? 1 : 0);
2025        mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_F,
2026                mPrefs.getBoolean(PREF_DISCOVERY_F, DISCOVERY_F_DEFAULT) ? 1 : 0);
2027        mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_15693,
2028                mPrefs.getBoolean(PREF_DISCOVERY_15693, DISCOVERY_15693_DEFAULT) ? 1 : 0);
2029        mManager.doSetProperties(PROPERTY_NFC_DISCOVERY_NFCIP,
2030                mPrefs.getBoolean(PREF_DISCOVERY_NFCIP, DISCOVERY_NFCIP_DEFAULT) ? 1 : 0);
2031     }
2032
2033    private void updateNfcOnSetting(boolean oldEnabledState) {
2034        mPrefsEditor.putBoolean(PREF_NFC_ON, mIsNfcEnabled);
2035        mPrefsEditor.apply();
2036
2037        synchronized(this) {
2038            if (oldEnabledState != mIsNfcEnabled) {
2039                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGE);
2040                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2041                intent.putExtra(NfcAdapter.EXTRA_NEW_BOOLEAN_STATE, mIsNfcEnabled);
2042                mContext.sendBroadcast(intent);
2043            }
2044
2045            if (mIsNfcEnabled) {
2046
2047                Context context = getApplicationContext();
2048
2049                // Set this to null by default. If there isn't a tag on disk
2050                // or if there was an error reading the tag then this will cause
2051                // the status bar icon to be removed.
2052                NdefMessage myTag = null;
2053
2054                FileInputStream input = null;
2055
2056                try {
2057                    input = context.openFileInput(MY_TAG_FILE_NAME);
2058                    ByteArrayOutputStream bytes = new ByteArrayOutputStream();
2059
2060                    byte[] buffer = new byte[4096];
2061                    int read = 0;
2062                    while ((read = input.read(buffer)) > 0) {
2063                        bytes.write(buffer, 0, read);
2064                    }
2065
2066                    myTag = new NdefMessage(bytes.toByteArray());
2067                } catch (FileNotFoundException e) {
2068                    // Ignore.
2069                } catch (IOException e) {
2070                    Log.e(TAG, "Could not read mytag file: ", e);
2071                    context.deleteFile(MY_TAG_FILE_NAME);
2072                } catch (FormatException e) {
2073                    Log.e(TAG, "Invalid NdefMessage for mytag", e);
2074                    context.deleteFile(MY_TAG_FILE_NAME);
2075                } finally {
2076                    try {
2077                        if (input != null) {
2078                            input.close();
2079                        }
2080                    } catch (IOException e) {
2081                        // Ignore
2082                    }
2083                }
2084
2085                try {
2086                    mNfcAdapter.localSet(myTag);
2087                } catch (RemoteException e) {
2088                    // Ignore
2089                }
2090            } else {
2091                sendMessage(MSG_HIDE_MY_TAG_ICON, null);
2092            }
2093        }
2094    }
2095
2096    // Reset all internals
2097    private synchronized void reset() {
2098        // TODO: none of these appear to be synchronized but are
2099        // read/written from different threads (notably Binder threads)...
2100
2101        // Clear tables
2102        mObjectMap.clear();
2103        mSocketMap.clear();
2104
2105        // Reset variables
2106        mIsNfcEnabled = false;
2107        mSelectedSeId = 0;
2108    }
2109
2110    private synchronized Object findObject(int key) {
2111        Object device = null;
2112
2113        device = mObjectMap.get(key);
2114        if (device == null) {
2115            Log.w(TAG, "Handle not found !");
2116        }
2117
2118        return device;
2119    }
2120
2121    synchronized void registerTagObject(NativeNfcTag nativeTag) {
2122        mObjectMap.put(nativeTag.getHandle(), nativeTag);
2123    }
2124
2125    synchronized void unregisterObject(int handle) {
2126        mObjectMap.remove(handle);
2127    }
2128
2129    private synchronized Object findSocket(int key) {
2130        if (mSocketMap == null) {
2131            return null;
2132        }
2133        return mSocketMap.get(key);
2134    }
2135
2136    private void RemoveSocket(int key) {
2137        mSocketMap.remove(key);
2138    }
2139
2140    /** For use by code in this process */
2141    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength) {
2142        try {
2143            int handle = mNfcAdapter.createLlcpSocket(sap, miu, rw, linearBufferLength);
2144            if (ErrorCodes.isError(handle)) {
2145                Log.e(TAG, "unable to create socket: " + ErrorCodes.asString(handle));
2146                return null;
2147            }
2148            return new LlcpSocket(mLlcpSocket, handle);
2149        } catch (RemoteException e) {
2150            // This will never happen since the code is calling into it's own process
2151            throw new IllegalStateException("unable to talk to myself", e);
2152        }
2153    }
2154
2155    /** For use by code in this process */
2156    public LlcpServiceSocket createLlcpServiceSocket(int sap, String sn, int miu, int rw,
2157            int linearBufferLength) {
2158        try {
2159            int handle = mNfcAdapter.createLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength);
2160            if (ErrorCodes.isError(handle)) {
2161                Log.e(TAG, "unable to create socket: " + ErrorCodes.asString(handle));
2162                return null;
2163            }
2164            return new LlcpServiceSocket(mLlcpServerSocketService, mLlcpSocket, handle);
2165        } catch (RemoteException e) {
2166            // This will never happen since the code is calling into it's own process
2167            throw new IllegalStateException("unable to talk to myself", e);
2168        }
2169    }
2170
2171    private void activateLlcpLink() {
2172        /* Broadcast Intent Link LLCP activated */
2173        Intent LlcpLinkIntent = new Intent();
2174        LlcpLinkIntent.setAction(NfcAdapter.ACTION_LLCP_LINK_STATE_CHANGED);
2175
2176        LlcpLinkIntent.putExtra(NfcAdapter.EXTRA_LLCP_LINK_STATE_CHANGED,
2177                NfcAdapter.LLCP_LINK_STATE_ACTIVATED);
2178
2179        if (DBG) Log.d(TAG, "Broadcasting LLCP activation");
2180        mContext.sendOrderedBroadcast(LlcpLinkIntent, NFC_PERM);
2181    }
2182
2183    public void sendMockNdefTag(NdefMessage msg) {
2184        sendMessage(MSG_MOCK_NDEF, msg);
2185    }
2186
2187    void sendMessage(int what, Object obj) {
2188        Message msg = mHandler.obtainMessage();
2189        msg.what = what;
2190        msg.obj = obj;
2191        mHandler.sendMessage(msg);
2192    }
2193
2194    final class NfcServiceHandler extends Handler {
2195
2196        public NdefMessage[] findAndReadNdef(NativeNfcTag nativeTag) {
2197            // Try to find NDEF on any of the technologies.
2198            int[] technologies = nativeTag.getTechList();
2199            int[] handles = nativeTag.getHandleList();
2200            int techIndex = 0;
2201            int lastHandleScanned = 0;
2202            boolean ndefFoundAndConnected = false;
2203            NdefMessage[] ndefMsgs = null;
2204            boolean foundFormattable = false;
2205
2206            while ((!ndefFoundAndConnected) && (techIndex < technologies.length)) {
2207                if (handles[techIndex] != lastHandleScanned) {
2208                    // We haven't seen this handle yet, connect and checkndef
2209                    if (nativeTag.connect(technologies[techIndex])) {
2210                        // Check if this type is NDEF formatable
2211                        if (!foundFormattable && (nativeTag.isNdefFormatable())) {
2212                            foundFormattable = true;
2213                            nativeTag.addNdefFormatableTechnology(
2214                                    nativeTag.getConnectedHandle(),
2215                                    nativeTag.getConnectedTechnology());
2216                        } // else not formatable
2217                        int[] ndefinfo = new int[2];
2218                        if (nativeTag.checkNdef(ndefinfo)) {
2219                            ndefFoundAndConnected = true;
2220                            boolean generateEmptyNdef = false;
2221
2222                            int supportedNdefLength = ndefinfo[0];
2223                            int cardState = ndefinfo[1];
2224                            byte[] buff = nativeTag.read();
2225                            if (buff != null) {
2226                                ndefMsgs = new NdefMessage[1];
2227                                try {
2228                                    ndefMsgs[0] = new NdefMessage(buff);
2229                                    nativeTag.addNdefTechnology(ndefMsgs[0],
2230                                            nativeTag.getConnectedHandle(),
2231                                            nativeTag.getConnectedLibNfcType(),
2232                                            nativeTag.getConnectedTechnology(),
2233                                            supportedNdefLength, cardState);
2234                                    nativeTag.reconnect();
2235                                } catch (FormatException e) {
2236                                   // Create an intent anyway, without NDEF messages
2237                                   generateEmptyNdef = true;
2238                                }
2239                            } else {
2240                                generateEmptyNdef = true;
2241                            }
2242
2243                           if (generateEmptyNdef) {
2244                               ndefMsgs = new NdefMessage[] { };
2245                               nativeTag.addNdefTechnology(null,
2246                                       nativeTag.getConnectedHandle(),
2247                                       nativeTag.getConnectedLibNfcType(),
2248                                       nativeTag.getConnectedTechnology(),
2249                                       supportedNdefLength, cardState);
2250                               nativeTag.reconnect();
2251                           }
2252                        } // else, no NDEF on this tech, continue loop
2253                    } else {
2254                        // Connect failed, tag maybe lost. Try next handle
2255                        // anyway.
2256                    }
2257                }
2258                lastHandleScanned = handles[techIndex];
2259                techIndex++;
2260            }
2261
2262            return ndefMsgs;
2263        }
2264
2265        @Override
2266        public void handleMessage(Message msg) {
2267           switch (msg.what) {
2268           case MSG_MOCK_NDEF: {
2269               NdefMessage ndefMsg = (NdefMessage) msg.obj;
2270               Tag tag = Tag.createMockTag(new byte[] { 0x00 },
2271                       new int[] { },
2272                       new Bundle[] { });
2273               Log.d(TAG, "mock NDEF tag, starting corresponding activity");
2274               Log.d(TAG, tag.toString());
2275               dispatchTag(tag, new NdefMessage[] { ndefMsg });
2276               break;
2277           }
2278
2279           case MSG_NDEF_TAG:
2280               if (DBG) Log.d(TAG, "Tag detected, notifying applications");
2281               NativeNfcTag nativeTag = (NativeNfcTag) msg.obj;
2282               NdefMessage[] ndefMsgs = findAndReadNdef(nativeTag);
2283
2284               if (ndefMsgs != null) {
2285                   nativeTag.startPresenceChecking();
2286                   dispatchNativeTag(nativeTag, ndefMsgs);
2287               } else {
2288                   // No ndef found or connect failed, just try to reconnect and dispatch
2289                   if (nativeTag.reconnect()) {
2290                       nativeTag.startPresenceChecking();
2291                       dispatchNativeTag(nativeTag, null);
2292                   } else {
2293                       Log.w(TAG, "Failed to connect to tag");
2294                       nativeTag.disconnect();
2295                   }
2296               }
2297               break;
2298
2299           case MSG_CARD_EMULATION:
2300               if (DBG) Log.d(TAG, "Card Emulation message");
2301               byte[] aid = (byte[]) msg.obj;
2302               /* Send broadcast ordered */
2303               Intent TransactionIntent = new Intent();
2304               TransactionIntent.setAction(NfcAdapter.ACTION_TRANSACTION_DETECTED);
2305               TransactionIntent.putExtra(NfcAdapter.EXTRA_AID, aid);
2306               if (DBG) Log.d(TAG, "Broadcasting Card Emulation event");
2307               mContext.sendOrderedBroadcast(TransactionIntent, NFC_PERM);
2308               break;
2309
2310           case MSG_LLCP_LINK_ACTIVATION:
2311               NativeP2pDevice device = (NativeP2pDevice) msg.obj;
2312
2313               Log.d(TAG, "LLCP Activation message");
2314
2315               if (device.getMode() == NativeP2pDevice.MODE_P2P_TARGET) {
2316                   if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
2317                   if (device.doConnect()) {
2318                       /* Check Llcp compliancy */
2319                       if (mManager.doCheckLlcp()) {
2320                           /* Activate Llcp Link */
2321                           if (mManager.doActivateLlcp()) {
2322                               if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
2323                               activateLlcpLink();
2324                           } else {
2325                               /* should not happen */
2326                               Log.w(TAG, "Initiator Activate LLCP NOK. Disconnect.");
2327                               device.doDisconnect();
2328                           }
2329
2330                       } else {
2331                           if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
2332                           device.doDisconnect();
2333                       }
2334                   } else {
2335                       if (DBG) Log.d(TAG, "Cannot connect remote Target. Restart polling loop.");
2336                       device.doDisconnect();
2337                   }
2338
2339               } else if (device.getMode() == NativeP2pDevice.MODE_P2P_INITIATOR) {
2340                   if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
2341                   /* Check Llcp compliancy */
2342                   if (mManager.doCheckLlcp()) {
2343                       /* Activate Llcp Link */
2344                       if (mManager.doActivateLlcp()) {
2345                           if (DBG) Log.d(TAG, "Target Activate LLCP OK");
2346                           activateLlcpLink();
2347                      }
2348                   } else {
2349                       Log.w(TAG, "checkLlcp failed");
2350                   }
2351               }
2352               break;
2353
2354           case MSG_LLCP_LINK_DEACTIVATED:
2355               device = (NativeP2pDevice) msg.obj;
2356
2357               Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
2358               if (device.getMode() == NativeP2pDevice.MODE_P2P_TARGET) {
2359                   if (DBG) Log.d(TAG, "disconnecting from target");
2360                   /* Restart polling loop */
2361                   device.doDisconnect();
2362               } else {
2363                   if (DBG) Log.d(TAG, "not disconnecting from initiator");
2364               }
2365
2366               /* Broadcast Intent Link LLCP activated */
2367               Intent LlcpLinkIntent = new Intent();
2368               LlcpLinkIntent.setAction(NfcAdapter.ACTION_LLCP_LINK_STATE_CHANGED);
2369               LlcpLinkIntent.putExtra(NfcAdapter.EXTRA_LLCP_LINK_STATE_CHANGED,
2370                       NfcAdapter.LLCP_LINK_STATE_DEACTIVATED);
2371               if (DBG) Log.d(TAG, "Broadcasting LLCP deactivation");
2372               mContext.sendOrderedBroadcast(LlcpLinkIntent, NFC_PERM);
2373               break;
2374
2375           case MSG_TARGET_DESELECTED:
2376               /* Broadcast Intent Target Deselected */
2377               if (DBG) Log.d(TAG, "Target Deselected");
2378               Intent TargetDeselectedIntent = new Intent();
2379               TargetDeselectedIntent.setAction(mManager.INTERNAL_TARGET_DESELECTED_ACTION);
2380               if (DBG) Log.d(TAG, "Broadcasting Intent");
2381               mContext.sendOrderedBroadcast(TargetDeselectedIntent, NFC_PERM);
2382               break;
2383
2384           case MSG_SHOW_MY_TAG_ICON: {
2385               StatusBarManager sb = (StatusBarManager) getSystemService(
2386                       Context.STATUS_BAR_SERVICE);
2387               sb.setIcon("nfc", R.drawable.stat_sys_nfc, 0);
2388               break;
2389           }
2390
2391           case MSG_HIDE_MY_TAG_ICON: {
2392               StatusBarManager sb = (StatusBarManager) getSystemService(
2393                       Context.STATUS_BAR_SERVICE);
2394               sb.removeIcon("nfc");
2395               break;
2396           }
2397
2398           case MSG_SE_FIELD_ACTIVATED:{
2399               if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
2400               Intent eventFieldOnIntent = new Intent();
2401               eventFieldOnIntent.setAction(NfcAdapter.ACTION_RF_FIELD_ON_DETECTED);
2402               if (DBG) Log.d(TAG, "Broadcasting Intent");
2403               mContext.sendBroadcast(eventFieldOnIntent, NFC_PERM);
2404               break;
2405           }
2406
2407           case MSG_SE_FIELD_DEACTIVATED:{
2408               if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
2409               Intent eventFieldOffIntent = new Intent();
2410               eventFieldOffIntent.setAction(NfcAdapter.ACTION_RF_FIELD_OFF_DETECTED);
2411               if (DBG) Log.d(TAG, "Broadcasting Intent");
2412               mContext.sendBroadcast(eventFieldOffIntent, NFC_PERM);
2413               break;
2414           }
2415
2416           default:
2417               Log.e(TAG, "Unknown message received");
2418               break;
2419           }
2420        }
2421
2422        private Intent buildTagIntent(Tag tag, NdefMessage[] msgs, String action) {
2423            Intent intent = new Intent(action);
2424            intent.putExtra(NfcAdapter.EXTRA_TAG, tag);
2425            intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId());
2426            intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, msgs);
2427            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2428            return intent;
2429        }
2430
2431        private void dispatchNativeTag(NativeNfcTag nativeTag, NdefMessage[] msgs) {
2432            Tag tag = new Tag(nativeTag.getUid(), nativeTag.getTechList(),
2433                    nativeTag.getTechExtras(), nativeTag.getHandle());
2434            if (dispatchTag(tag, msgs)) {
2435                registerTagObject(nativeTag);
2436            } else {
2437                nativeTag.disconnect();
2438            }
2439        }
2440
2441        public byte[] concat(byte[]... arrays) {
2442            int length = 0;
2443            for (byte[] array : arrays) {
2444                length += array.length;
2445            }
2446            byte[] result = new byte[length];
2447            int pos = 0;
2448            for (byte[] array : arrays) {
2449                System.arraycopy(array, 0, result, pos, array.length);
2450                pos += array.length;
2451            }
2452            return result;
2453        }
2454
2455        private Uri parseWellKnownUriRecord(NdefRecord record) {
2456            byte[] payload = record.getPayload();
2457
2458            /*
2459             * payload[0] contains the URI Identifier Code, per the
2460             * NFC Forum "URI Record Type Definition" section 3.2.2.
2461             *
2462             * payload[1]...payload[payload.length - 1] contains the rest of
2463             * the URI.
2464             */
2465            String prefix = URI_PREFIX_MAP[(payload[0] & 0xff)];
2466            byte[] fullUri = concat(prefix.getBytes(Charsets.UTF_8),
2467                    Arrays.copyOfRange(payload, 1, payload.length));
2468            return Uri.parse(new String(fullUri, Charsets.UTF_8));
2469        }
2470
2471        private boolean setTypeOrDataFromNdef(Intent intent, NdefRecord record) {
2472            short tnf = record.getTnf();
2473            byte[] type = record.getType();
2474            switch (tnf) {
2475                case NdefRecord.TNF_MIME_MEDIA: {
2476                    intent.setType(new String(type, Charsets.US_ASCII));
2477                    return true;
2478                }
2479                case NdefRecord.TNF_ABSOLUTE_URI: {
2480                    intent.setData(Uri.parse(new String(type, Charsets.UTF_8)));
2481                    return true;
2482                }
2483                case NdefRecord.TNF_WELL_KNOWN: {
2484                    if (Arrays.equals(type, NdefRecord.RTD_TEXT)) {
2485                        intent.setType("text/plain");
2486                        return true;
2487                    } else if (Arrays.equals(type, NdefRecord.RTD_SMART_POSTER)) {
2488                        // Parse the smart poster looking for the URI
2489                        try {
2490                            NdefMessage msg = new NdefMessage(record.getPayload());
2491                            for (NdefRecord subRecord : msg.getRecords()) {
2492                                if (subRecord.getTnf() == NdefRecord.TNF_WELL_KNOWN
2493                                        && Arrays.equals(subRecord.getType(), NdefRecord.RTD_URI)) {
2494                                    intent.setData(parseWellKnownUriRecord(subRecord));
2495                                    return true;
2496                                }
2497                            }
2498                        } catch (FormatException e) {
2499                            return false;
2500                        }
2501                    } else if (Arrays.equals(type, NdefRecord.RTD_URI)) {
2502                        intent.setData(parseWellKnownUriRecord(record));
2503                        return true;
2504                    }
2505                    return false;
2506                }
2507            }
2508            return false;
2509        }
2510
2511        private Uri buildTechListUri(Tag tag) {
2512            int[] techList = tag.getTechnologyList();
2513            Arrays.sort(techList);
2514            Uri.Builder builder = new Uri.Builder();
2515            builder.scheme("vnd.android.nfc").authority("tag");
2516            for (int tech : techList) {
2517                builder.appendPath(Integer.toString(tech));
2518            }
2519            builder.appendPath("");
2520            return builder.build();
2521        }
2522
2523        /** Returns false if no activities were found to dispatch to */
2524        private boolean dispatchTag(Tag tag, NdefMessage[] msgs) {
2525            if (DBG) {
2526                Log.d(TAG, "Dispatching tag");
2527                Log.d(TAG, tag.toString());
2528            }
2529
2530            IntentFilter[] overrideFilters;
2531            PendingIntent overrideIntent;
2532            synchronized (mNfcAdapter) {
2533                overrideFilters = mDispatchOverrideFilters;
2534                overrideIntent = mDispatchOverrideIntent;
2535            }
2536
2537            // First look for dispatch overrides
2538            if (overrideFilters != null && overrideIntent != null) {
2539                if (DBG) Log.d(TAG, "Attempting to dispatch tag with override");
2540                try {
2541                    if (dispatchTagInternal(tag, msgs, overrideIntent, overrideFilters)) {
2542                        if (DBG) Log.d(TAG, "Dispatched to override");
2543                        return true;
2544                    }
2545                    Log.w(TAG, "Dispatch override registered, but no filters matched");
2546                } catch (CanceledException e) {
2547                    Log.w(TAG, "Dispatch overrides pending intent was canceled");
2548                    synchronized (mNfcAdapter) {
2549                        mDispatchOverrideFilters = null;
2550                        mDispatchOverrideIntent = null;
2551                    }
2552                }
2553            }
2554
2555            // Try a standard dispatch
2556            try {
2557                return dispatchTagInternal(tag, msgs, null, null);
2558            } catch (CanceledException e) {
2559                Log.e(TAG, "CanceledException unexpected here", e);
2560                return false;
2561            }
2562        }
2563
2564        // Dispatch to either an override pending intent or a standard startActivity()
2565        private boolean dispatchTagInternal(Tag tag, NdefMessage[] msgs,
2566                PendingIntent overrideIntent, IntentFilter[] overrideFilters)
2567                throws CanceledException{
2568            Intent intent;
2569            if (msgs != null && msgs.length > 0) {
2570                NdefMessage msg = msgs[0];
2571                NdefRecord[] records = msg.getRecords();
2572                if (records.length > 0) {
2573                    // Found valid NDEF data, try to dispatch that first
2574                    NdefRecord record = records[0];
2575
2576                    intent = buildTagIntent(tag, msgs, NfcAdapter.ACTION_NDEF_DISCOVERED);
2577                    setTypeOrDataFromNdef(intent, record);
2578
2579                    if (startDispatchActivity(intent, overrideIntent, overrideFilters)) {
2580                        // If an activity is found then skip further dispatching
2581                        return true;
2582                    } else {
2583                        if (DBG) Log.d(TAG, "No activities for NDEF handling of " + intent);
2584                    }
2585                }
2586            }
2587
2588            // Try the technology specific dispatch
2589            intent = buildTagIntent(tag, msgs, NfcAdapter.ACTION_TECHNOLOGY_DISCOVERED);
2590            intent.setData(buildTechListUri(tag));
2591            if (startDispatchActivity(intent, overrideIntent, overrideFilters)) {
2592                return true;
2593            } else {
2594                if (DBG) Log.w(TAG, "No activities for technology handling of " + intent);
2595            }
2596
2597            // Try the generic intent
2598            intent = buildTagIntent(tag, msgs, NfcAdapter.ACTION_TAG_DISCOVERED);
2599            if (startDispatchActivity(intent, overrideIntent, overrideFilters)) {
2600                return true;
2601            } else {
2602                Log.e(TAG, "No tag fallback activity found for " + intent);
2603                return false;
2604            }
2605        }
2606
2607        private boolean startDispatchActivity(Intent intent, PendingIntent overrideIntent,
2608                IntentFilter[] overrideFilters) throws CanceledException {
2609            if (overrideIntent != null) {
2610                for (IntentFilter filter : overrideFilters) {
2611                    if (filter.match(mContext.getContentResolver(), intent, false, TAG) >= 0) {
2612                        Log.i(TAG, "Dispatching to override intent " + overrideIntent);
2613                        overrideIntent.send(mContext, Activity.RESULT_OK, intent);
2614                        return true;
2615                    }
2616                }
2617                return false;
2618            } else {
2619                try {
2620                    // If the current app called stopAppSwitches() then our startActivity()
2621                    // can be delayed for several seconds. This happens with the default home
2622                    // screen. As a system service we can override this behavior with
2623                    // resumeAppSwitches()
2624                    mIActivityManager.resumeAppSwitches();
2625                } catch (RemoteException e) { }
2626                try {
2627                    mContext.startActivity(intent);
2628                    return true;
2629                } catch (ActivityNotFoundException e) {
2630                    return false;
2631                }
2632            }
2633        }
2634    }
2635
2636    private NfcServiceHandler mHandler = new NfcServiceHandler();
2637
2638    private class EnableDisableDiscoveryTask extends AsyncTask<Boolean, Void, Void> {
2639        @Override
2640        protected Void doInBackground(Boolean... enable) {
2641            if (enable != null && enable.length > 0 && enable[0]) {
2642                synchronized (NfcService.this) {
2643                    mScreenOn = true;
2644                    maybeEnableDiscovery();
2645                }
2646            } else {
2647                mWakeLock.acquire();
2648                synchronized (NfcService.this) {
2649                    mScreenOn = false;
2650                    maybeDisableDiscovery();
2651                }
2652                mWakeLock.release();
2653            }
2654            return null;
2655        }
2656    }
2657
2658    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2659        @Override
2660        public void onReceive(Context context, Intent intent) {
2661            if (intent.getAction().equals(
2662                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
2663                if (DBG) Log.d(TAG, "INERNAL_TARGET_DESELECTED_ACTION");
2664
2665                /* Restart polling loop for notification */
2666                maybeEnableDiscovery();
2667
2668            } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
2669                // Perform discovery enable in thread to protect against ANR when the
2670                // NFC stack wedges. This is *not* the correct way to fix this issue -
2671                // configuration of the local NFC adapter should be very quick and should
2672                // be safe on the main thread, and the NFC stack should not wedge.
2673                new EnableDisableDiscoveryTask().execute(new Boolean(true));
2674            } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
2675                // Perform discovery disable in thread to protect against ANR when the
2676                // NFC stack wedges. This is *not* the correct way to fix this issue -
2677                // configuration of the local NFC adapter should be very quick and should
2678                // be safe on the main thread, and the NFC stack should not wedge.
2679                new EnableDisableDiscoveryTask().execute(new Boolean(false));
2680            }
2681        }
2682    };
2683}
2684