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 android.app.ActivityManager;
20import android.app.Application;
21import android.app.KeyguardManager;
22import android.app.PendingIntent;
23import android.content.BroadcastReceiver;
24import android.content.ComponentName;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.SharedPreferences;
30import android.content.pm.PackageInfo;
31import android.content.pm.PackageManager;
32import android.content.pm.UserInfo;
33import android.content.res.Resources.NotFoundException;
34import android.media.AudioManager;
35import android.media.SoundPool;
36import android.nfc.BeamShareData;
37import android.nfc.ErrorCodes;
38import android.nfc.FormatException;
39import android.nfc.IAppCallback;
40import android.nfc.INfcAdapter;
41import android.nfc.INfcAdapterExtras;
42import android.nfc.INfcCardEmulation;
43import android.nfc.INfcTag;
44import android.nfc.INfcUnlockHandler;
45import android.nfc.NdefMessage;
46import android.nfc.NfcAdapter;
47import android.nfc.Tag;
48import android.nfc.TechListParcel;
49import android.nfc.TransceiveResult;
50import android.nfc.tech.Ndef;
51import android.nfc.tech.TagTechnology;
52import android.os.AsyncTask;
53import android.os.Binder;
54import android.os.Build;
55import android.os.Bundle;
56import android.os.Handler;
57import android.os.IBinder;
58import android.os.Message;
59import android.os.PowerManager;
60import android.os.Process;
61import android.os.RemoteException;
62import android.os.ServiceManager;
63import android.os.UserHandle;
64import android.os.UserManager;
65import android.provider.Settings;
66import android.util.Log;
67
68import com.android.nfc.DeviceHost.DeviceHostListener;
69import com.android.nfc.DeviceHost.LlcpConnectionlessSocket;
70import com.android.nfc.DeviceHost.LlcpServerSocket;
71import com.android.nfc.DeviceHost.LlcpSocket;
72import com.android.nfc.DeviceHost.NfcDepEndpoint;
73import com.android.nfc.DeviceHost.TagEndpoint;
74import com.android.nfc.cardemulation.CardEmulationManager;
75import com.android.nfc.dhimpl.NativeNfcManager;
76import com.android.nfc.handover.HandoverManager;
77
78import java.io.FileDescriptor;
79import java.io.PrintWriter;
80import java.util.Arrays;
81import java.util.HashMap;
82import java.util.List;
83import java.util.Map;
84import java.util.NoSuchElementException;
85
86public class NfcService implements DeviceHostListener {
87    static final boolean DBG = false;
88    static final String TAG = "NfcService";
89
90    public static final String SERVICE_NAME = "nfc";
91
92    public static final String PREF = "NfcServicePrefs";
93
94    static final String PREF_NFC_ON = "nfc_on";
95    static final boolean NFC_ON_DEFAULT = true;
96    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
97    static final boolean NDEF_PUSH_ON_DEFAULT = true;
98    static final String PREF_FIRST_BEAM = "first_beam";
99    static final String PREF_FIRST_BOOT = "first_boot";
100    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
101
102    static final int MSG_NDEF_TAG = 0;
103    static final int MSG_LLCP_LINK_ACTIVATION = 1;
104    static final int MSG_LLCP_LINK_DEACTIVATED = 2;
105    static final int MSG_MOCK_NDEF = 3;
106    static final int MSG_LLCP_LINK_FIRST_PACKET = 4;
107    static final int MSG_ROUTE_AID = 5;
108    static final int MSG_UNROUTE_AID = 6;
109    static final int MSG_COMMIT_ROUTING = 7;
110    static final int MSG_INVOKE_BEAM = 8;
111    static final int MSG_RF_FIELD_ACTIVATED = 9;
112    static final int MSG_RF_FIELD_DEACTIVATED = 10;
113    static final int MSG_RESUME_POLLING = 11;
114
115    static final long MAX_POLLING_PAUSE_TIMEOUT = 40000;
116
117    static final int TASK_ENABLE = 1;
118    static final int TASK_DISABLE = 2;
119    static final int TASK_BOOT = 3;
120
121    // Polling technology masks
122    static final int NFC_POLL_A = 0x01;
123    static final int NFC_POLL_B = 0x02;
124    static final int NFC_POLL_F = 0x04;
125    static final int NFC_POLL_ISO15693 = 0x08;
126    static final int NFC_POLL_B_PRIME = 0x10;
127    static final int NFC_POLL_KOVIO = 0x20;
128
129    // minimum screen state that enables NFC polling
130    static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
131
132    // Time to wait for NFC controller to initialize before watchdog
133    // goes off. This time is chosen large, because firmware download
134    // may be a part of initialization.
135    static final int INIT_WATCHDOG_MS = 90000;
136
137    // Time to wait for routing to be applied before watchdog
138    // goes off
139    static final int ROUTING_WATCHDOG_MS = 10000;
140
141    // Default delay used for presence checks
142    static final int DEFAULT_PRESENCE_CHECK_DELAY = 125;
143
144    // The amount of time we wait before manually launching
145    // the Beam animation when called through the share menu.
146    static final int INVOKE_BEAM_DELAY_MS = 1000;
147
148    // RF field events as defined in NFC extras
149    public static final String ACTION_RF_FIELD_ON_DETECTED =
150            "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
151    public static final String ACTION_RF_FIELD_OFF_DETECTED =
152            "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
153
154    // for use with playSound()
155    public static final int SOUND_START = 0;
156    public static final int SOUND_END = 1;
157    public static final int SOUND_ERROR = 2;
158
159    public static final String ACTION_LLCP_UP =
160            "com.android.nfc.action.LLCP_UP";
161
162    public static final String ACTION_LLCP_DOWN =
163            "com.android.nfc.action.LLCP_DOWN";
164
165    // Timeout to re-apply routing if a tag was present and we postponed it
166    private static final int APPLY_ROUTING_RETRY_TIMEOUT_MS = 5000;
167
168    private final UserManager mUserManager;
169
170    // NFC Execution Environment
171    // fields below are protected by this
172    private final ReaderModeDeathRecipient mReaderModeDeathRecipient =
173            new ReaderModeDeathRecipient();
174    private final NfcUnlockManager mNfcUnlockManager;
175
176    private final NfceeAccessControl mNfceeAccessControl;
177
178    List<PackageInfo> mInstalledPackages; // cached version of installed packages
179
180    // fields below are used in multiple threads and protected by synchronized(this)
181    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
182    int mScreenState;
183    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
184    boolean mIsNdefPushEnabled;
185    NfcDiscoveryParameters mCurrentDiscoveryParameters =
186            NfcDiscoveryParameters.getNfcOffParameters();
187
188    ReaderModeParams mReaderModeParams;
189
190    // mState is protected by this, however it is only modified in onCreate()
191    // and the default AsyncTask thread so it is read unprotected from that
192    // thread
193    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
194    // fields below are final after onCreate()
195    Context mContext;
196    private DeviceHost mDeviceHost;
197    private SharedPreferences mPrefs;
198    private SharedPreferences.Editor mPrefsEditor;
199    private PowerManager.WakeLock mRoutingWakeLock;
200
201    int mStartSound;
202    int mEndSound;
203    int mErrorSound;
204    SoundPool mSoundPool; // playback synchronized on this
205    P2pLinkManager mP2pLinkManager;
206    TagService mNfcTagService;
207    NfcAdapterService mNfcAdapter;
208    boolean mIsAirplaneSensitive;
209    boolean mIsAirplaneToggleable;
210    boolean mIsDebugBuild;
211    boolean mIsHceCapable;
212    boolean mPollingPaused;
213
214    private NfcDispatcher mNfcDispatcher;
215    private PowerManager mPowerManager;
216    private KeyguardManager mKeyguard;
217    private HandoverManager mHandoverManager;
218    private ContentResolver mContentResolver;
219    private CardEmulationManager mCardEmulationManager;
220
221    private ScreenStateHelper mScreenStateHelper;
222    private ForegroundUtils mForegroundUtils;
223
224    private int mUserId;
225    private static NfcService sService;
226
227    public static NfcService getInstance() {
228        return sService;
229    }
230
231    @Override
232    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
233        sendMessage(NfcService.MSG_NDEF_TAG, tag);
234    }
235
236    /**
237     * Notifies transaction
238     */
239    @Override
240    public void onHostCardEmulationActivated() {
241        if (mCardEmulationManager != null) {
242            mCardEmulationManager.onHostCardEmulationActivated();
243        }
244    }
245
246    @Override
247    public void onHostCardEmulationData(byte[] data) {
248        if (mCardEmulationManager != null) {
249            mCardEmulationManager.onHostCardEmulationData(data);
250        }
251    }
252
253    @Override
254    public void onHostCardEmulationDeactivated() {
255        if (mCardEmulationManager != null) {
256            mCardEmulationManager.onHostCardEmulationDeactivated();
257        }
258    }
259
260    /**
261     * Notifies P2P Device detected, to activate LLCP link
262     */
263    @Override
264    public void onLlcpLinkActivated(NfcDepEndpoint device) {
265        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
266    }
267
268    /**
269     * Notifies P2P Device detected, to activate LLCP link
270     */
271    @Override
272    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
273        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
274    }
275
276    /**
277     * Notifies P2P Device detected, first packet received over LLCP link
278     */
279    @Override
280    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
281        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
282    }
283
284    @Override
285    public void onRemoteFieldActivated() {
286        sendMessage(NfcService.MSG_RF_FIELD_ACTIVATED, null);
287    }
288
289    public void onRemoteFieldDeactivated() {
290        sendMessage(NfcService.MSG_RF_FIELD_DEACTIVATED, null);
291    }
292
293    final class ReaderModeParams {
294        public int flags;
295        public IAppCallback callback;
296        public int presenceCheckDelay;
297    }
298
299    public NfcService(Application nfcApplication) {
300        mUserId = ActivityManager.getCurrentUser();
301        mContext = nfcApplication;
302
303        mNfcTagService = new TagService();
304        mNfcAdapter = new NfcAdapterService();
305        Log.i(TAG, "Starting NFC service");
306
307        sService = this;
308
309        mScreenStateHelper = new ScreenStateHelper(mContext);
310        mContentResolver = mContext.getContentResolver();
311        mDeviceHost = new NativeNfcManager(mContext, this);
312
313        mNfcUnlockManager = NfcUnlockManager.getInstance();
314
315        mHandoverManager = new HandoverManager(mContext);
316        boolean isNfcProvisioningEnabled = false;
317        try {
318            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
319                    R.bool.enable_nfc_provisioning);
320        } catch (NotFoundException e) {
321        }
322
323        if (isNfcProvisioningEnabled) {
324            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
325                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
326        } else {
327            mInProvisionMode = false;
328        }
329
330        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
331        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
332                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
333
334        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
335        mPrefsEditor = mPrefs.edit();
336
337        mNfceeAccessControl = new NfceeAccessControl(mContext);
338
339        mState = NfcAdapter.STATE_OFF;
340        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
341        setBeamShareActivityState(mIsNdefPushEnabled);
342
343        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
344
345        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
346
347        mRoutingWakeLock = mPowerManager.newWakeLock(
348                PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
349
350        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
351        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
352
353        mScreenState = mScreenStateHelper.checkScreenState();
354
355        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
356
357        // Intents for all users
358        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
359        filter.addAction(Intent.ACTION_SCREEN_ON);
360        filter.addAction(Intent.ACTION_USER_PRESENT);
361        filter.addAction(Intent.ACTION_USER_SWITCHED);
362        registerForAirplaneMode(filter);
363        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
364
365        IntentFilter ownerFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
366        ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
367        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
368
369        ownerFilter = new IntentFilter();
370        ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
371        ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
372        ownerFilter.addDataScheme("package");
373        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
374
375        updatePackageCache();
376
377        PackageManager pm = mContext.getPackageManager();
378        mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
379        if (mIsHceCapable) {
380            mCardEmulationManager = new CardEmulationManager(mContext);
381        }
382        mForegroundUtils = ForegroundUtils.getInstance();
383        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
384    }
385
386    void initSoundPool() {
387        synchronized (this) {
388            if (mSoundPool == null) {
389                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
390                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
391                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
392                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
393            }
394        }
395    }
396
397    void releaseSoundPool() {
398        synchronized (this) {
399            if (mSoundPool != null) {
400                mSoundPool.release();
401                mSoundPool = null;
402            }
403        }
404    }
405
406    void registerForAirplaneMode(IntentFilter filter) {
407        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
408                Settings.Global.AIRPLANE_MODE_RADIOS);
409        final String toggleableRadios = Settings.System.getString(mContentResolver,
410                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
411
412        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
413                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
414        mIsAirplaneToggleable = toggleableRadios == null ? false :
415                toggleableRadios.contains(Settings.Global.RADIO_NFC);
416
417        if (mIsAirplaneSensitive) {
418            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
419        }
420    }
421
422    void updatePackageCache() {
423        PackageManager pm = mContext.getPackageManager();
424        List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
425        synchronized (this) {
426            mInstalledPackages = packages;
427        }
428    }
429
430    /**
431     * Manages tasks that involve turning on/off the NFC controller.
432     * <p/>
433     * <p>All work that might turn the NFC adapter on or off must be done
434     * through this task, to keep the handling of mState simple.
435     * In other words, mState is only modified in these tasks (and we
436     * don't need a lock to read it in these tasks).
437     * <p/>
438     * <p>These tasks are all done on the same AsyncTask background
439     * thread, so they are serialized. Each task may temporarily transition
440     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
441     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
442     * of starting in either STATE_OFF or STATE_ON, without needing to hold
443     * NfcService.this for the entire task.
444     * <p/>
445     * <p>AsyncTask's are also implicitly queued. This is useful for corner
446     * cases like turning airplane mode on while TASK_ENABLE is in progress.
447     * The TASK_DISABLE triggered by airplane mode will be correctly executed
448     * immediately after TASK_ENABLE is complete. This seems like the most sane
449     * way to deal with these situations.
450     * <p/>
451     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
452     * preferences
453     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
454     * preferences
455     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
456     */
457    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
458        @Override
459        protected Void doInBackground(Integer... params) {
460            // Sanity check mState
461            switch (mState) {
462                case NfcAdapter.STATE_TURNING_OFF:
463                case NfcAdapter.STATE_TURNING_ON:
464                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
465                            mState);
466                    return null;
467            }
468
469            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
470             * override with the default. THREAD_PRIORITY_BACKGROUND causes
471             * us to service software I2C too slow for firmware download
472             * with the NXP PN544.
473             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
474             * problem only occurs on I2C platforms using PN544
475             */
476            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
477
478            switch (params[0].intValue()) {
479                case TASK_ENABLE:
480                    enableInternal();
481                    break;
482                case TASK_DISABLE:
483                    disableInternal();
484                    break;
485                case TASK_BOOT:
486                    Log.d(TAG, "checking on firmware download");
487                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
488                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
489                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
490                        Log.d(TAG, "NFC is on. Doing normal stuff");
491                        enableInternal();
492                    } else {
493                        Log.d(TAG, "NFC is off.  Checking firmware version");
494                        mDeviceHost.checkFirmware();
495                    }
496                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
497                        Log.i(TAG, "First Boot");
498                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
499                        mPrefsEditor.apply();
500                    }
501                    break;
502            }
503
504            // Restore default AsyncTask priority
505            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
506            return null;
507        }
508
509        /**
510         * Enable NFC adapter functions.
511         * Does not toggle preferences.
512         */
513        boolean enableInternal() {
514            if (mState == NfcAdapter.STATE_ON) {
515                return true;
516            }
517            Log.i(TAG, "Enabling NFC");
518            updateState(NfcAdapter.STATE_TURNING_ON);
519
520            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
521            watchDog.start();
522            try {
523                mRoutingWakeLock.acquire();
524                try {
525                    if (!mDeviceHost.initialize()) {
526                        Log.w(TAG, "Error enabling NFC");
527                        updateState(NfcAdapter.STATE_OFF);
528                        return false;
529                    }
530                } finally {
531                    mRoutingWakeLock.release();
532                }
533            } finally {
534                watchDog.cancel();
535            }
536
537            if (mIsHceCapable) {
538                // Generate the initial card emulation routing table
539                mCardEmulationManager.onNfcEnabled();
540            }
541
542            synchronized (NfcService.this) {
543                mObjectMap.clear();
544                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
545                updateState(NfcAdapter.STATE_ON);
546            }
547
548            initSoundPool();
549
550            /* Start polling loop */
551
552            applyRouting(true);
553            return true;
554        }
555
556        /**
557         * Disable all NFC adapter functions.
558         * Does not toggle preferences.
559         */
560        boolean disableInternal() {
561            if (mState == NfcAdapter.STATE_OFF) {
562                return true;
563            }
564            Log.i(TAG, "Disabling NFC");
565            updateState(NfcAdapter.STATE_TURNING_OFF);
566
567            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
568             * Implemented with a new thread (instead of a Handler or AsyncTask),
569             * because the UI Thread and AsyncTask thread-pools can also get hung
570             * when the NFC controller stops responding */
571            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
572            watchDog.start();
573
574            if (mIsHceCapable) {
575                mCardEmulationManager.onNfcDisabled();
576            }
577
578            mP2pLinkManager.enableDisable(false, false);
579
580            // Stop watchdog if tag present
581            // A convenient way to stop the watchdog properly consists of
582            // disconnecting the tag. The polling loop shall be stopped before
583            // to avoid the tag being discovered again.
584            maybeDisconnectTarget();
585
586            mNfcDispatcher.setForegroundDispatch(null, null, null);
587
588
589            boolean result = mDeviceHost.deinitialize();
590            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
591
592            watchDog.cancel();
593
594            synchronized (NfcService.this) {
595                mCurrentDiscoveryParameters = NfcDiscoveryParameters.getNfcOffParameters();
596                updateState(NfcAdapter.STATE_OFF);
597            }
598
599            releaseSoundPool();
600
601            return result;
602        }
603
604        void updateState(int newState) {
605            synchronized (NfcService.this) {
606                if (newState == mState) {
607                    return;
608                }
609                mState = newState;
610                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
611                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
612                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
613                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
614            }
615        }
616    }
617
618    void saveNfcOnSetting(boolean on) {
619        synchronized (NfcService.this) {
620            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
621            mPrefsEditor.apply();
622        }
623    }
624
625    public void playSound(int sound) {
626        synchronized (this) {
627            if (mSoundPool == null) {
628                Log.w(TAG, "Not playing sound when NFC is disabled");
629                return;
630            }
631            switch (sound) {
632                case SOUND_START:
633                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
634                    break;
635                case SOUND_END:
636                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
637                    break;
638                case SOUND_ERROR:
639                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
640                    break;
641            }
642        }
643    }
644
645    synchronized int getUserId() {
646        return mUserId;
647    }
648
649    void setBeamShareActivityState(boolean enabled) {
650        mContext.getPackageManager().setComponentEnabledSetting(
651                new ComponentName("com.android.nfc","com.android.nfc.BeamShareActivity"),
652                enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
653                          PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
654                PackageManager.DONT_KILL_APP);
655    }
656
657    final class NfcAdapterService extends INfcAdapter.Stub {
658        @Override
659        public boolean enable() throws RemoteException {
660            NfcPermissions.enforceAdminPermissions(mContext);
661
662            saveNfcOnSetting(true);
663
664            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
665                if (!mIsAirplaneToggleable) {
666                    Log.i(TAG, "denying enable() request (airplane mode)");
667                    return false;
668                }
669                // Make sure the override survives a reboot
670                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
671                mPrefsEditor.apply();
672            }
673            new EnableDisableTask().execute(TASK_ENABLE);
674
675            return true;
676        }
677
678        @Override
679        public boolean disable(boolean saveState) throws RemoteException {
680            NfcPermissions.enforceAdminPermissions(mContext);
681
682            if (saveState) {
683                saveNfcOnSetting(false);
684            }
685
686            new EnableDisableTask().execute(TASK_DISABLE);
687
688            return true;
689        }
690
691        @Override
692        public void pausePolling(int timeoutInMs) {
693            NfcPermissions.enforceAdminPermissions(mContext);
694
695            if (timeoutInMs <= 0 || timeoutInMs > MAX_POLLING_PAUSE_TIMEOUT) {
696                Log.e(TAG, "Refusing to pause polling for " + timeoutInMs + "ms.");
697                return;
698            }
699
700            synchronized (NfcService.this) {
701                mPollingPaused = true;
702                mDeviceHost.disableDiscovery();
703                mHandler.sendMessageDelayed(
704                        mHandler.obtainMessage(MSG_RESUME_POLLING), timeoutInMs);
705            }
706        }
707
708        @Override
709        public void resumePolling() {
710            NfcPermissions.enforceAdminPermissions(mContext);
711
712            synchronized (NfcService.this) {
713                if (!mPollingPaused) {
714                    return;
715                }
716
717                mHandler.removeMessages(MSG_RESUME_POLLING);
718                mPollingPaused = false;
719                new ApplyRoutingTask().execute();
720            }
721        }
722
723        @Override
724        public boolean isNdefPushEnabled() throws RemoteException {
725            synchronized (NfcService.this) {
726                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
727            }
728        }
729
730        @Override
731        public boolean enableNdefPush() throws RemoteException {
732            NfcPermissions.enforceAdminPermissions(mContext);
733            synchronized (NfcService.this) {
734                if (mIsNdefPushEnabled) {
735                    return true;
736                }
737                Log.i(TAG, "enabling NDEF Push");
738                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
739                mPrefsEditor.apply();
740                mIsNdefPushEnabled = true;
741                setBeamShareActivityState(true);
742                if (isNfcEnabled()) {
743                    mP2pLinkManager.enableDisable(true, true);
744                }
745            }
746            return true;
747        }
748
749        @Override
750        public boolean disableNdefPush() throws RemoteException {
751            NfcPermissions.enforceAdminPermissions(mContext);
752            synchronized (NfcService.this) {
753                if (!mIsNdefPushEnabled) {
754                    return true;
755                }
756                Log.i(TAG, "disabling NDEF Push");
757                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
758                mPrefsEditor.apply();
759                mIsNdefPushEnabled = false;
760                setBeamShareActivityState(false);
761                if (isNfcEnabled()) {
762                    mP2pLinkManager.enableDisable(false, true);
763                }
764            }
765            return true;
766        }
767
768        @Override
769        public void setForegroundDispatch(PendingIntent intent,
770                IntentFilter[] filters, TechListParcel techListsParcel) {
771            NfcPermissions.enforceUserPermissions(mContext);
772
773            // Short-cut the disable path
774            if (intent == null && filters == null && techListsParcel == null) {
775                mNfcDispatcher.setForegroundDispatch(null, null, null);
776                return;
777            }
778
779            // Validate the IntentFilters
780            if (filters != null) {
781                if (filters.length == 0) {
782                    filters = null;
783                } else {
784                    for (IntentFilter filter : filters) {
785                        if (filter == null) {
786                            throw new IllegalArgumentException("null IntentFilter");
787                        }
788                    }
789                }
790            }
791
792            // Validate the tech lists
793            String[][] techLists = null;
794            if (techListsParcel != null) {
795                techLists = techListsParcel.getTechLists();
796            }
797
798            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
799        }
800
801
802        @Override
803        public void setAppCallback(IAppCallback callback) {
804            NfcPermissions.enforceUserPermissions(mContext);
805
806            // don't allow Beam for managed profiles, or devices with a device owner or policy owner
807            UserInfo userInfo = mUserManager.getUserInfo(UserHandle.getCallingUserId());
808            if(!userInfo.isManagedProfile()
809                    && !mUserManager.hasUserRestriction(
810                            UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle())) {
811                mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
812            } else if (DBG) {
813                Log.d(TAG, "Disabling default Beam behavior");
814            }
815        }
816
817        @Override
818        public void invokeBeam() {
819            NfcPermissions.enforceUserPermissions(mContext);
820
821            if (mForegroundUtils.isInForeground(Binder.getCallingUid())) {
822                mP2pLinkManager.onManualBeamInvoke(null);
823            } else {
824                Log.e(TAG, "Calling activity not in foreground.");
825            }
826        }
827
828        @Override
829        public void invokeBeamInternal(BeamShareData shareData) {
830            NfcPermissions.enforceAdminPermissions(mContext);
831            Message msg = Message.obtain();
832            msg.what = MSG_INVOKE_BEAM;
833            msg.obj = shareData;
834            // We have to send this message delayed for two reasons:
835            // 1) This is an IPC call from BeamShareActivity, which is
836            //    running when the user has invoked Beam through the
837            //    share menu. As soon as BeamShareActivity closes, the UI
838            //    will need some time to rebuild the original Activity.
839            //    Waiting here for a while gives a better chance of the UI
840            //    having been rebuilt, which means the screenshot that the
841            //    Beam animation is using will be more accurate.
842            // 2) Similarly, because the Activity that launched BeamShareActivity
843            //    with an ACTION_SEND intent is now in paused state, the NDEF
844            //    callbacks that it has registered may no longer be valid.
845            //    Allowing the original Activity to resume will make sure we
846            //    it has a chance to re-register the NDEF message / callback,
847            //    so we share the right data.
848            //
849            //    Note that this is somewhat of a hack because the delay may not actually
850            //    be long enough for 2) on very slow devices, but there's no better
851            //    way to do this right now without additional framework changes.
852            mHandler.sendMessageDelayed(msg, INVOKE_BEAM_DELAY_MS);
853        }
854
855        @Override
856        public INfcTag getNfcTagInterface() throws RemoteException {
857            return mNfcTagService;
858        }
859
860        @Override
861        public INfcCardEmulation getNfcCardEmulationInterface() {
862            if (mIsHceCapable) {
863                return mCardEmulationManager.getNfcCardEmulationInterface();
864            } else {
865                return null;
866            }
867        }
868
869        @Override
870        public int getState() throws RemoteException {
871            synchronized (NfcService.this) {
872                return mState;
873            }
874        }
875
876        @Override
877        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
878            NfcService.this.dump(fd, pw, args);
879        }
880
881        @Override
882        public void dispatch(Tag tag) throws RemoteException {
883            NfcPermissions.enforceAdminPermissions(mContext);
884            mNfcDispatcher.dispatchTag(tag);
885        }
886
887        @Override
888        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
889            NfcPermissions.enforceAdminPermissions(mContext);
890            mDeviceHost.setP2pInitiatorModes(initiatorModes);
891            mDeviceHost.setP2pTargetModes(targetModes);
892            applyRouting(true);
893        }
894
895        @Override
896        public void setReaderMode(IBinder binder, IAppCallback callback, int flags, Bundle extras)
897                throws RemoteException {
898            synchronized (NfcService.this) {
899                if (flags != 0) {
900                    try {
901                        mReaderModeParams = new ReaderModeParams();
902                        mReaderModeParams.callback = callback;
903                        mReaderModeParams.flags = flags;
904                        mReaderModeParams.presenceCheckDelay = extras != null
905                                ? (extras.getInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY,
906                                        DEFAULT_PRESENCE_CHECK_DELAY))
907                                : DEFAULT_PRESENCE_CHECK_DELAY;
908                        binder.linkToDeath(mReaderModeDeathRecipient, 0);
909                    } catch (RemoteException e) {
910                        Log.e(TAG, "Remote binder has already died.");
911                        return;
912                    }
913                } else {
914                    try {
915                        mReaderModeParams = null;
916                        binder.unlinkToDeath(mReaderModeDeathRecipient, 0);
917                    } catch (NoSuchElementException e) {
918                        Log.e(TAG, "Reader mode Binder was never registered.");
919                    }
920                }
921                applyRouting(false);
922            }
923        }
924
925        @Override
926        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) throws RemoteException {
927            // nfc-extras implementation is no longer present in AOSP.
928            return null;
929        }
930
931        @Override
932        public void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, int[] techList) {
933            NfcPermissions.enforceAdminPermissions(mContext);
934
935            int lockscreenPollMask = computeLockscreenPollMask(techList);
936            synchronized (NfcService.this) {
937                mNfcUnlockManager.addUnlockHandler(unlockHandler, lockscreenPollMask);
938            }
939
940            applyRouting(false);
941        }
942
943        @Override
944        public void removeNfcUnlockHandler(INfcUnlockHandler token) throws RemoteException {
945            synchronized (NfcService.this) {
946                mNfcUnlockManager.removeUnlockHandler(token.asBinder());
947            }
948
949            applyRouting(false);
950        }
951
952        private int computeLockscreenPollMask(int[] techList) {
953
954            Map<Integer, Integer> techCodeToMask = new HashMap<Integer, Integer>();
955
956            techCodeToMask.put(TagTechnology.NFC_A, NfcService.NFC_POLL_A);
957            techCodeToMask.put(TagTechnology.NFC_B,
958                    NfcService.NFC_POLL_B | NfcService.NFC_POLL_B_PRIME);
959            techCodeToMask.put(TagTechnology.NFC_V, NfcService.NFC_POLL_ISO15693);
960            techCodeToMask.put(TagTechnology.NFC_F, NfcService.NFC_POLL_F);
961            techCodeToMask.put(TagTechnology.NFC_BARCODE, NfcService.NFC_POLL_KOVIO);
962
963            int mask = 0;
964
965            for (int i = 0; i < techList.length; i++) {
966                if (techCodeToMask.containsKey(techList[i])) {
967                    mask |= techCodeToMask.get(techList[i]).intValue();
968                }
969            }
970
971            return mask;
972        }
973    }
974
975    final class ReaderModeDeathRecipient implements IBinder.DeathRecipient {
976        @Override
977        public void binderDied() {
978            synchronized (NfcService.this) {
979                if (mReaderModeParams != null) {
980                    mReaderModeParams = null;
981                    applyRouting(false);
982                }
983            }
984        }
985    }
986
987    final class TagService extends INfcTag.Stub {
988        @Override
989        public int close(int nativeHandle) throws RemoteException {
990            NfcPermissions.enforceUserPermissions(mContext);
991
992            TagEndpoint tag = null;
993
994            if (!isNfcEnabled()) {
995                return ErrorCodes.ERROR_NOT_INITIALIZED;
996            }
997
998            /* find the tag in the hmap */
999            tag = (TagEndpoint) findObject(nativeHandle);
1000            if (tag != null) {
1001                /* Remove the device from the hmap */
1002                unregisterObject(nativeHandle);
1003                tag.disconnect();
1004                return ErrorCodes.SUCCESS;
1005            }
1006            /* Restart polling loop for notification */
1007            applyRouting(true);
1008            return ErrorCodes.ERROR_DISCONNECT;
1009        }
1010
1011        @Override
1012        public int connect(int nativeHandle, int technology) throws RemoteException {
1013            NfcPermissions.enforceUserPermissions(mContext);
1014
1015            TagEndpoint tag = null;
1016
1017            if (!isNfcEnabled()) {
1018                return ErrorCodes.ERROR_NOT_INITIALIZED;
1019            }
1020
1021            /* find the tag in the hmap */
1022            tag = (TagEndpoint) findObject(nativeHandle);
1023            if (tag == null) {
1024                return ErrorCodes.ERROR_DISCONNECT;
1025            }
1026
1027            if (!tag.isPresent()) {
1028                return ErrorCodes.ERROR_DISCONNECT;
1029            }
1030
1031            // Note that on most tags, all technologies are behind a single
1032            // handle. This means that the connect at the lower levels
1033            // will do nothing, as the tag is already connected to that handle.
1034            if (tag.connect(technology)) {
1035                return ErrorCodes.SUCCESS;
1036            } else {
1037                return ErrorCodes.ERROR_DISCONNECT;
1038            }
1039        }
1040
1041        @Override
1042        public int reconnect(int nativeHandle) throws RemoteException {
1043            NfcPermissions.enforceUserPermissions(mContext);
1044
1045            TagEndpoint tag = null;
1046
1047            // Check if NFC is enabled
1048            if (!isNfcEnabled()) {
1049                return ErrorCodes.ERROR_NOT_INITIALIZED;
1050            }
1051
1052            /* find the tag in the hmap */
1053            tag = (TagEndpoint) findObject(nativeHandle);
1054            if (tag != null) {
1055                if (tag.reconnect()) {
1056                    return ErrorCodes.SUCCESS;
1057                } else {
1058                    return ErrorCodes.ERROR_DISCONNECT;
1059                }
1060            }
1061            return ErrorCodes.ERROR_DISCONNECT;
1062        }
1063
1064        @Override
1065        public int[] getTechList(int nativeHandle) throws RemoteException {
1066            NfcPermissions.enforceUserPermissions(mContext);
1067
1068            // Check if NFC is enabled
1069            if (!isNfcEnabled()) {
1070                return null;
1071            }
1072
1073            /* find the tag in the hmap */
1074            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1075            if (tag != null) {
1076                return tag.getTechList();
1077            }
1078            return null;
1079        }
1080
1081        @Override
1082        public boolean isPresent(int nativeHandle) throws RemoteException {
1083            TagEndpoint tag = null;
1084
1085            // Check if NFC is enabled
1086            if (!isNfcEnabled()) {
1087                return false;
1088            }
1089
1090            /* find the tag in the hmap */
1091            tag = (TagEndpoint) findObject(nativeHandle);
1092            if (tag == null) {
1093                return false;
1094            }
1095
1096            return tag.isPresent();
1097        }
1098
1099        @Override
1100        public boolean isNdef(int nativeHandle) throws RemoteException {
1101            NfcPermissions.enforceUserPermissions(mContext);
1102
1103            TagEndpoint tag = null;
1104
1105            // Check if NFC is enabled
1106            if (!isNfcEnabled()) {
1107                return false;
1108            }
1109
1110            /* find the tag in the hmap */
1111            tag = (TagEndpoint) findObject(nativeHandle);
1112            int[] ndefInfo = new int[2];
1113            if (tag == null) {
1114                return false;
1115            }
1116            return tag.checkNdef(ndefInfo);
1117        }
1118
1119        @Override
1120        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
1121                throws RemoteException {
1122            NfcPermissions.enforceUserPermissions(mContext);
1123
1124            TagEndpoint tag = null;
1125            byte[] response;
1126
1127            // Check if NFC is enabled
1128            if (!isNfcEnabled()) {
1129                return null;
1130            }
1131
1132            /* find the tag in the hmap */
1133            tag = (TagEndpoint) findObject(nativeHandle);
1134            if (tag != null) {
1135                // Check if length is within limits
1136                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1137                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1138                }
1139                int[] targetLost = new int[1];
1140                response = tag.transceive(data, raw, targetLost);
1141                int result;
1142                if (response != null) {
1143                    result = TransceiveResult.RESULT_SUCCESS;
1144                } else if (targetLost[0] == 1) {
1145                    result = TransceiveResult.RESULT_TAGLOST;
1146                } else {
1147                    result = TransceiveResult.RESULT_FAILURE;
1148                }
1149                return new TransceiveResult(result, response);
1150            }
1151            return null;
1152        }
1153
1154        @Override
1155        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1156            NfcPermissions.enforceUserPermissions(mContext);
1157
1158            TagEndpoint tag;
1159
1160            // Check if NFC is enabled
1161            if (!isNfcEnabled()) {
1162                return null;
1163            }
1164
1165            /* find the tag in the hmap */
1166            tag = (TagEndpoint) findObject(nativeHandle);
1167            if (tag != null) {
1168                byte[] buf = tag.readNdef();
1169                if (buf == null) {
1170                    return null;
1171                }
1172
1173                /* Create an NdefMessage */
1174                try {
1175                    return new NdefMessage(buf);
1176                } catch (FormatException e) {
1177                    return null;
1178                }
1179            }
1180            return null;
1181        }
1182
1183        @Override
1184        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1185            NfcPermissions.enforceUserPermissions(mContext);
1186
1187            TagEndpoint tag;
1188
1189            // Check if NFC is enabled
1190            if (!isNfcEnabled()) {
1191                return ErrorCodes.ERROR_NOT_INITIALIZED;
1192            }
1193
1194            /* find the tag in the hmap */
1195            tag = (TagEndpoint) findObject(nativeHandle);
1196            if (tag == null) {
1197                return ErrorCodes.ERROR_IO;
1198            }
1199
1200            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1201
1202            if (tag.writeNdef(msg.toByteArray())) {
1203                return ErrorCodes.SUCCESS;
1204            } else {
1205                return ErrorCodes.ERROR_IO;
1206            }
1207
1208        }
1209
1210        @Override
1211        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
1212            throw new UnsupportedOperationException();
1213        }
1214
1215        @Override
1216        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
1217            NfcPermissions.enforceUserPermissions(mContext);
1218
1219            TagEndpoint tag;
1220
1221            // Check if NFC is enabled
1222            if (!isNfcEnabled()) {
1223                return ErrorCodes.ERROR_NOT_INITIALIZED;
1224            }
1225
1226            /* find the tag in the hmap */
1227            tag = (TagEndpoint) findObject(nativeHandle);
1228            if (tag == null) {
1229                return ErrorCodes.ERROR_IO;
1230            }
1231
1232            if (tag.makeReadOnly()) {
1233                return ErrorCodes.SUCCESS;
1234            } else {
1235                return ErrorCodes.ERROR_IO;
1236            }
1237        }
1238
1239        @Override
1240        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
1241            NfcPermissions.enforceUserPermissions(mContext);
1242
1243            TagEndpoint tag;
1244
1245            // Check if NFC is enabled
1246            if (!isNfcEnabled()) {
1247                return ErrorCodes.ERROR_NOT_INITIALIZED;
1248            }
1249
1250            /* find the tag in the hmap */
1251            tag = (TagEndpoint) findObject(nativeHandle);
1252            if (tag == null) {
1253                return ErrorCodes.ERROR_IO;
1254            }
1255
1256            if (tag.formatNdef(key)) {
1257                return ErrorCodes.SUCCESS;
1258            } else {
1259                return ErrorCodes.ERROR_IO;
1260            }
1261        }
1262
1263        @Override
1264        public Tag rediscover(int nativeHandle) throws RemoteException {
1265            NfcPermissions.enforceUserPermissions(mContext);
1266
1267            TagEndpoint tag = null;
1268
1269            // Check if NFC is enabled
1270            if (!isNfcEnabled()) {
1271                return null;
1272            }
1273
1274            /* find the tag in the hmap */
1275            tag = (TagEndpoint) findObject(nativeHandle);
1276            if (tag != null) {
1277                // For now the prime usecase for rediscover() is to be able
1278                // to access the NDEF technology after formatting without
1279                // having to remove the tag from the field, or similar
1280                // to have access to NdefFormatable in case low-level commands
1281                // were used to remove NDEF. So instead of doing a full stack
1282                // rediscover (which is poorly supported at the moment anyway),
1283                // we simply remove these two technologies and detect them
1284                // again.
1285                tag.removeTechnology(TagTechnology.NDEF);
1286                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1287                tag.findAndReadNdef();
1288                // Build a new Tag object to return
1289                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
1290                        tag.getTechExtras(), tag.getHandle(), this);
1291                return newTag;
1292            }
1293            return null;
1294        }
1295
1296        @Override
1297        public int setTimeout(int tech, int timeout) throws RemoteException {
1298            NfcPermissions.enforceUserPermissions(mContext);
1299            boolean success = mDeviceHost.setTimeout(tech, timeout);
1300            if (success) {
1301                return ErrorCodes.SUCCESS;
1302            } else {
1303                return ErrorCodes.ERROR_INVALID_PARAM;
1304            }
1305        }
1306
1307        @Override
1308        public int getTimeout(int tech) throws RemoteException {
1309            NfcPermissions.enforceUserPermissions(mContext);
1310
1311            return mDeviceHost.getTimeout(tech);
1312        }
1313
1314        @Override
1315        public void resetTimeouts() throws RemoteException {
1316            NfcPermissions.enforceUserPermissions(mContext);
1317
1318            mDeviceHost.resetTimeouts();
1319        }
1320
1321        @Override
1322        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1323            return mDeviceHost.canMakeReadOnly(ndefType);
1324        }
1325
1326        @Override
1327        public int getMaxTransceiveLength(int tech) throws RemoteException {
1328            return mDeviceHost.getMaxTransceiveLength(tech);
1329        }
1330
1331        @Override
1332        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1333            return mDeviceHost.getExtendedLengthApdusSupported();
1334        }
1335    }
1336
1337    boolean isNfcEnabledOrShuttingDown() {
1338        synchronized (this) {
1339            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
1340        }
1341    }
1342
1343    boolean isNfcEnabled() {
1344        synchronized (this) {
1345            return mState == NfcAdapter.STATE_ON;
1346        }
1347    }
1348
1349    class WatchDogThread extends Thread {
1350        final Object mCancelWaiter = new Object();
1351        final int mTimeout;
1352        boolean mCanceled = false;
1353
1354        public WatchDogThread(String threadName, int timeout) {
1355            super(threadName);
1356            mTimeout = timeout;
1357        }
1358
1359        @Override
1360        public void run() {
1361            try {
1362                synchronized (mCancelWaiter) {
1363                    mCancelWaiter.wait(mTimeout);
1364                    if (mCanceled) {
1365                        return;
1366                    }
1367                }
1368            } catch (InterruptedException e) {
1369                // Should not happen; fall-through to abort.
1370                Log.w(TAG, "Watchdog thread interruped.");
1371                interrupt();
1372            }
1373            Log.e(TAG, "Watchdog triggered, aborting.");
1374            mDeviceHost.doAbort();
1375        }
1376
1377        public synchronized void cancel() {
1378            synchronized (mCancelWaiter) {
1379                mCanceled = true;
1380                mCancelWaiter.notify();
1381            }
1382        }
1383    }
1384
1385    static byte[] hexStringToBytes(String s) {
1386        if (s == null || s.length() == 0) return null;
1387        int len = s.length();
1388        if (len % 2 != 0) {
1389            s = '0' + s;
1390            len++;
1391        }
1392        byte[] data = new byte[len / 2];
1393        for (int i = 0; i < len; i += 2) {
1394            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
1395                    + Character.digit(s.charAt(i + 1), 16));
1396        }
1397        return data;
1398    }
1399
1400    /**
1401     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1402     */
1403    void applyRouting(boolean force) {
1404        synchronized (this) {
1405            if (!isNfcEnabledOrShuttingDown()) {
1406                return;
1407            }
1408            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
1409            if (mInProvisionMode) {
1410                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
1411                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
1412                if (!mInProvisionMode) {
1413                    // Notify dispatcher it's fine to dispatch to any package now
1414                    // and allow handover transfers.
1415                    mNfcDispatcher.disableProvisioningMode();
1416                    mHandoverManager.setEnabled(true);
1417                }
1418            }
1419            // Special case: if we're transitioning to unlocked state while
1420            // still talking to a tag, postpone re-configuration.
1421            if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && isTagPresent()) {
1422                Log.d(TAG, "Not updating discovery parameters, tag connected.");
1423                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESUME_POLLING),
1424                        APPLY_ROUTING_RETRY_TIMEOUT_MS);
1425                return;
1426            }
1427
1428            try {
1429                watchDog.start();
1430                // Compute new polling parameters
1431                NfcDiscoveryParameters newParams = computeDiscoveryParameters(mScreenState);
1432                if (force || !newParams.equals(mCurrentDiscoveryParameters)) {
1433                    if (newParams.shouldEnableDiscovery()) {
1434                        boolean shouldRestart = mCurrentDiscoveryParameters.shouldEnableDiscovery();
1435                        mDeviceHost.enableDiscovery(newParams, shouldRestart);
1436                    } else {
1437                        mDeviceHost.disableDiscovery();
1438                    }
1439                    mCurrentDiscoveryParameters = newParams;
1440                } else {
1441                    Log.d(TAG, "Discovery configuration equal, not updating.");
1442                }
1443            } finally {
1444                watchDog.cancel();
1445            }
1446        }
1447    }
1448
1449    private NfcDiscoveryParameters computeDiscoveryParameters(int screenState) {
1450        // Recompute discovery parameters based on screen state
1451        NfcDiscoveryParameters.Builder paramsBuilder = NfcDiscoveryParameters.newBuilder();
1452        // Polling
1453        if (screenState >= NFC_POLLING_MODE) {
1454            // Check if reader-mode is enabled
1455            if (mReaderModeParams != null) {
1456                int techMask = 0;
1457                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_A) != 0)
1458                    techMask |= NFC_POLL_A;
1459                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_B) != 0)
1460                    techMask |= NFC_POLL_B;
1461                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_F) != 0)
1462                    techMask |= NFC_POLL_F;
1463                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_V) != 0)
1464                    techMask |= NFC_POLL_ISO15693;
1465                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_BARCODE) != 0)
1466                    techMask |= NFC_POLL_KOVIO;
1467
1468                paramsBuilder.setTechMask(techMask);
1469                paramsBuilder.setEnableReaderMode(true);
1470            } else {
1471                paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
1472            }
1473        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mInProvisionMode) {
1474            paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
1475        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED &&
1476                mNfcUnlockManager.isLockscreenPollingEnabled()) {
1477            // For lock-screen tags, no low-power polling
1478            paramsBuilder.setTechMask(mNfcUnlockManager.getLockscreenPollMask());
1479            paramsBuilder.setEnableLowPowerDiscovery(false);
1480        }
1481
1482        if (mIsHceCapable && mScreenState >= ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
1483            // Host routing is always enabled at lock screen or later
1484            paramsBuilder.setEnableHostRouting(true);
1485        }
1486        return paramsBuilder.build();
1487    }
1488
1489    private boolean isTagPresent() {
1490        for (Object object : mObjectMap.values()) {
1491            if (object instanceof TagEndpoint) {
1492                return ((TagEndpoint) object).isPresent();
1493            }
1494        }
1495        return false;
1496    }
1497    /**
1498     * Disconnect any target if present
1499     */
1500    void maybeDisconnectTarget() {
1501        if (!isNfcEnabledOrShuttingDown()) {
1502            return;
1503        }
1504        Object[] objectsToDisconnect;
1505        synchronized (this) {
1506            Object[] objectValues = mObjectMap.values().toArray();
1507            // Copy the array before we clear mObjectMap,
1508            // just in case the HashMap values are backed by the same array
1509            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
1510            mObjectMap.clear();
1511        }
1512        for (Object o : objectsToDisconnect) {
1513            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
1514            if (o instanceof TagEndpoint) {
1515                // Disconnect from tags
1516                TagEndpoint tag = (TagEndpoint) o;
1517                tag.disconnect();
1518            } else if (o instanceof NfcDepEndpoint) {
1519                // Disconnect from P2P devices
1520                NfcDepEndpoint device = (NfcDepEndpoint) o;
1521                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1522                    // Remote peer is target, request disconnection
1523                    device.disconnect();
1524                } else {
1525                    // Remote peer is initiator, we cannot disconnect
1526                    // Just wait for field removal
1527                }
1528            }
1529        }
1530    }
1531
1532    Object findObject(int key) {
1533        synchronized (this) {
1534            Object device = mObjectMap.get(key);
1535            if (device == null) {
1536                Log.w(TAG, "Handle not found");
1537            }
1538            return device;
1539        }
1540    }
1541
1542    void registerTagObject(TagEndpoint tag) {
1543        synchronized (this) {
1544            mObjectMap.put(tag.getHandle(), tag);
1545        }
1546    }
1547
1548    void unregisterObject(int handle) {
1549        synchronized (this) {
1550            mObjectMap.remove(handle);
1551        }
1552    }
1553
1554    /**
1555     * For use by code in this process
1556     */
1557    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1558            throws LlcpException {
1559        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1560    }
1561
1562    /**
1563     * For use by code in this process
1564     */
1565    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
1566            throws LlcpException {
1567        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
1568    }
1569
1570    /**
1571     * For use by code in this process
1572     */
1573    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1574            int linearBufferLength) throws LlcpException {
1575        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1576    }
1577
1578    public void sendMockNdefTag(NdefMessage msg) {
1579        sendMessage(MSG_MOCK_NDEF, msg);
1580    }
1581
1582    public void routeAids(String aid, int route) {
1583        Message msg = mHandler.obtainMessage();
1584        msg.what = MSG_ROUTE_AID;
1585        msg.arg1 = route;
1586        msg.obj = aid;
1587        mHandler.sendMessage(msg);
1588    }
1589
1590    public void unrouteAids(String aid) {
1591        sendMessage(MSG_UNROUTE_AID, aid);
1592    }
1593
1594    public void commitRouting() {
1595        mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
1596    }
1597
1598    public boolean sendData(byte[] data) {
1599        return mDeviceHost.sendRawFrame(data);
1600    }
1601
1602    void sendMessage(int what, Object obj) {
1603        Message msg = mHandler.obtainMessage();
1604        msg.what = what;
1605        msg.obj = obj;
1606        mHandler.sendMessage(msg);
1607    }
1608
1609    final class NfcServiceHandler extends Handler {
1610        @Override
1611        public void handleMessage(Message msg) {
1612            switch (msg.what) {
1613                case MSG_ROUTE_AID: {
1614                    int route = msg.arg1;
1615                    String aid = (String) msg.obj;
1616                    mDeviceHost.routeAid(hexStringToBytes(aid), route);
1617                    // Restart polling config
1618                    break;
1619                }
1620                case MSG_UNROUTE_AID: {
1621                    String aid = (String) msg.obj;
1622                    mDeviceHost.unrouteAid(hexStringToBytes(aid));
1623                    break;
1624                }
1625                case MSG_INVOKE_BEAM: {
1626                    mP2pLinkManager.onManualBeamInvoke((BeamShareData)msg.obj);
1627                    break;
1628                }
1629                case MSG_COMMIT_ROUTING: {
1630                    boolean commit = false;
1631                    synchronized (NfcService.this) {
1632                        if (mCurrentDiscoveryParameters.shouldEnableDiscovery()) {
1633                            commit = true;
1634                        } else {
1635                            Log.d(TAG, "Not committing routing because discovery is disabled.");
1636                        }
1637                    }
1638                    if (commit) {
1639                        mDeviceHost.commitRouting();
1640                    }
1641                    break;
1642                }
1643                case MSG_MOCK_NDEF: {
1644                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
1645                    Bundle extras = new Bundle();
1646                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
1647                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
1648                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
1649                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
1650                    Tag tag = Tag.createMockTag(new byte[]{0x00},
1651                            new int[]{TagTechnology.NDEF},
1652                            new Bundle[]{extras});
1653                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
1654                    Log.d(TAG, tag.toString());
1655                    int dispatchStatus = mNfcDispatcher.dispatchTag(tag);
1656                    if (dispatchStatus == NfcDispatcher.DISPATCH_SUCCESS) {
1657                        playSound(SOUND_END);
1658                    } else if (dispatchStatus == NfcDispatcher.DISPATCH_FAIL) {
1659                        playSound(SOUND_ERROR);
1660                    }
1661                    break;
1662                }
1663
1664                case MSG_NDEF_TAG:
1665                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
1666                    TagEndpoint tag = (TagEndpoint) msg.obj;
1667                    ReaderModeParams readerParams = null;
1668                    int presenceCheckDelay = DEFAULT_PRESENCE_CHECK_DELAY;
1669                    DeviceHost.TagDisconnectedCallback callback =
1670                            new DeviceHost.TagDisconnectedCallback() {
1671                                @Override
1672                                public void onTagDisconnected(long handle) {
1673                                    applyRouting(false);
1674                                }
1675                            };
1676                    synchronized (NfcService.this) {
1677                        readerParams = mReaderModeParams;
1678                    }
1679                    if (readerParams != null) {
1680                        presenceCheckDelay = readerParams.presenceCheckDelay;
1681                        if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
1682                            if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
1683                            tag.startPresenceChecking(presenceCheckDelay, callback);
1684                            dispatchTagEndpoint(tag, readerParams);
1685                            break;
1686                        }
1687                    }
1688
1689                    boolean playSound = readerParams == null ||
1690                        (readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0;
1691                    if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && playSound) {
1692                        playSound(SOUND_START);
1693                    }
1694                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
1695                        // When these tags start containing NDEF, they will require
1696                        // the stack to deal with them in a different way, since
1697                        // they are activated only really shortly.
1698                        // For now, don't consider NDEF on these.
1699                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
1700                        tag.startPresenceChecking(presenceCheckDelay, callback);
1701                        dispatchTagEndpoint(tag, readerParams);
1702                        break;
1703                    }
1704                    NdefMessage ndefMsg = tag.findAndReadNdef();
1705
1706                    if (ndefMsg != null) {
1707                        tag.startPresenceChecking(presenceCheckDelay, callback);
1708                        dispatchTagEndpoint(tag, readerParams);
1709                    } else {
1710                        if (tag.reconnect()) {
1711                            tag.startPresenceChecking(presenceCheckDelay, callback);
1712                            dispatchTagEndpoint(tag, readerParams);
1713                        } else {
1714                            tag.disconnect();
1715                            playSound(SOUND_ERROR);
1716                        }
1717                    }
1718                    break;
1719                case MSG_LLCP_LINK_ACTIVATION:
1720                    if (mIsDebugBuild) {
1721                        Intent actIntent = new Intent(ACTION_LLCP_UP);
1722                        mContext.sendBroadcast(actIntent);
1723                    }
1724                    llcpActivated((NfcDepEndpoint) msg.obj);
1725                    break;
1726
1727                case MSG_LLCP_LINK_DEACTIVATED:
1728                    if (mIsDebugBuild) {
1729                        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
1730                        mContext.sendBroadcast(deactIntent);
1731                    }
1732                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
1733                    boolean needsDisconnect = false;
1734
1735                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
1736                    synchronized (NfcService.this) {
1737                        /* Check if the device has been already unregistered */
1738                        if (mObjectMap.remove(device.getHandle()) != null) {
1739                            /* Disconnect if we are initiator */
1740                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1741                                if (DBG) Log.d(TAG, "disconnecting from target");
1742                                needsDisconnect = true;
1743                            } else {
1744                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
1745                            }
1746                        }
1747                    }
1748                    if (needsDisconnect) {
1749                        device.disconnect();  // restarts polling loop
1750                    }
1751
1752                    mP2pLinkManager.onLlcpDeactivated();
1753                    break;
1754                case MSG_LLCP_LINK_FIRST_PACKET:
1755                    mP2pLinkManager.onLlcpFirstPacketReceived();
1756                    break;
1757                case MSG_RF_FIELD_ACTIVATED:
1758                    Intent fieldOnIntent = new Intent(ACTION_RF_FIELD_ON_DETECTED);
1759                    sendNfcEeAccessProtectedBroadcast(fieldOnIntent);
1760                    break;
1761                case MSG_RF_FIELD_DEACTIVATED:
1762                    Intent fieldOffIntent = new Intent(ACTION_RF_FIELD_OFF_DETECTED);
1763                    sendNfcEeAccessProtectedBroadcast(fieldOffIntent);
1764                    break;
1765                case MSG_RESUME_POLLING:
1766                    mNfcAdapter.resumePolling();
1767                    break;
1768                default:
1769                    Log.e(TAG, "Unknown message received");
1770                    break;
1771            }
1772        }
1773
1774        private void sendNfcEeAccessProtectedBroadcast(Intent intent) {
1775            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
1776            // Resume app switches so the receivers can start activites without delay
1777            mNfcDispatcher.resumeAppSwitches();
1778
1779            synchronized (this) {
1780                for (PackageInfo pkg : mInstalledPackages) {
1781                    if (pkg != null && pkg.applicationInfo != null) {
1782                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
1783                            intent.setPackage(pkg.packageName);
1784                            mContext.sendBroadcast(intent);
1785                        }
1786                    }
1787                }
1788            }
1789        }
1790
1791        private boolean llcpActivated(NfcDepEndpoint device) {
1792            Log.d(TAG, "LLCP Activation message");
1793
1794            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1795                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1796                if (device.connect()) {
1797                    /* Check LLCP compliancy */
1798                    if (mDeviceHost.doCheckLlcp()) {
1799                        /* Activate LLCP Link */
1800                        if (mDeviceHost.doActivateLlcp()) {
1801                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
1802                            synchronized (NfcService.this) {
1803                                // Register P2P device
1804                                mObjectMap.put(device.getHandle(), device);
1805                            }
1806                            mP2pLinkManager.onLlcpActivated();
1807                            return true;
1808                        } else {
1809                            /* should not happen */
1810                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1811                            device.disconnect();
1812                        }
1813                    } else {
1814                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1815                        device.disconnect();
1816                    }
1817                } else {
1818                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1819                    /*
1820                     * The polling loop should have been restarted in failing
1821                     * doConnect
1822                     */
1823                }
1824            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1825                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1826                /* Check LLCP compliancy */
1827                if (mDeviceHost.doCheckLlcp()) {
1828                    /* Activate LLCP Link */
1829                    if (mDeviceHost.doActivateLlcp()) {
1830                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
1831                        synchronized (NfcService.this) {
1832                            // Register P2P device
1833                            mObjectMap.put(device.getHandle(), device);
1834                        }
1835                        mP2pLinkManager.onLlcpActivated();
1836                        return true;
1837                    }
1838                } else {
1839                    Log.w(TAG, "checkLlcp failed");
1840                }
1841            }
1842
1843            return false;
1844        }
1845
1846        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, ReaderModeParams readerParams) {
1847            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
1848                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
1849            registerTagObject(tagEndpoint);
1850            if (readerParams != null) {
1851                try {
1852                    if ((readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
1853                        playSound(SOUND_END);
1854                    }
1855                    if (readerParams.callback != null) {
1856                        readerParams.callback.onTagDiscovered(tag);
1857                        return;
1858                    } else {
1859                        // Follow normal dispatch below
1860                    }
1861                } catch (RemoteException e) {
1862                    Log.e(TAG, "Reader mode remote has died, falling back.", e);
1863                    // Intentional fall-through
1864                } catch (Exception e) {
1865                    // Catch any other exception
1866                    Log.e(TAG, "App exception, not dispatching.", e);
1867                    return;
1868                }
1869            }
1870            int dispatchResult = mNfcDispatcher.dispatchTag(tag);
1871            if (dispatchResult == NfcDispatcher.DISPATCH_FAIL) {
1872                unregisterObject(tagEndpoint.getHandle());
1873                playSound(SOUND_ERROR);
1874            } else if (dispatchResult == NfcDispatcher.DISPATCH_SUCCESS) {
1875                playSound(SOUND_END);
1876            }
1877        }
1878    }
1879
1880    private NfcServiceHandler mHandler = new NfcServiceHandler();
1881
1882    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
1883        @Override
1884        protected Void doInBackground(Integer... params) {
1885            synchronized (NfcService.this) {
1886                if (params == null || params.length != 1) {
1887                    // force apply current routing
1888                    applyRouting(true);
1889                    return null;
1890                }
1891                mScreenState = params[0].intValue();
1892
1893                mRoutingWakeLock.acquire();
1894                try {
1895                    applyRouting(false);
1896                } finally {
1897                    mRoutingWakeLock.release();
1898                }
1899                return null;
1900            }
1901        }
1902    }
1903
1904    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1905        @Override
1906        public void onReceive(Context context, Intent intent) {
1907            String action = intent.getAction();
1908            if (action.equals(Intent.ACTION_SCREEN_ON)
1909                    || action.equals(Intent.ACTION_SCREEN_OFF)
1910                    || action.equals(Intent.ACTION_USER_PRESENT)) {
1911                // Perform applyRouting() in AsyncTask to serialize blocking calls
1912                int screenState = ScreenStateHelper.SCREEN_STATE_OFF;
1913                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1914                    screenState = ScreenStateHelper.SCREEN_STATE_OFF;
1915                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1916                    screenState = mKeyguard.isKeyguardLocked()
1917                            ? ScreenStateHelper.SCREEN_STATE_ON_LOCKED
1918                            : ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1919                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1920                    screenState = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1921                }
1922                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
1923            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
1924                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
1925                // Query the airplane mode from Settings.System just to make sure that
1926                // some random app is not sending this intent
1927                if (isAirplaneModeOn != isAirplaneModeOn()) {
1928                    return;
1929                }
1930                if (!mIsAirplaneSensitive) {
1931                    return;
1932                }
1933                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
1934                mPrefsEditor.apply();
1935                if (isAirplaneModeOn) {
1936                    new EnableDisableTask().execute(TASK_DISABLE);
1937                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
1938                    new EnableDisableTask().execute(TASK_ENABLE);
1939                }
1940            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
1941                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1942                synchronized (this) {
1943                    mUserId = userId;
1944                }
1945                mP2pLinkManager.onUserSwitched(getUserId());
1946                if (mIsHceCapable) {
1947                    mCardEmulationManager.onUserSwitched(getUserId());
1948                }
1949            }
1950        }
1951    };
1952
1953    private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
1954        @Override
1955        public void onReceive(Context context, Intent intent) {
1956            String action = intent.getAction();
1957            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
1958                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
1959                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
1960                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1961                updatePackageCache();
1962
1963                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
1964                    // Clear the NFCEE access cache in case a UID gets recycled
1965                    mNfceeAccessControl.invalidateCache();
1966                }
1967            }
1968        }
1969    };
1970
1971
1972    /**
1973     * Returns true if airplane mode is currently on
1974     */
1975    boolean isAirplaneModeOn() {
1976        return Settings.System.getInt(mContentResolver,
1977                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
1978    }
1979
1980    /**
1981     * for debugging only - no i18n
1982     */
1983    static String stateToString(int state) {
1984        switch (state) {
1985            case NfcAdapter.STATE_OFF:
1986                return "off";
1987            case NfcAdapter.STATE_TURNING_ON:
1988                return "turning on";
1989            case NfcAdapter.STATE_ON:
1990                return "on";
1991            case NfcAdapter.STATE_TURNING_OFF:
1992                return "turning off";
1993            default:
1994                return "<error>";
1995        }
1996    }
1997
1998    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1999        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2000                != PackageManager.PERMISSION_GRANTED) {
2001            pw.println("Permission Denial: can't dump nfc from from pid="
2002                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
2003                    + " without permission " + android.Manifest.permission.DUMP);
2004            return;
2005        }
2006
2007        synchronized (this) {
2008            pw.println("mState=" + stateToString(mState));
2009            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
2010            pw.println("mScreenState=" + ScreenStateHelper.screenStateToString(mScreenState));
2011            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
2012            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
2013            pw.println(mCurrentDiscoveryParameters);
2014            mP2pLinkManager.dump(fd, pw, args);
2015            if (mIsHceCapable) {
2016                mCardEmulationManager.dump(fd, pw, args);
2017            }
2018            mNfcDispatcher.dump(fd, pw, args);
2019            pw.println(mDeviceHost.dump());
2020        }
2021    }
2022}
2023