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