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