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