NfcService.java revision d92037714c289cffb9ed1e6e6df36cd3b7292a21
1f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly/*
2f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * Copyright (C) 2010 The Android Open Source Project
3f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly *
4f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License");
5f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * you may not use this file except in compliance with the License.
6f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * You may obtain a copy of the License at
7f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly *
8f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly *      http://www.apache.org/licenses/LICENSE-2.0
9f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly *
10f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * Unless required by applicable law or agreed to in writing, software
11f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS,
12f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * See the License for the specific language governing permissions and
14f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly * limitations under the License.
15f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly */
16f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1713d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellypackage com.android.nfc;
18f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
19f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamiltonimport com.android.nfc.DeviceHost.DeviceHostListener;
204a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamiltonimport com.android.nfc.DeviceHost.LlcpServerSocket;
214a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamiltonimport com.android.nfc.DeviceHost.LlcpSocket;
22f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamiltonimport com.android.nfc.DeviceHost.NfcDepEndpoint;
23f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamiltonimport com.android.nfc.DeviceHost.TagEndpoint;
2481c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport com.android.nfc.nxp.NativeNfcManager;
2581c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport com.android.nfc.nxp.NativeNfcSecureElement;
268afd14d3b23d3124c48ee275ba2845aede6542a1Jeff Hamiltonimport com.android.nfc3.R;
27d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
282f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pellyimport android.app.Application;
29275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parksimport android.app.KeyguardManager;
3005973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamiltonimport android.app.PendingIntent;
3113d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.BroadcastReceiver;
3205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamiltonimport android.content.ComponentName;
3331949217328bf2357ff044f0d18677fe588c790cNick Pellyimport android.content.ContentResolver;
3413d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Context;
3513d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Intent;
3613d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.IntentFilter;
370e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.content.SharedPreferences;
3893d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamiltonimport android.content.pm.PackageManager;
39d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.AudioManager;
40d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.SoundPool;
413fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamiltonimport android.net.Uri;
42f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.ErrorCodes;
43f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.FormatException;
442094515fca0cfa0ac87e9cc260d3953d416afe3eJason parksimport android.nfc.INdefPushCallback;
450e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.INfcAdapter;
4649d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.nfc.INfcAdapterExtras;
47f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.INfcTag;
48f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NdefMessage;
49f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NfcAdapter;
500e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.Tag;
5124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.nfc.TechListParcel;
529d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenenimport android.nfc.TransceiveResult;
53aca0d055a82da850c27f6872405602ad5f3fee7bJeff Hamiltonimport android.nfc.tech.Ndef;
5481c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport android.nfc.tech.TagTechnology;
557c034a7fe7d36b1ab039af2c44717812ea02657eNick Pellyimport android.os.AsyncTask;
5650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Rootimport android.os.Binder;
57b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamiltonimport android.os.Bundle;
58b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Handler;
5949d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.os.IBinder;
60b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Message;
61533043d1003de2f6a20a29201100d94c3c7bc9caNick Pellyimport android.os.PowerManager;
624467dca5650a170af5020c10a8ccb25f86f1007fNick Pellyimport android.os.Process;
63f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.os.RemoteException;
6413d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.os.ServiceManager;
65d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.provider.Settings;
66f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.util.Log;
67f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
6831949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.FileDescriptor;
6957d376f1ee1a3939977b95759525585abb9601fbJeff Hamiltonimport java.io.IOException;
7031949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.PrintWriter;
7131949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.Arrays;
723ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamiltonimport java.util.HashMap;
7384e1e0adc2516afd35ebab029a52e764e0490559Jason parksimport java.util.HashSet;
7431949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.concurrent.ExecutionException;
753ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
7677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellypublic class NfcService extends Application implements DeviceHostListener {
77bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
78bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
798d6a8dce6706c6c6b3158101f2f3e94a1e0ad946Ben Dodson    static final boolean DBG = true;
8076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
81fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
82d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
83fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
84bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM = android.Manifest.permission.NFC;
85bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM_ERROR = "NFC permission required";
86bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
87bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
88a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly    private static final String NFCEE_ADMIN_PERM = "com.android.nfc.permission.NFCEE_ADMIN";
8993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    private static final String NFCEE_ADMIN_PERM_ERROR = "NFCEE_ADMIN permission required";
90bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
9177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
92f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
93f5c40bdbcabbe81fdf43a24cd82be919ffb5de04Jeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
94f5c40bdbcabbe81fdf43a24cd82be919ffb5de04Jeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
95f5c40bdbcabbe81fdf43a24cd82be919ffb5de04Jeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
96f5c40bdbcabbe81fdf43a24cd82be919ffb5de04Jeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
97f5c40bdbcabbe81fdf43a24cd82be919ffb5de04Jeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
98f5c40bdbcabbe81fdf43a24cd82be919ffb5de04Jeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
99a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
100b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
101b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_CARD_EMULATION = 1;
102b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_ACTIVATION = 2;
103b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
104b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_TARGET_DESELECTED = 4;
105b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    static final int MSG_MOCK_NDEF = 7;
106c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_ACTIVATED = 8;
107c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_DEACTIVATED = 9;
1082c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_APDU_RECEIVED = 10;
1092c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
1102c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_MIFARE_ACCESS = 12;
111b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
11231949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
11331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
11431949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
11531949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_EE_WIPE = 4;
11631949217328bf2357ff044f0d18677fe588c790cNick Pelly
11749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Copied from com.android.nfc_extras to avoid library dependency
11849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Must keep in sync with com.android.nfc_extras
11949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_OFF = 1;
12049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
1217efbf69a37134ccbd86a1f6b4121f16b4a80eaaeNick Pelly
122d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
123d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
124d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
125d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
126d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
12749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_ON_DETECTED =
12849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
12949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_OFF_DETECTED =
13049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
13149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_AID_SELECTED =
13249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.AID_SELECTED";
13349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
13449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
1352c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_APDU_RECEIVED =
1362c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.APDU_RECEIVED";
1372c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_APDU_BYTES =
1382c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.APDU_BYTES";
1392c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1402c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_EMV_CARD_REMOVAL =
1412c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
1422c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1432c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_MIFARE_ACCESS_DETECTED =
1442c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
1452c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_MIFARE_BLOCK =
1462c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.MIFARE_BLOCK";
1472c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
14831949217328bf2357ff044f0d18677fe588c790cNick Pelly    //TODO: dont hardcode this
14931949217328bf2357ff044f0d18677fe588c790cNick Pelly    private static final byte[][] EE_WIPE_APDUS = {
15031949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
15131949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
15231949217328bf2357ff044f0d18677fe588c790cNick Pelly                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
15331949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
15431949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
15531949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
15631949217328bf2357ff044f0d18677fe588c790cNick Pelly                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
15731949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
15831949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
15931949217328bf2357ff044f0d18677fe588c790cNick Pelly    };
16049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
16149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
16249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
1630bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    private NativeNfcSecureElement mSecureElement;
16449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private OpenSecureElement mOpenEe;  // null when EE closed
16549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private int mEeRoutingState;  // contactless interface routing
1660bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
167d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    // fields below must be used only on the UI thread and therefore aren't synchronized
168d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    boolean mP2pStarted = false;
169d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
1702f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
1712f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    private final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
17284e1e0adc2516afd35ebab029a52e764e0490559Jason parks    private HashSet<String> mSePackages = new HashSet<String>();
17331949217328bf2357ff044f0d18677fe588c790cNick Pelly    private boolean mIsScreenUnlocked;
1740b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly    private boolean mIsNdefPushEnabled;
17531949217328bf2357ff044f0d18677fe588c790cNick Pelly
17631949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
17731949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
17831949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
17931949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
1802f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
1812f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
18205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
1834a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
1840e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
1850e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
186533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly    private PowerManager.WakeLock mWakeLock;
187d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
188d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
189d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
190d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
19177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
1924a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
1934a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
1944a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterExtrasService mExtrasService;
19531949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
19631949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
1972ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
19876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
199275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
200d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
201d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    private static NfcService sService;
202d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
20393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceAdminPerm(Context context) {
20493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        int admin = context.checkCallingOrSelfPermission(ADMIN_PERM);
20593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        int nfcee = context.checkCallingOrSelfPermission(NFCEE_ADMIN_PERM);
20693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        if (admin != PackageManager.PERMISSION_GRANTED
20793d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton                && nfcee != PackageManager.PERMISSION_GRANTED) {
20893d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            throw new SecurityException(ADMIN_PERM_ERROR);
20993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        }
21093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
21193d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
21293d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceNfceeAdminPerm(Context context) {
21393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        context.enforceCallingOrSelfPermission(NFCEE_ADMIN_PERM, NFCEE_ADMIN_PERM_ERROR);
21493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
21593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
216d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
217d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
218d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
219f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2200e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
221f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
222f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
223f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
224f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
225f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
226f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
227f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
228d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
229f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationDeselected() {
230f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
231f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
232f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
233f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
234f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
235f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
236d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
237f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationAidSelected(byte[] aid) {
238f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_CARD_EMULATION, aid);
239f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
240f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
241f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
242f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
243f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
244f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
245f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
246f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
247f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
248f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
249f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
250f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
251f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
252d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
253f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
254f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
255f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
256f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
257d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
258f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldActivated() {
259f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
260f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
261f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
262d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
263f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldDeactivated() {
264f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
265f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
266f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
267f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
268442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeApduReceived(byte[] apdu) {
269442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
270442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
271442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
272442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
273442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeEmvCardRemoval() {
274442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
275442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
276442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
277442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
278442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeMifareAccess(byte[] block) {
279442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
280442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
281442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
282442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
2830e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    public void onCreate() {
2842f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        super.onCreate();
2852f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
2864a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
2874a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
288ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly        mExtrasService = new NfcAdapterExtrasService();
2894a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton
2902f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
2912f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
292d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
293d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
2940e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mContext = this;
295f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        mDeviceHost = new NativeNfcManager(this, this);
29674180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
29777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mP2pLinkManager = new P2pLinkManager(mContext);
29877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly        mNfcDispatcher = new NfcDispatcher(this, mP2pLinkManager);
29924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
3000bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        mSecureElement = new NativeNfcSecureElement();
301eab09ad7204fe1f0feaca33efccf75c1bb388708Robert Tsai        mEeRoutingState = ROUTE_OFF;
3020bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
303275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        mPrefs = getSharedPreferences(PREF, Context.MODE_PRIVATE);
3040e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
305f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
30631949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
3070b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
308f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
309275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
310275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
311533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
312275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
31331949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsScreenUnlocked = pm.isScreenOn() && !mKeyguard.isKeyguardLocked();
314533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
315d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
316f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
317eead88c5e2bdd34eb33fdf2c76717f9edb9e0396Jeff Hamilton        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
31865945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_OFF);
31965945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
320bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
321275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
32231949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
323275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        registerReceiver(mReceiver, filter);
324bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
325bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter = new IntentFilter();
326bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
327bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addDataScheme("package");
328bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
329275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        registerReceiver(mReceiver, filter);
3300e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
33131949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
33231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
33331949217328bf2357ff044f0d18677fe588c790cNick Pelly
334d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
335d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
336d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
337d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
338d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mStartSound = mSoundPool.load(this, R.raw.start, 1);
339d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mEndSound = mSoundPool.load(this, R.raw.end, 1);
340d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mErrorSound = mSoundPool.load(this, R.raw.error, 1);
341d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
342d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
343d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
344d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
345d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
346d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
347d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
348d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
349d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
350d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
351d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
352d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
353d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
35431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
35531949217328bf2357ff044f0d18677fe588c790cNick Pelly        final ContentResolver resolver = mContext.getContentResolver();
35631949217328bf2357ff044f0d18677fe588c790cNick Pelly        final String airplaneModeRadios = Settings.System.getString(resolver,
35731949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_RADIOS);
35831949217328bf2357ff044f0d18677fe588c790cNick Pelly        final String toggleableRadios = Settings.System.getString(resolver,
35931949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
36031949217328bf2357ff044f0d18677fe588c790cNick Pelly
36131949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
36231949217328bf2357ff044f0d18677fe588c790cNick Pelly                airplaneModeRadios.contains(Settings.System.RADIO_NFC);
36331949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
36431949217328bf2357ff044f0d18677fe588c790cNick Pelly            toggleableRadios.contains(Settings.System.RADIO_NFC);
36531949217328bf2357ff044f0d18677fe588c790cNick Pelly
36631949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
36731949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
36831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
36931949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
37031949217328bf2357ff044f0d18677fe588c790cNick Pelly
37131949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
37231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
37331949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
37431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
37531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
37631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
37731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
37831949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
37931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
38031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
38131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
38231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
38331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
38431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
38531949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
38631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
38731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
38831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
38931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
39031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
39131949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
39231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
39331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
39431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
39531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
39631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
39731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
39831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * process may temporarily enable the NFC adapter
39931949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
40031949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
40131949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
40231949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
40331949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
40431949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
40531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
40631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
40731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
40831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
40931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
41031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
41131949217328bf2357ff044f0d18677fe588c790cNick Pelly
4124467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
4134467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
4144467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
4154467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
4164467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
4174467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
4184467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
4194467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
4204467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
42131949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
42231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
42331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
42431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
42531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
42631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
42731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
42831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
4290fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    Log.d(TAG,"checking on firmware download");
43031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
43131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            !(mIsAirplaneSensitive && isAirplaneModeOn())) {
4320fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is on. Doing normal stuff");
43331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
4340fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
4350fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is off.  Checking firmware version");
4360fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
43731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
43831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
43931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
44031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
44131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
44231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        executeEeWipe();
44331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
44431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
44531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_EE_WIPE:
44631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    executeEeWipe();
44731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
44831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
449d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
450d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
451d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
45231949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
45331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
45431949217328bf2357ff044f0d18677fe588c790cNick Pelly
45531949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
45631949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
45731949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
45831949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
45931949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
46031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
46131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
46231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
46331949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
46431949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
46531949217328bf2357ff044f0d18677fe588c790cNick Pelly
46631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!mDeviceHost.initialize()) {
46731949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Error enabling NFC");
46831949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_OFF);
46931949217328bf2357ff044f0d18677fe588c790cNick Pelly                return false;
47031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
47131949217328bf2357ff044f0d18677fe588c790cNick Pelly
47231949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized(NfcService.this) {
47331949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
47431949217328bf2357ff044f0d18677fe588c790cNick Pelly
4750b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
47631949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
47731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
47831949217328bf2357ff044f0d18677fe588c790cNick Pelly
479d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
480d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
48131949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
48231949217328bf2357ff044f0d18677fe588c790cNick Pelly            applyRouting();
48331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
48431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
48531949217328bf2357ff044f0d18677fe588c790cNick Pelly
48631949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
48731949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
48831949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
48931949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
49031949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
49131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
49231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
49331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
49431949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
49531949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
49631949217328bf2357ff044f0d18677fe588c790cNick Pelly
49731949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
49831949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
49931949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
50031949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
50131949217328bf2357ff044f0d18677fe588c790cNick Pelly            WatchDogThread watchDog = new WatchDogThread();
50231949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
50331949217328bf2357ff044f0d18677fe588c790cNick Pelly
50477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
50531949217328bf2357ff044f0d18677fe588c790cNick Pelly
50631949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
50731949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
50831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
50931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
51031949217328bf2357ff044f0d18677fe588c790cNick Pelly            applyRouting();
51131949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
51231949217328bf2357ff044f0d18677fe588c790cNick Pelly
5130b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
51431949217328bf2357ff044f0d18677fe588c790cNick Pelly
51531949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
51631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
51731949217328bf2357ff044f0d18677fe588c790cNick Pelly
51831949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
51931949217328bf2357ff044f0d18677fe588c790cNick Pelly
52031949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_OFF);
52131949217328bf2357ff044f0d18677fe588c790cNick Pelly
522d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
523d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
52431949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
52531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
52631949217328bf2357ff044f0d18677fe588c790cNick Pelly
52731949217328bf2357ff044f0d18677fe588c790cNick Pelly        void executeEeWipe() {
52831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // TODO: read SE reset list from /system/etc
52931949217328bf2357ff044f0d18677fe588c790cNick Pelly            byte[][]apdus = EE_WIPE_APDUS;
53031949217328bf2357ff044f0d18677fe588c790cNick Pelly
53131949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
53231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (tempEnable) {
53331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!enableInternal()) {
534ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
53531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
536f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
537f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
53831949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Executing SE wipe");
53931949217328bf2357ff044f0d18677fe588c790cNick Pelly            int handle = mSecureElement.doOpenSecureElementConnection();
54031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (handle == 0) {
54131949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Could not open the secure element");
54231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (tempEnable) {
54331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
54431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
54531949217328bf2357ff044f0d18677fe588c790cNick Pelly                return;
54631949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
54731949217328bf2357ff044f0d18677fe588c790cNick Pelly
54831949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
54931949217328bf2357ff044f0d18677fe588c790cNick Pelly
55031949217328bf2357ff044f0d18677fe588c790cNick Pelly            for (byte[] cmd : apdus) {
551ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                byte[] resp = mSecureElement.doTransceive(handle, cmd);
552ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                if (resp == null) {
553ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
554ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    break;
555ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                }
55631949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
55731949217328bf2357ff044f0d18677fe588c790cNick Pelly
55831949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.resetTimeouts();
55931949217328bf2357ff044f0d18677fe588c790cNick Pelly            mSecureElement.doDisconnect(handle);
56031949217328bf2357ff044f0d18677fe588c790cNick Pelly
56131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (tempEnable) {
56231949217328bf2357ff044f0d18677fe588c790cNick Pelly                disableInternal();
56331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
56431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
56531949217328bf2357ff044f0d18677fe588c790cNick Pelly
56631949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
56731949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (this) {
56831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
56931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
57031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
57131949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
57231949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
57331949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
57431949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
57531949217328bf2357ff044f0d18677fe588c790cNick Pelly                mContext.sendBroadcast(intent);
57631949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
57731949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
57831949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
57931949217328bf2357ff044f0d18677fe588c790cNick Pelly
58031949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
58131949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
58231949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
58331949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
58431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
5850e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
5860e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
587d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
588d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
589d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
590d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
591d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
592d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
593d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
594d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
595d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
596d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
597d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
598d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
599d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
600d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
601d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
602d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
603d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
604d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
605d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
606d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
6070e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
6082f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    public void onTerminate() {
6092f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        super.onTerminate();
6102f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        // NFC application is persistent, it should not be destroyed by framework
6110e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        Log.wtf(TAG, "NFC service is under attack!");
6120e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
6130e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
6144a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
615fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
6160e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
61793d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
6180e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
61931949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
62031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
62131949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.i(TAG, "denying enable() request (airplane mode)");
62231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return false;
623f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
62431949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
62531949217328bf2357ff044f0d18677fe588c790cNick Pelly
62631949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
627f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
628f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
629fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
6300e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean disable() throws RemoteException {
63193d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
6320e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
63331949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(false);
63431949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
63531949217328bf2357ff044f0d18677fe588c790cNick Pelly
63631949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
637f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
638f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
639fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
6400b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
64131949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
6420b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return mIsNdefPushEnabled;
64331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
644d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
645d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
646d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
6470b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
648d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
649d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
6500b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
65131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
65231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
6530b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
6540b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
65531949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
6560b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
65731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
65877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
659d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
660d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
661d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
662d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
663d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
664d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
6650b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
666d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
667d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
6680b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
66931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
67031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
6710b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
6720b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
67331949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
6740b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
67531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
67677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
677d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
678d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
679d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
680d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
681d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
682d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
6830b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
68424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
68505973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
686a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
6870b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
6880b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
6890b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
6900b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
691ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
692a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
693a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
694a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
695a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
696a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
697a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
698a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
699a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
700a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
701a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
702a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
703a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
704a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
705a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
70624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
70724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
70824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
70924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
71024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
71149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
7120b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
7132094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
7142094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
7152094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
7160b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundNdefPush(NdefMessage msg, INdefPushCallback callback) {
717ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
7180b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mP2pLinkManager.setNdefToSend(msg, callback);
719ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
720ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
721ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
7220e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
723d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
7240e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
7250e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
7260e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
727fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
72849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public INfcAdapterExtras getNfcAdapterExtrasInterface() {
72993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
73049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mExtrasService;
7310bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
7320bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
733fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
73431949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
73531949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
73631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
73731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
73831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
73931949217328bf2357ff044f0d18677fe588c790cNick Pelly
74031949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
74131949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
74231949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
7430e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
7440e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    };
7450e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
7464a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
747fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
748f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
749d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
750bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
751f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
752f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
75331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
754f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
755f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
756f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
757f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
758f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
759f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
760b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
761b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
76221545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
763b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
764f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
765f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
76649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            applyRouting();
767f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
768f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
769f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
770fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
771ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
772d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
773bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
774f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
775f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
77631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
777f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
778f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
779f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
780f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
781f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
782b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
783b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
784f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
785ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
7861b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen            if (technology == TagTechnology.NFC_B) {
7871b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen                return ErrorCodes.ERROR_NOT_SUPPORTED;
7881b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen            }
7891b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen
790ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
791ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
792ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
793ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
794ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
795ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
796ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
797ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
798f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
799f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
800fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
801aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
802aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
803aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
804f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
805aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
806aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
80731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
808aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
809aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
810aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
811aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
812f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
813aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
814aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
815aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
816aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
817aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
818aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
819aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
820aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
821aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
822aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
823aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
824b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
825d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
826bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
827f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
82831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
829f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
830f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
831f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
832f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
833f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
834f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
835b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
836f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
837f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
838f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
839f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
840fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
841f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public byte[] getUid(int nativeHandle) throws RemoteException {
842f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
843f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] uid;
844f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
845f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
84631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
847f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
848f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
849f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
850f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
851f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
852f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
853f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                uid = tag.getUid();
854f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return uid;
855f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
856f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
857f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
858f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
859fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
860b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
861f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
862b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
863b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
86431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
865b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
866b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
867b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
868b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
869f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
870b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
871b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
872b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
873b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
874ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
875b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
876b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
877fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
878f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
879f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
880f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
881f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
88231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
8832c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
884f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
885f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
886f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
887f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
8883ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
8892c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
8902c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
891f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
89270bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
893f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
894f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
895fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
8969d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
89797c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
898d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
899bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
900f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
901f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
902f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
903f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
90431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
905f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
906f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
907f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
908f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
909f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
910f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
911bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
912bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
913bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
914bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
9159d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
9169d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
917bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
918bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
919bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
920bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
921bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
922bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
923bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
924bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
925bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
926f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
927f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
928f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
929f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
930fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9313fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
932d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
933bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
934f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
935f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
936f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
93731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
938f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
939f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
940f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
941f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
942f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
943f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
944f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
945f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
946f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
947f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
948f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
949f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
950f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
951f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
952f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
953f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
954f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
955f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
956f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
957f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
958f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
959fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9603fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
961d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
962bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
963f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
964f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
965f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
96631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
967f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
968f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
969f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
970f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
971f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
972f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
973f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
974f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
975f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
976f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
977f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
978f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
979f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
980f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
981f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
982f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
983f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
984fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
985f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int getLastError(int nativeHandle) throws RemoteException {
986f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            return(mDeviceHost.doGetLastError());
987f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
988f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
989fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9903fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
9913fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
992f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
993f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
994fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9953fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
99603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
99703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
998f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
99903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
100003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
100131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
100203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
100303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
100403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
100503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1006f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
100703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
100803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
100903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
101003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1011f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
101203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1013f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
101403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
101503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1016f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1017f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
10180aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
10190aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
10200aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
10210aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1022f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
10230aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10240aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
102531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
10260aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
10270aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10280aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10290aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1030f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
10310aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
10320aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
10330aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10340aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10350aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
10360aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1037f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
10380aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
10390aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10400aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
10410aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10421b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
10433fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
10443fb14d0868594c78a777e805545209636814e223Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
10453fb14d0868594c78a777e805545209636814e223Martijn Coenen
1046f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
10473fb14d0868594c78a777e805545209636814e223Martijn Coenen
10483fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
104931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
10503fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
10513fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
10523fb14d0868594c78a777e805545209636814e223Martijn Coenen
10533fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1054f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
10553fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
10563fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
10573fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
10583fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
10593fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
10603fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
10613fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
10623fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
10633fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
10643fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
10653fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1066f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                NdefMessage[] msgs = tag.findAndReadNdef();
10673fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
10683fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
10694a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
10703fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
10713fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
10723fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
10733fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
10743fb14d0868594c78a777e805545209636814e223Martijn Coenen
10751b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1076fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
10771b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1078f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1079fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1080fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1081fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1082fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1083fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1084dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1085dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1086dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1087358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
1088358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1089358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1090358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1091358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1092358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1093358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1094dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
1095dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1096dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1097f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
10981b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1099bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1100bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1101bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1102bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1103bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1104bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1105bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1106bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1107bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1108bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1109bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1110bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1111bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1112bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
11130e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    };
1114f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1115dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    private void _nfcEeClose(boolean checkPid, int callingPid) throws IOException {
1116dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // Blocks until a pending open() or transceive() times out.
1117dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        //TODO: This is incorrect behavior - the close should interrupt pending
1118dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // operations. However this is not supported by current hardware.
1119dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1120dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        synchronized(NfcService.this) {
112131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1122dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC adapter is disabled");
1123dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1124dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (mOpenEe == null) {
1125dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC EE closed");
1126dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1127dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (checkPid && mOpenEe.pid != -1 && callingPid != mOpenEe.pid) {
1128dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new SecurityException("Wrong PID");
1129dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1130dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1131f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
1132dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mSecureElement.doDisconnect(mOpenEe.handle);
1133dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mOpenEe = null;
1134dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1135dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            applyRouting();
1136dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        }
1137dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    }
1138dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
11394a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
114049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeNoException() {
114149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
114249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", 0);
114349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
114449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
114549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeIoException(IOException e) {
114649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
114749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", -1);
114849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putString("m", e.getMessage());
114949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
115049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
11510bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1152bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
115349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public Bundle open(IBinder b) throws RemoteException {
115493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
1155bd555ee64250126b60b24814120a2049943920caNick Pelly
115649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
115749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
115849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                _open(b);
115949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
116049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
116149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
11620bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
116349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
116449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
11650bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
116649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private void _open(IBinder b) throws IOException, RemoteException {
116749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
116831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
116949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC adapter is disabled");
117049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
117149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe != null) {
117249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE already open");
117349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
11740bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
117549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                int handle = mSecureElement.doOpenSecureElementConnection();
117649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (handle == 0) {
117749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE failed to open");
117849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
1179f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
1180ba6401757f8017faeb77423f2d08fd51be1d1051Nick Pelly
118149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                mOpenEe = new OpenSecureElement(getCallingPid(), handle);
118249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                try {
118349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    b.linkToDeath(mOpenEe, 0);
118449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                } catch (RemoteException e) {
118549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    mOpenEe.binderDied();
118649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
118784e1e0adc2516afd35ebab029a52e764e0490559Jason parks
118884e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // Add the calling package to the list of packages that have accessed
118984e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // the secure element.
119084e1e0adc2516afd35ebab029a52e764e0490559Jason parks                for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) {
119184e1e0adc2516afd35ebab029a52e764e0490559Jason parks                    mSePackages.add(packageName);
119284e1e0adc2516afd35ebab029a52e764e0490559Jason parks                }
119349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly           }
11940bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
11950bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1196bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
119749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public Bundle close() throws RemoteException {
119893d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
11990bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
120049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
120149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
1202dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                _nfcEeClose(true, getCallingPid());
120349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
120449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
120549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
12060bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
120749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
120849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
12090bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1210bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
121149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public Bundle transceive(byte[] in) throws RemoteException {
121293d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
1213bd555ee64250126b60b24814120a2049943920caNick Pelly
121449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
121549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            byte[] out;
121649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
121749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                out = _transceive(in);
121849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
121949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result.putByteArray("out", out);
122049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
122149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
12220bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
122349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
122449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
12250bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
122649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private byte[] _transceive(byte[] data) throws IOException, RemoteException {
122749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
122831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
122949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC is not enabled");
123049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
123149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe == null){
123249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE is not open");
123349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
123449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (getCallingPid() != mOpenEe.pid) {
123549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new SecurityException("Wrong PID");
123649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
12370bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
12380bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
123949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mSecureElement.doTransceive(mOpenEe.handle, data);
12400bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
12410bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1242bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
124349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int getCardEmulationRoute() throws RemoteException {
124493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
124549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mEeRoutingState;
12460bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
12470bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1248bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
124949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void setCardEmulationRoute(int route) throws RemoteException {
125093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
125149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            mEeRoutingState = route;
125249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            applyRouting();
12530bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
1254bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
1255bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
12565a8844da9bc569aa7289426bf7b96e7eef90abf5Nick Pelly        public void authenticate(byte[] token) throws RemoteException {
1257bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            NfcService.enforceNfceeAdminPerm(mContext);
1258bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
12590bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    };
12600bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
126149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** resources kept while secure element is open */
126249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private class OpenSecureElement implements IBinder.DeathRecipient {
126349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int pid;  // pid that opened SE
126449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int handle; // low-level handle
126549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public OpenSecureElement(int pid, int handle) {
126649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.pid = pid;
126749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.handle = handle;
126849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1269bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
127049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void binderDied() {
127149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized (NfcService.this) {
127249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (DBG) Log.d(TAG, "Tracked app " + pid + " died");
127349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                pid = -1;
12740bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas                try {
1275dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                    _nfcEeClose(false, -1);
1276dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                } catch (IOException e) { /* already closed */ }
12770bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
12780bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
12790bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    }
12800bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
128131949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
128231949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
128331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1284e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1285aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1286aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
128731949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
12882edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        boolean mWatchDogCanceled = false;
12892edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
12902edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
12912edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            boolean slept = false;
12922edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            while (!slept) {
12932edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                try {
12942edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    Thread.sleep(10000);
12952edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    slept = true;
12962edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                } catch (InterruptedException e) { }
12972edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
12982edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            synchronized (this) {
12992edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                if (!mWatchDogCanceled) {
13002edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    // Trigger watch-dog
13012edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    Log.e(TAG, "Watch dog triggered");
13022083287b83a587d8f6e9ad829ea18041dc17d842Nick Pelly                    mDeviceHost.doAbort();
13032edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
13042edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
13052edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
13062edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
13072edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            mWatchDogCanceled = true;
13082edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
13092edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
13102edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
131149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** apply NFC discovery and EE routing */
1312e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton    void applyRouting() {
1313e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
1314e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            if (!isNfcEnabled() || mOpenEe != null) {
1315e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1316e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1317e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            if (mIsScreenUnlocked) {
1318e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1319e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                    Log.d(TAG, "NFC-EE routing ON");
1320e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                    mDeviceHost.doSelectSecureElement();
1321e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                } else {
1322e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                    Log.d(TAG, "NFC-EE routing OFF");
1323e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                    mDeviceHost.doDeselectSecureElement();
1324e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                }
1325e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                Log.d(TAG, "NFC-C polling ON");
1326e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                mDeviceHost.enableDiscovery();
1327221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            } else {
132849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                Log.d(TAG, "NFC-EE routing OFF");
1329f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                mDeviceHost.doDeselectSecureElement();
1330e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                Log.d(TAG, "NFC-C polling OFF");
1331e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                mDeviceHost.disableDiscovery();
1332221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
133365945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
133465945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
133565945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
13362436ffe91853535fad87b7a8e03d8883bae20f20Arnaud Ferir    /** Disconnect any target if present */
133731949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
133831949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (!isNfcEnabled()) {
1339a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1340a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
134131949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
134231949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
134331949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
134431949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
134531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
134631949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
134731949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
134831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
134931949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
135031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
135131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
135231949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
135331949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
135431949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
135531949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
135631949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
135731949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
135831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
135931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
136031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
136131949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
136231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
136331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1364bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1365bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1366bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1367bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1368bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
136931949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
137031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
137131949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
137231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
137331949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
13742f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
137531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
13760e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1377f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1378f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
137931949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
138031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
138131949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1382f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1383b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1384b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
138531949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
138631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
138731949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
138831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
1389f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1390f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1391d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
13924a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
13934a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton            throws IOException, LlcpException {
13944a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1395d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1396d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1397d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
13984a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
13994a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton            int linearBufferLength) throws IOException, LlcpException {
14004a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1401d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1402d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
140357d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
1404b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
140557d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
140657d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
1407b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
1408b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
1409b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
1410b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
1411b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
1412b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1413b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
14143fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
1415b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
1416b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
141731949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
141831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
141931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
142031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
142131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
142231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
142331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
142431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
142531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
142631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new int[] { TagTechnology.NDEF },
142731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new Bundle[] { extras });
142831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
142931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
143031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean delivered = mNfcDispatcher.dispatchTag(tag,
143131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new NdefMessage[] { ndefMsg });
143231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (delivered) {
1433d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
143477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    } else {
1435d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
143631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
143731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
143831949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
143957d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
144031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
144131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
144231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
1443d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    playSound(SOUND_START);
144431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage[] ndefMsgs = tag.findAndReadNdef();
1445c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
144631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (ndefMsgs != null) {
144731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        tag.startPresenceChecking();
144831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        dispatchTagEndpoint(tag, ndefMsgs);
144931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
145031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
145131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.startPresenceChecking();
145231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            dispatchTagEndpoint(tag, null);
145331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
145431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
1455d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
145631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
145731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
145831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
145931949217328bf2357ff044f0d18677fe588c790cNick Pelly
146031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_CARD_EMULATION:
146131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Emulation message");
146231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] aid = (byte[]) msg.obj;
146331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
146431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent aidIntent = new Intent();
146531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.setAction(ACTION_AID_SELECTED);
146631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.putExtra(EXTRA_AID, aid);
146731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
146814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(aidIntent);
146931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
147031949217328bf2357ff044f0d18677fe588c790cNick Pelly
147131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_EMV_CARD_REMOVAL:
147231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Removal message");
147331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
147431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent cardRemovalIntent = new Intent();
147531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
147631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
147714a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(cardRemovalIntent);
147831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
147931949217328bf2357ff044f0d18677fe588c790cNick Pelly
148031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_APDU_RECEIVED:
148131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "APDU Received message");
148231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] apduBytes = (byte[]) msg.obj;
148331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
148431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent apduReceivedIntent = new Intent();
148531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
148631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (apduBytes != null && apduBytes.length > 0) {
148731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
148831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
148931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
149014a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(apduReceivedIntent);
149131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
149231949217328bf2357ff044f0d18677fe588c790cNick Pelly
149331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_MIFARE_ACCESS:
149431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "MIFARE access message");
149531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
149631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] mifareCmd = (byte[]) msg.obj;
149731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent mifareAccessIntent = new Intent();
149831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
149931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mifareCmd != null && mifareCmd.length > 1) {
150031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        int mifareBlock = mifareCmd[1] & 0xff;
150131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
150231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
150331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
150431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
150514a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(mifareAccessIntent);
150631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
1507c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
150831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
150931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
151031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
151131949217328bf2357ff044f0d18677fe588c790cNick Pelly
151231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
151331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
151431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
151531949217328bf2357ff044f0d18677fe588c790cNick Pelly
151631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
151731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
151831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
151931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
152031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
152131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
152231949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
152331949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
152431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
152531949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
152631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
152731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
152831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
152931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
153031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
153131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
153231949217328bf2357ff044f0d18677fe588c790cNick Pelly
153377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
153431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
153531949217328bf2357ff044f0d18677fe588c790cNick Pelly
153631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_TARGET_DESELECTED:
153731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Broadcast Intent Target Deselected */
153831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Target Deselected");
153931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent intent = new Intent();
154031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
154131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting Intent");
154231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
154331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
154431949217328bf2357ff044f0d18677fe588c790cNick Pelly
154531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_ACTIVATED: {
154631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
154731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOnIntent = new Intent();
154831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
154914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOnIntent);
155031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
155131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
155231949217328bf2357ff044f0d18677fe588c790cNick Pelly
155331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_DEACTIVATED: {
155431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
155531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOffIntent = new Intent();
155631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
155714a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOffIntent);
155831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
155931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
156031949217328bf2357ff044f0d18677fe588c790cNick Pelly
156131949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
156231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
156331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
156431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
1565b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1566d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
156714a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        private void sendSeBroadcast(Intent intent) {
15688e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly            mNfcDispatcher.resumeAppSwitches();
156914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
157014a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton            mContext.sendBroadcast(intent, NFCEE_ADMIN_PERM);
157114a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        }
157214a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton
1573d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
1574d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
1575d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1576d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1577d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1578d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
1579d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
1580d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
1581d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
1582d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
1583d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
158431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            boolean isZeroClickOn;
158531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
158631949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
158731949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
1588d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
158977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                            mP2pLinkManager.onLlcpActivated();
1590d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
1591d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
1592d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
1593d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1594d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
1595d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
1596d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
1597d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1598d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
1599d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1600d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1601d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1602d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
1603d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
1604d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
1605d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
1606d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1607d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1608d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1609d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
1610d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
1611d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
1612d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
1613d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
161431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        boolean isZeroClickOn;
161531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
161631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
161731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
1618d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
161977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
1620d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
1621d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1622d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1623d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
1624d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1625d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
1626d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1627d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
1628d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
1629d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1630f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, NdefMessage[] msgs) {
1631f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
1632f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
1633f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
163476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly            if (!mNfcDispatcher.dispatchTag(tag, msgs)) {
1635f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
1636d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
1637d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else {
1638d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
16393fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
16403fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
1641b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
1642b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1643b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
164449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
164531949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableDiscoveryTask extends AsyncTask<Boolean, Void, Void> {
1646fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1647275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        protected Void doInBackground(Boolean... params) {
1648275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks            if (DBG) Log.d(TAG, "EnableDisableDiscoveryTask: enable = " + params[0]);
1649275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
1650275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks            if (params != null && params.length > 0 && params[0]) {
1651161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                synchronized (NfcService.this) {
165231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (!mIsScreenUnlocked) {
165331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mIsScreenUnlocked = true;
1654275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                        applyRouting();
1655275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                    } else {
1656275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                        if (DBG) Log.d(TAG, "Ignoring enable request");
1657275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                    }
1658161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
16597c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            } else {
1660533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly                mWakeLock.acquire();
1661161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                synchronized (NfcService.this) {
166231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mIsScreenUnlocked) {
166331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mIsScreenUnlocked = false;
1664e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton//                        applyRouting();
1665e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                        /*
1666e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                         * TODO undo this after the LLCP stack is fixed.
1667e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                         * This is done locally here since the LLCP stack is still using
1668e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                         * globals without holding any locks, and if we attempt to change
1669e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                         * the NFCEE routing while the target is still connected (and it's
1670e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                         * a P2P target) the async LLCP callbacks will crash since the routing
1671e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                         * manipulation code is overwriting globals it relies on. This hack should
1672e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                         * be removed when the LLCP stack is fixed.
1673e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                         */
16747bbabb2deebbc498c635f690c5283201da549247Martijn Coenen                        if (isNfcEnabled() && mOpenEe == null) {
16757bbabb2deebbc498c635f690c5283201da549247Martijn Coenen                            Log.d(TAG, "NFC-C polling OFF");
16767bbabb2deebbc498c635f690c5283201da549247Martijn Coenen                            mDeviceHost.disableDiscovery();
16777bbabb2deebbc498c635f690c5283201da549247Martijn Coenen                            maybeDisconnectTarget();
1678e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                            Log.d(TAG, "NFC-EE routing OFF");
1679e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                            mDeviceHost.doDeselectSecureElement();
1680e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                        }
1681275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                    } else {
1682275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                        if (DBG) Log.d(TAG, "Ignoring disable request");
1683275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                    }
1684161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
1685533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly                mWakeLock.release();
16867c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
16877c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            return null;
16887c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
16897c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
16907c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
16910e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
16920e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        @Override
16930e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public void onReceive(Context context, Intent intent) {
169431949217328bf2357ff044f0d18677fe588c790cNick Pelly            String action = intent.getAction();
169531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (action.equals(
1696f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
1697ef92efa7fd86d75cc35465b84e8740f941ff0f0aJeff Hamilton                if (DBG) Log.d(TAG, "INERNAL_TARGET_DESELECTED_ACTION");
16980e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
1699f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Restart polling loop for notification */
170049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                applyRouting();
1701f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
170231949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1703275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                // Only enable if the screen is unlocked. If the screen is locked
1704275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                // Intent.ACTION_USER_PRESENT will be broadcast when the screen is
1705275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                // unlocked.
170636a1e42f1811692fb734bc5f015e294eab0bed4cJeff Hamilton                boolean enable = !mKeyguard.isKeyguardLocked();
1707275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
17086ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                // Perform discovery enable in thread to protect against ANR when the
17096ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                // NFC stack wedges. This is *not* the correct way to fix this issue -
17106ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                // configuration of the local NFC adapter should be very quick and should
17116ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                // be safe on the main thread, and the NFC stack should not wedge.
1712275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                new EnableDisableDiscoveryTask().execute(enable);
171331949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
17147c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly                // Perform discovery disable in thread to protect against ANR when the
17157c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly                // NFC stack wedges. This is *not* the correct way to fix this issue -
17167c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly                // configuration of the local NFC adapter should be very quick and should
17177c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly                // be safe on the main thread, and the NFC stack should not wedge.
1718275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                new EnableDisableDiscoveryTask().execute(Boolean.FALSE);
171931949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1720275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                // The user has unlocked the screen. Enabled!
1721275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                new EnableDisableDiscoveryTask().execute(Boolean.TRUE);
172231949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
172331949217328bf2357ff044f0d18677fe588c790cNick Pelly                EnableDisableTask eeWipeTask = new EnableDisableTask();
172431949217328bf2357ff044f0d18677fe588c790cNick Pelly                eeWipeTask.execute(TASK_EE_WIPE);
172531949217328bf2357ff044f0d18677fe588c790cNick Pelly                try {
172631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eeWipeTask.get();  // blocks until EE wipe is complete
172731949217328bf2357ff044f0d18677fe588c790cNick Pelly                } catch (ExecutionException e) {
172831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.w(TAG, "failed to wipe NFC-EE");
172931949217328bf2357ff044f0d18677fe588c790cNick Pelly                } catch (InterruptedException e) {
173031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.w(TAG, "failed to wipe NFC-EE");
173131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
173231949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
17337a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
17347a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                if (dataRemoved) {
17357a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                    Uri data = intent.getData();
17367a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                    if (data == null) return;
17377a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                    String packageName = data.getSchemeSpecificPart();
17387a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton
17397a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                    synchronized (NfcService.this) {
174084e1e0adc2516afd35ebab029a52e764e0490559Jason parks                        if (mSePackages.contains(packageName)) {
174131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new EnableDisableTask().execute(TASK_EE_WIPE);
174284e1e0adc2516afd35ebab029a52e764e0490559Jason parks                            mSePackages.remove(packageName);
17437a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                        }
1744bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                    }
1745bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
174631949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
174731949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
174831949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
174931949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
175031949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
175131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
175231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
175331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
175431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
175531949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
175631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
175731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
175831949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
175931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
176031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
1761f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1762f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1763f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
176431949217328bf2357ff044f0d18677fe588c790cNick Pelly
176531949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** Returns true if airplane mode is currently on */
176631949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
176731949217328bf2357ff044f0d18677fe588c790cNick Pelly        return Settings.System.getInt(mContext.getContentResolver(),
176831949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
176931949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
177031949217328bf2357ff044f0d18677fe588c790cNick Pelly
177131949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** for debugging only - no il8n */
177231949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
177331949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
177431949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
177531949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
177631949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
177731949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
177831949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
177931949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
178031949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
178131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
178231949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
178331949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
178431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
178531949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
178631949217328bf2357ff044f0d18677fe588c790cNick Pelly
178731949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
178850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
178950effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
179050effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
179150effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
179250effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
179350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
179450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
179550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
179631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
179731949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
17980b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
179931949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsScreenUnlocked=" + mIsScreenUnlocked);
180031949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
180131949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
180277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
180356f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
180431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
180531949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
180674180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
1807