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