NfcService.java revision d1936808c5f37f97fdb876836194ecbfe1cdfff5
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;
30d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.app.Notification;
31d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.app.NotificationManager;
3205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamiltonimport android.app.PendingIntent;
3313d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.BroadcastReceiver;
3405973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamiltonimport android.content.ComponentName;
3531949217328bf2357ff044f0d18677fe588c790cNick Pellyimport android.content.ContentResolver;
3613d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Context;
3713d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Intent;
3813d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.IntentFilter;
390e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.content.SharedPreferences;
4093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamiltonimport android.content.pm.PackageManager;
41d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.AudioManager;
42d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.SoundPool;
433fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamiltonimport android.net.Uri;
44f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.ErrorCodes;
45f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.FormatException;
462094515fca0cfa0ac87e9cc260d3953d416afe3eJason parksimport android.nfc.INdefPushCallback;
470e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.INfcAdapter;
4849d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.nfc.INfcAdapterExtras;
49f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.INfcTag;
50f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NdefMessage;
51f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NfcAdapter;
520e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.Tag;
5324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.nfc.TechListParcel;
549d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenenimport android.nfc.TransceiveResult;
55aca0d055a82da850c27f6872405602ad5f3fee7bJeff Hamiltonimport android.nfc.tech.Ndef;
5681c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport android.nfc.tech.TagTechnology;
577c034a7fe7d36b1ab039af2c44717812ea02657eNick Pellyimport android.os.AsyncTask;
58b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamiltonimport android.os.Bundle;
59b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Handler;
6049d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.os.IBinder;
61b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Message;
62533043d1003de2f6a20a29201100d94c3c7bc9caNick Pellyimport android.os.PowerManager;
634467dca5650a170af5020c10a8ccb25f86f1007fNick Pellyimport android.os.Process;
64f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.os.RemoteException;
6513d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.os.ServiceManager;
66d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.provider.Settings;
67f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.util.Log;
68f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
6931949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.FileDescriptor;
7057d376f1ee1a3939977b95759525585abb9601fbJeff Hamiltonimport java.io.IOException;
7131949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.PrintWriter;
7231949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.Arrays;
733ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamiltonimport java.util.HashMap;
7484e1e0adc2516afd35ebab029a52e764e0490559Jason parksimport java.util.HashSet;
7531949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.concurrent.ExecutionException;
763ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
77d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamiltoninterface P2pStatusListener {
78d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    void onP2pBegin();
79d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    void onP2pEnd();
80d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    void onP2pError();
81d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton}
82d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
83d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamiltonpublic class NfcService extends Application implements DeviceHostListener, P2pStatusListener {
84bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
85bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
868d6a8dce6706c6c6b3158101f2f3e94a1e0ad946Ben Dodson    static final boolean DBG = true;
8776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
88fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
89d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
90fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
91bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM = android.Manifest.permission.NFC;
92bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM_ERROR = "NFC permission required";
93bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
94bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
95a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly    private static final String NFCEE_ADMIN_PERM = "com.android.nfc.permission.NFCEE_ADMIN";
9693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    private static final String NFCEE_ADMIN_PERM_ERROR = "NFCEE_ADMIN permission required";
97bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
98225ae2587712b06a354b4ad4625aadc780fa4e80Martijn Coenen    /*package*/ static final String PREF = "NfcServicePrefs";
99f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1000e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private static final String PREF_NFC_ON = "nfc_on";
1010e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private static final boolean NFC_ON_DEFAULT = true;
102d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen    private static final String PREF_ZEROCLICK_ON = "zeroclick_on";
103d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen    private static final boolean ZEROCLICK_ON_DEFAULT = true;
104f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
105a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly    private static final String PREF_FIRST_BOOT = "first_boot";
106d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen    private static final String PREF_FIRST_SHARE = "first_share";
107d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen
108d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen    private static final int NOTIFICATION_FIRST_SHARE = 0;
109a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
110b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
111b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_CARD_EMULATION = 1;
112b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_ACTIVATION = 2;
113b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
114b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_TARGET_DESELECTED = 4;
115b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    static final int MSG_MOCK_NDEF = 7;
116c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_ACTIVATED = 8;
117c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_DEACTIVATED = 9;
1182c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_APDU_RECEIVED = 10;
1192c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
1202c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_MIFARE_ACCESS = 12;
121b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
12231949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
12331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
12431949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
12531949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_EE_WIPE = 4;
12631949217328bf2357ff044f0d18677fe588c790cNick Pelly
12749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Copied from com.android.nfc_extras to avoid library dependency
12849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Must keep in sync with com.android.nfc_extras
12949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_OFF = 1;
13049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
1317efbf69a37134ccbd86a1f6b4121f16b4a80eaaeNick Pelly
13249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_ON_DETECTED =
13349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
13449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_OFF_DETECTED =
13549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
13649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_AID_SELECTED =
13749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.AID_SELECTED";
13849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
13949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
1402c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_APDU_RECEIVED =
1412c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.APDU_RECEIVED";
1422c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_APDU_BYTES =
1432c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.APDU_BYTES";
1442c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1452c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_EMV_CARD_REMOVAL =
1462c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
1472c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1482c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_MIFARE_ACCESS_DETECTED =
1492c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
1502c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_MIFARE_BLOCK =
1512c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.MIFARE_BLOCK";
1522c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
15331949217328bf2357ff044f0d18677fe588c790cNick Pelly    //TODO: dont hardcode this
15431949217328bf2357ff044f0d18677fe588c790cNick Pelly    private static final byte[][] EE_WIPE_APDUS = {
15531949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
15631949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
15731949217328bf2357ff044f0d18677fe588c790cNick Pelly                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
15831949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
15931949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
16031949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
16131949217328bf2357ff044f0d18677fe588c790cNick Pelly                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
16231949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
16331949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
16431949217328bf2357ff044f0d18677fe588c790cNick Pelly    };
16549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
16649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
16749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
1680bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    private NativeNfcSecureElement mSecureElement;
16949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private OpenSecureElement mOpenEe;  // null when EE closed
17049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private int mEeRoutingState;  // contactless interface routing
1710bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
172d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    // fields below must be used only on the UI thread and therefore aren't synchronized
173d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    boolean mP2pStarted = false;
174d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
1752f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
1762f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    private final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
17784e1e0adc2516afd35ebab029a52e764e0490559Jason parks    private HashSet<String> mSePackages = new HashSet<String>();
17831949217328bf2357ff044f0d18677fe588c790cNick Pelly    private boolean mIsScreenUnlocked;
17931949217328bf2357ff044f0d18677fe588c790cNick Pelly    private boolean mIsZeroClickRequested;
18031949217328bf2357ff044f0d18677fe588c790cNick Pelly
18131949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
18231949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
18331949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
18431949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
1852f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
1862f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
18705973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
1884a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
1890e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
1900e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
191533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly    private PowerManager.WakeLock mWakeLock;
192d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen    private NotificationManager mNotificationManager;
1932ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson    NdefP2pManager mP2pManager;
194d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
195d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
196d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
197d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
1984a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
1994a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
2004a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterExtrasService mExtrasService;
20131949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
20231949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
2032ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
20476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
205275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
206d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
207d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    private static NfcService sService;
208d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
20993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceAdminPerm(Context context) {
21093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        int admin = context.checkCallingOrSelfPermission(ADMIN_PERM);
21193d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        int nfcee = context.checkCallingOrSelfPermission(NFCEE_ADMIN_PERM);
21293d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        if (admin != PackageManager.PERMISSION_GRANTED
21393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton                && nfcee != PackageManager.PERMISSION_GRANTED) {
21493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            throw new SecurityException(ADMIN_PERM_ERROR);
21593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        }
21693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
21793d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
21893d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceNfceeAdminPerm(Context context) {
21993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton        context.enforceCallingOrSelfPermission(NFCEE_ADMIN_PERM, NFCEE_ADMIN_PERM_ERROR);
22093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
22193d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
222d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
223d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
224d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
225f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2260e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
227f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
228f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
229f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
230f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
231f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
232f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
233f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
234d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
235f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationDeselected() {
236f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
237f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
238f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
239f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
240f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
241f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
242d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
243f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationAidSelected(byte[] aid) {
244f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_CARD_EMULATION, aid);
245f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
246f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
247f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
248f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
249f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
250f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
251f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
252f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
253f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
254f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
255f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
256f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
257f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
258d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
259f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
260f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
261f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
262f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
263d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
264f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldActivated() {
265f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
266f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
267f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
268d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
269f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldDeactivated() {
270f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
271f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
272f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
273f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
274442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeApduReceived(byte[] apdu) {
275442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
276442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
277442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
278442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
279442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeEmvCardRemoval() {
280442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
281442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
282442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
283442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
284442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeMifareAccess(byte[] block) {
285442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
286442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
287442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
288442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
2890e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    public void onCreate() {
2902f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        super.onCreate();
2912f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
2924a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
2934a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
294ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly        mExtrasService = new NfcAdapterExtrasService();
2954a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton
2962f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
2972f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
298d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
299d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
300d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
301d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        mStartSound = mSoundPool.load(this, R.raw.start, 1);
302d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        mEndSound = mSoundPool.load(this, R.raw.end, 1);
303d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        mErrorSound = mSoundPool.load(this, R.raw.error, 1);
304d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
3050e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mContext = this;
306f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        mDeviceHost = new NativeNfcManager(this, this);
30774180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
308d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton        mP2pManager = new NdefP2pManager(this, this);
3092ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson        mNfcDispatcher = new NfcDispatcher(this, mP2pManager);
31024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
3110bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        mSecureElement = new NativeNfcSecureElement();
312eab09ad7204fe1f0feaca33efccf75c1bb388708Robert Tsai        mEeRoutingState = ROUTE_OFF;
3130bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
314275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        mPrefs = getSharedPreferences(PREF, Context.MODE_PRIVATE);
3150e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
316f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
31731949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
31831949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsZeroClickRequested = mPrefs.getBoolean(PREF_ZEROCLICK_ON, ZEROCLICK_ON_DEFAULT);
319f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
320275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
321275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
322533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
323275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
32431949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsScreenUnlocked = pm.isScreenOn() && !mKeyguard.isKeyguardLocked();
325533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
326d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
327f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
328eead88c5e2bdd34eb33fdf2c76717f9edb9e0396Jeff Hamilton        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
32965945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_OFF);
33065945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
331bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
332275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
33331949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
334275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        registerReceiver(mReceiver, filter);
335bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
336bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter = new IntentFilter();
337bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
338bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addDataScheme("package");
339bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
340d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen        mNotificationManager = (NotificationManager) this.getSystemService(
341d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                Context.NOTIFICATION_SERVICE);
342d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen
343275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        registerReceiver(mReceiver, filter);
3440e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
34531949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
34631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
34731949217328bf2357ff044f0d18677fe588c790cNick Pelly
34831949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
34931949217328bf2357ff044f0d18677fe588c790cNick Pelly        final ContentResolver resolver = mContext.getContentResolver();
35031949217328bf2357ff044f0d18677fe588c790cNick Pelly        final String airplaneModeRadios = Settings.System.getString(resolver,
35131949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_RADIOS);
35231949217328bf2357ff044f0d18677fe588c790cNick Pelly        final String toggleableRadios = Settings.System.getString(resolver,
35331949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
35431949217328bf2357ff044f0d18677fe588c790cNick Pelly
35531949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
35631949217328bf2357ff044f0d18677fe588c790cNick Pelly                airplaneModeRadios.contains(Settings.System.RADIO_NFC);
35731949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
35831949217328bf2357ff044f0d18677fe588c790cNick Pelly            toggleableRadios.contains(Settings.System.RADIO_NFC);
35931949217328bf2357ff044f0d18677fe588c790cNick Pelly
36031949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
36131949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
36231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
36331949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
36431949217328bf2357ff044f0d18677fe588c790cNick Pelly
36531949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
36631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
36731949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
36831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
36931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
37031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
37131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
37231949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
37331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
37431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
37531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
37631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
37731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
37831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
37931949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
38031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
38131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
38231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
38331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
38431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
38531949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
38631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
38731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
38831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
38931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
39031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
39131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
39231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * process may temporarily enable the NFC adapter
39331949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
39431949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
39531949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
39631949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
39731949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
39831949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
39931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
40031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
40131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
40231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
40331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
40431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
40531949217328bf2357ff044f0d18677fe588c790cNick Pelly
4064467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
4074467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
4084467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
4094467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
4104467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
4114467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
4124467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
4134467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
4144467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
41531949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
41631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
41731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
41831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
41931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
42031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
42131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
42231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
42331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
42431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            !(mIsAirplaneSensitive && isAirplaneModeOn())) {
42531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
42631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
42731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
42831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
42931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
43031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
43131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        executeEeWipe();
43231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
43331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
43431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_EE_WIPE:
43531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    executeEeWipe();
43631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
43731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
438d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
439d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
440d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
44131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
44231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
44331949217328bf2357ff044f0d18677fe588c790cNick Pelly
44431949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
44531949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
44631949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
44731949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
44831949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
44931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
45031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
45131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
45231949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
45331949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
45431949217328bf2357ff044f0d18677fe588c790cNick Pelly
45531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!mDeviceHost.initialize()) {
45631949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Error enabling NFC");
45731949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_OFF);
45831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return false;
45931949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
46031949217328bf2357ff044f0d18677fe588c790cNick Pelly
46131949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized(NfcService.this) {
46231949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
46331949217328bf2357ff044f0d18677fe588c790cNick Pelly
46431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (mIsZeroClickRequested) {
46531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mP2pManager.enableP2p();
46631949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
46731949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
46831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
46931949217328bf2357ff044f0d18677fe588c790cNick Pelly
47031949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
47131949217328bf2357ff044f0d18677fe588c790cNick Pelly            applyRouting();
47231949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
47331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
47431949217328bf2357ff044f0d18677fe588c790cNick Pelly
47531949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
47631949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
47731949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
47831949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
47931949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
48031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
48131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
48231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
48331949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
48431949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
48531949217328bf2357ff044f0d18677fe588c790cNick Pelly
48631949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
48731949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
48831949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
48931949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
49031949217328bf2357ff044f0d18677fe588c790cNick Pelly            WatchDogThread watchDog = new WatchDogThread();
49131949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
49231949217328bf2357ff044f0d18677fe588c790cNick Pelly
49331949217328bf2357ff044f0d18677fe588c790cNick Pelly            mP2pManager.disableP2p();
49431949217328bf2357ff044f0d18677fe588c790cNick Pelly
49531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
49631949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
49731949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
49831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
49931949217328bf2357ff044f0d18677fe588c790cNick Pelly            applyRouting();
50031949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
50131949217328bf2357ff044f0d18677fe588c790cNick Pelly
50231949217328bf2357ff044f0d18677fe588c790cNick Pelly            mNfcDispatcher.disableForegroundDispatch();
50331949217328bf2357ff044f0d18677fe588c790cNick Pelly
50431949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
50531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
50631949217328bf2357ff044f0d18677fe588c790cNick Pelly
50731949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
50831949217328bf2357ff044f0d18677fe588c790cNick Pelly
50931949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_OFF);
51031949217328bf2357ff044f0d18677fe588c790cNick Pelly
51131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
51231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
51331949217328bf2357ff044f0d18677fe588c790cNick Pelly
51431949217328bf2357ff044f0d18677fe588c790cNick Pelly        void executeEeWipe() {
51531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // TODO: read SE reset list from /system/etc
51631949217328bf2357ff044f0d18677fe588c790cNick Pelly            byte[][]apdus = EE_WIPE_APDUS;
51731949217328bf2357ff044f0d18677fe588c790cNick Pelly
51831949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
51931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (tempEnable) {
52031949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!enableInternal()) {
521ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
52231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
523f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
524f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
52531949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Executing SE wipe");
52631949217328bf2357ff044f0d18677fe588c790cNick Pelly            int handle = mSecureElement.doOpenSecureElementConnection();
52731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (handle == 0) {
52831949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Could not open the secure element");
52931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (tempEnable) {
53031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
53131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
53231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return;
53331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
53431949217328bf2357ff044f0d18677fe588c790cNick Pelly
53531949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
53631949217328bf2357ff044f0d18677fe588c790cNick Pelly
53731949217328bf2357ff044f0d18677fe588c790cNick Pelly            for (byte[] cmd : apdus) {
538ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                byte[] resp = mSecureElement.doTransceive(handle, cmd);
539ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                if (resp == null) {
540ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
541ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    break;
542ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                }
54331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
54431949217328bf2357ff044f0d18677fe588c790cNick Pelly
54531949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.resetTimeouts();
54631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mSecureElement.doDisconnect(handle);
54731949217328bf2357ff044f0d18677fe588c790cNick Pelly
54831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (tempEnable) {
54931949217328bf2357ff044f0d18677fe588c790cNick Pelly                disableInternal();
55031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
55131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
55231949217328bf2357ff044f0d18677fe588c790cNick Pelly
55331949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
55431949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (this) {
55531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
55631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
55731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
55831949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
55931949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
56031949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
56131949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
56231949217328bf2357ff044f0d18677fe588c790cNick Pelly                mContext.sendBroadcast(intent);
56331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
56431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
56531949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
56631949217328bf2357ff044f0d18677fe588c790cNick Pelly
56731949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
56831949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
56931949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
57031949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
57131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
5720e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
5730e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
574d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen    private void onFirstShare() {
575d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen        Intent intent = new Intent(Settings.ACTION_NFCSHARING_SETTINGS);
576d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen        PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent,
577d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                PendingIntent.FLAG_UPDATE_CURRENT);
578d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen        Notification notification = new Notification.Builder(mContext)
579d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                .setContentTitle(mContext.getString(R.string.first_share_title))
580d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                .setContentText(mContext.getString(R.string.first_share_text))
581d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                .setContentIntent(pi)
582d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                .setSmallIcon(R.drawable.stat_sys_nfc)
583d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                .setAutoCancel(true)
584d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                .getNotification();
585d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen        mNotificationManager.notify(NOTIFICATION_FIRST_SHARE, notification);
586d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen    }
587d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen
588d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    private void playSound(int sound) {
589d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
590d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            mSoundPool.play(sound, 1.0f, 1.0f, 0, 0, 1.0f);
591d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
592d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
593d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
5940e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
595d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    public void onP2pBegin() {
596d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton        if (!mP2pStarted) {
597d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton            playSound(mStartSound);
598d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton            mP2pStarted = true;
599d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton        }
600d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    }
601d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
602d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    @Override
603d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    public void onP2pEnd() {
604d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton        if (mP2pStarted) {
605d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton            playSound(mEndSound);
606d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton            mP2pStarted = false;
607d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen
608d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen            // If first time, throw up a notification
609d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen            if (mPrefs.getBoolean(PREF_FIRST_SHARE, true)) {
610d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                Log.i(TAG, "First NFC share");
611d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                mPrefsEditor.putBoolean(PREF_FIRST_SHARE, false);
612d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                mPrefsEditor.apply();
613d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen                onFirstShare();
614d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenen            }
615d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton        }
616d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    }
617d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
618d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    @Override
619d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    public void onP2pError() {
620d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton        if (mP2pStarted) {
621d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton            playSound(mErrorSound);
622d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton            mP2pStarted = false;
623d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton        }
624d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    }
625d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
626d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    @Override
6272f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    public void onTerminate() {
6282f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        super.onTerminate();
6292f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        // NFC application is persistent, it should not be destroyed by framework
6300e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        Log.wtf(TAG, "NFC service is under attack!");
6310e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
6320e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
6334a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
634fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
6350e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
63693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
6370e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
63831949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
63931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
64031949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.i(TAG, "denying enable() request (airplane mode)");
64131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return false;
642f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
64331949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
64431949217328bf2357ff044f0d18677fe588c790cNick Pelly
64531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
646f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
647f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
648fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
6490e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean disable() throws RemoteException {
65093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
6510e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
65231949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(false);
65331949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
65431949217328bf2357ff044f0d18677fe588c790cNick Pelly
65531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
656f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
657f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
658fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
65931949217328bf2357ff044f0d18677fe588c790cNick Pelly        public boolean isZeroClickEnabled() throws RemoteException {
66031949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
66131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mIsZeroClickRequested;
66231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
663d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
664d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
665d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
666d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        public boolean enableZeroClick() throws RemoteException {
667d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
668d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
66931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (mIsZeroClickRequested) {
67031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
67131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
67231949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.i(TAG, "enabling 0-click");
67331949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.putBoolean(PREF_ZEROCLICK_ON, true);
67431949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
67531949217328bf2357ff044f0d18677fe588c790cNick Pelly                mIsZeroClickRequested = true;
67631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
67731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mP2pManager.enableP2p();
678d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
679d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
680d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
681d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
682d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
683d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
684d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        public boolean disableZeroClick() throws RemoteException {
685d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
686d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
68731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsZeroClickRequested) {
68831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
68931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
69031949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.i(TAG, "disabling 0-click");
69131949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.putBoolean(PREF_ZEROCLICK_ON, false);
69231949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
69331949217328bf2357ff044f0d18677fe588c790cNick Pelly                mIsZeroClickRequested = false;
69431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
69531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mP2pManager.disableP2p();
696d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
697d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
698d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
699d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
700d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
701d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
70205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton        public void enableForegroundDispatch(ComponentName activity, PendingIntent intent,
70324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
704a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Permission check
70505973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
706a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
707a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Argument validation
708a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (activity == null || intent == null) {
709ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton                throw new IllegalArgumentException();
710ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
711a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
712a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
713a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
714a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
715a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
716a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
717a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
718a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
719a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
720a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
721a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
722a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
723a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
724a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
72524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
72624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
72724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
72824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
72924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
73049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
73176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly            mNfcDispatcher.enableForegroundDispatch(intent, filters, techLists);
73205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton        }
73305973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton
73405973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton        @Override
73505973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton        public void disableForegroundDispatch(ComponentName activity) {
73605973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
73776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly
73876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly            mNfcDispatcher.disableForegroundDispatch();
73905973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton        }
74005973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton
74105973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton        @Override
742ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        public void enableForegroundNdefPush(ComponentName activity, NdefMessage msg) {
743ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
744ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            if (activity == null || msg == null) {
745ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton                throw new IllegalArgumentException();
746ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
7472ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson            if (mP2pManager.setForegroundMessage(msg)) {
748209282e9b744f3b9390154ebb69ad5587ccc2688Nick Pelly                Log.w(TAG, "Replacing active NDEF push message");
749ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
750ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
751ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
752ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
7532094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        public void enableForegroundNdefPushWithCallback(ComponentName activity,
7542094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks                INdefPushCallback callback) {
7552094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
7562094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks            if (activity == null || callback == null) {
7572094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks                throw new IllegalArgumentException();
7582094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks            }
7592ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson            if (mP2pManager.setForegroundCallback(callback)) {
760209282e9b744f3b9390154ebb69ad5587ccc2688Nick Pelly                Log.w(TAG, "Replacing active NDEF push message");
7612094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks            }
7622094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
7632094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
7642094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
765ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        public void disableForegroundNdefPush(ComponentName activity) {
766ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
7672ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson            boolean hadMsg = mP2pManager.setForegroundMessage(null);
7682ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson            boolean hadCallback = mP2pManager.setForegroundCallback(null);
7692094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks            if (!hadMsg || !hadCallback) {
770209282e9b744f3b9390154ebb69ad5587ccc2688Nick Pelly                Log.w(TAG, "No active foreground NDEF push message");
771ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
772ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
773ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
774ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
7750e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
776d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
7770e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
7780e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
7790e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
780fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
78149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public INfcAdapterExtras getNfcAdapterExtrasInterface() {
78293d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
78349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mExtrasService;
7840bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
7850bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
786fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
78731949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
78831949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
78931949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
79031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
79131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
79231949217328bf2357ff044f0d18677fe588c790cNick Pelly
79331949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
79431949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
79531949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
7960e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
7970e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    };
7980e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
7994a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
800fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
801f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
802d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
803bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
804f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
805f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
80631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
807f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
808f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
809f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
810f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
811f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
812f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
813b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
814b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
81521545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
816b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
817f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
818f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
81949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            applyRouting();
820f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
821f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
822f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
823fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
824ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
825d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
826bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
827f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
828f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
82931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
830f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
831f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
832f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
833f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
834f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
835b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
836b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
837f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
838ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
8391b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen            if (technology == TagTechnology.NFC_B) {
8401b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen                return ErrorCodes.ERROR_NOT_SUPPORTED;
8411b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen            }
8421b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen
843ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
844ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
845ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
846ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
847ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
848ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
849ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
850ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
851f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
852f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
853fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
854aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
855aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
856aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
857f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
858aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
859aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
86031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
861aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
862aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
863aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
864aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
865f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
866aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
867aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
868aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
869aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
870aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
871aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
872aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
873aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
874aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
875aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
876aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
877b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
878d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
879bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
880f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
88131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
882f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
883f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
884f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
885f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
886f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
887f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
888b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
889f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
890f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
891f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
892f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
893fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
894f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public byte[] getUid(int nativeHandle) throws RemoteException {
895f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
896f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] uid;
897f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
898f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
89931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
900f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
901f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
902f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
903f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
904f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
905f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
906f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                uid = tag.getUid();
907f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return uid;
908f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
909f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
910f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
911f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
912fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
913b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
914f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
915b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
916b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
91731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
918b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
919b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
920b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
921b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
922f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
923b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
924b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
925b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
926b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
927ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
928b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
929b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
930fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
931f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
932f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
933f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
934f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
93531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
9362c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
937f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
938f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
939f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
940f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
9413ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
9422c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
9432c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
944f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
94570bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
946f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
947f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
948fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9499d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
95097c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
951d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
952bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
953f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
954f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
955f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
956f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
95731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
958f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
959f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
960f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
961f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
962f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
963f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
9649d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
9659d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
9669d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                TransceiveResult transResult = new TransceiveResult(
9679d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                        (response != null) ? true : false,
9689d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                        (targetLost[0] == 1) ? true : false,
9699d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                        response);
9709d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                return transResult;
971f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
972f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
973f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
974f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
975fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9763fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
977d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
978bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
979f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
980f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
981f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
98231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
983f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
984f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
985f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
986f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
987f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
988f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
989f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
990f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
991f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
992f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
993f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
994f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
995f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
996f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
997f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
998f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
999f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1000f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1001f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1002f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1003f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1004fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
10053fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1006d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1007bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1008f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1009f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1010f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
101131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1012f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1013f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1014f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1015f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1016f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1017f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1018f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1019f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1020f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1021f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1022f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1023f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1024f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1025f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1026f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1027f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1028f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1029fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1030f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int getLastError(int nativeHandle) throws RemoteException {
1031f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            return(mDeviceHost.doGetLastError());
1032f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1033f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1034fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
10353fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
10363fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1037f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1038f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1039fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
10403fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
104103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
104203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1043f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
104403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
104503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
104631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
104703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
104803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
104903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
105003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1051f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
105203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
105303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
105403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
105503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1056f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
105703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1058f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
105903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
106003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1061f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1062f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
10630aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
10640aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
10650aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
10660aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1067f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
10680aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10690aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
107031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
10710aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
10720aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10730aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10740aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1075f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
10760aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
10770aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
10780aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10790aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10800aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
10810aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1082f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
10830aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
10840aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10850aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
10860aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10871b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
10883fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
10893fb14d0868594c78a777e805545209636814e223Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
10903fb14d0868594c78a777e805545209636814e223Martijn Coenen
1091f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
10923fb14d0868594c78a777e805545209636814e223Martijn Coenen
10933fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
109431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
10953fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
10963fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
10973fb14d0868594c78a777e805545209636814e223Martijn Coenen
10983fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1099f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
11003fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
11013fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
11023fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
11033fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
11043fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
11053fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
11063fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
11073fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
11083fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
11093fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
11103fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1111f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                NdefMessage[] msgs = tag.findAndReadNdef();
11123fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
11133fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
11144a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
11153fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
11163fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
11173fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
11183fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
11193fb14d0868594c78a777e805545209636814e223Martijn Coenen
11201b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1121fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
11221b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1123f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1124fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1125fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1126fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1127fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1128fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1129dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1130dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1131dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1132358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
1133358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1134358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1135358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1136358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1137358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1138358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1139dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
1140dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1141dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1142f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
11431b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
11440e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    };
1145f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1146dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    private void _nfcEeClose(boolean checkPid, int callingPid) throws IOException {
1147dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // Blocks until a pending open() or transceive() times out.
1148dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        //TODO: This is incorrect behavior - the close should interrupt pending
1149dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // operations. However this is not supported by current hardware.
1150dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1151dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        synchronized(NfcService.this) {
115231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1153dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC adapter is disabled");
1154dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1155dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (mOpenEe == null) {
1156dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC EE closed");
1157dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1158dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (checkPid && mOpenEe.pid != -1 && callingPid != mOpenEe.pid) {
1159dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new SecurityException("Wrong PID");
1160dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1161dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1162f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
1163dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mSecureElement.doDisconnect(mOpenEe.handle);
1164dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mOpenEe = null;
1165dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1166dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            applyRouting();
1167dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        }
1168dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    }
1169dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
11704a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
117149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeNoException() {
117249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
117349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", 0);
117449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
117549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
117649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeIoException(IOException e) {
117749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
117849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", -1);
117949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putString("m", e.getMessage());
118049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
118149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
11820bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1183bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
118449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public Bundle open(IBinder b) throws RemoteException {
118593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
1186bd555ee64250126b60b24814120a2049943920caNick Pelly
118749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
118849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
118949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                _open(b);
119049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
119149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
119249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
11930bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
119449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
119549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
11960bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
119749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private void _open(IBinder b) throws IOException, RemoteException {
119849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
119931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
120049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC adapter is disabled");
120149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
120249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe != null) {
120349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE already open");
120449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
12050bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
120649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                int handle = mSecureElement.doOpenSecureElementConnection();
120749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (handle == 0) {
120849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE failed to open");
120949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
1210f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
1211ba6401757f8017faeb77423f2d08fd51be1d1051Nick Pelly
121249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                mOpenEe = new OpenSecureElement(getCallingPid(), handle);
121349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                try {
121449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    b.linkToDeath(mOpenEe, 0);
121549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                } catch (RemoteException e) {
121649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    mOpenEe.binderDied();
121749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
121884e1e0adc2516afd35ebab029a52e764e0490559Jason parks
121984e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // Add the calling package to the list of packages that have accessed
122084e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // the secure element.
122184e1e0adc2516afd35ebab029a52e764e0490559Jason parks                for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) {
122284e1e0adc2516afd35ebab029a52e764e0490559Jason parks                    mSePackages.add(packageName);
122384e1e0adc2516afd35ebab029a52e764e0490559Jason parks                }
122449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly           }
12250bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
12260bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1227bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
122849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public Bundle close() throws RemoteException {
122993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
12300bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
123149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
123249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
1233dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                _nfcEeClose(true, getCallingPid());
123449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
123549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
123649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
12370bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
123849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
123949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
12400bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1241bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
124249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public Bundle transceive(byte[] in) throws RemoteException {
124393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
1244bd555ee64250126b60b24814120a2049943920caNick Pelly
124549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
124649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            byte[] out;
124749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
124849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                out = _transceive(in);
124949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
125049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result.putByteArray("out", out);
125149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
125249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
12530bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
125449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
125549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
12560bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
125749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private byte[] _transceive(byte[] data) throws IOException, RemoteException {
125849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
125931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
126049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC is not enabled");
126149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
126249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe == null){
126349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE is not open");
126449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
126549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (getCallingPid() != mOpenEe.pid) {
126649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new SecurityException("Wrong PID");
126749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
12680bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
12690bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
127049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mSecureElement.doTransceive(mOpenEe.handle, data);
12710bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
12720bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1273bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
127449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int getCardEmulationRoute() throws RemoteException {
127593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
127649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mEeRoutingState;
12770bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
12780bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1279bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
128049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void setCardEmulationRoute(int route) throws RemoteException {
128193d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceNfceeAdminPerm(mContext);
128249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            mEeRoutingState = route;
128349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            applyRouting();
12840bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
1285bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
1286bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
12875a8844da9bc569aa7289426bf7b96e7eef90abf5Nick Pelly        public void authenticate(byte[] token) throws RemoteException {
1288bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            NfcService.enforceNfceeAdminPerm(mContext);
1289bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
12900bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    };
12910bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
129249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** resources kept while secure element is open */
129349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private class OpenSecureElement implements IBinder.DeathRecipient {
129449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int pid;  // pid that opened SE
129549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int handle; // low-level handle
129649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public OpenSecureElement(int pid, int handle) {
129749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.pid = pid;
129849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.handle = handle;
129949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1300bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
130149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void binderDied() {
130249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized (NfcService.this) {
130349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (DBG) Log.d(TAG, "Tracked app " + pid + " died");
130449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                pid = -1;
13050bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas                try {
1306dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                    _nfcEeClose(false, -1);
1307dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                } catch (IOException e) { /* already closed */ }
13080bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
13090bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
13100bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    }
13110bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
131231949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
131331949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
131431949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1315e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1316aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1317aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
131831949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
13192edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        boolean mWatchDogCanceled = false;
13202edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
13212edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
13222edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            boolean slept = false;
13232edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            while (!slept) {
13242edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                try {
13252edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    Thread.sleep(10000);
13262edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    slept = true;
13272edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                } catch (InterruptedException e) { }
13282edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
13292edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            synchronized (this) {
13302edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                if (!mWatchDogCanceled) {
13312edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    // Trigger watch-dog
13322edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    Log.e(TAG, "Watch dog triggered");
13332083287b83a587d8f6e9ad829ea18041dc17d842Nick Pelly                    mDeviceHost.doAbort();
13342edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
13352edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
13362edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
13372edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
13382edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            mWatchDogCanceled = true;
13392edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
13402edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
13412edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
134249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** apply NFC discovery and EE routing */
134349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private synchronized void applyRouting() {
134431949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (!isNfcEnabled() || mOpenEe != null) {
134531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return;
134631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
134731949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsScreenUnlocked) {
134831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
134931949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.d(TAG, "NFC-EE routing ON");
135031949217328bf2357ff044f0d18677fe588c790cNick Pelly                mDeviceHost.doSelectSecureElement();
1351221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            } else {
135249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                Log.d(TAG, "NFC-EE routing OFF");
1353f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                mDeviceHost.doDeselectSecureElement();
1354221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
135531949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.d(TAG, "NFC-C polling ON");
135631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.enableDiscovery();
135731949217328bf2357ff044f0d18677fe588c790cNick Pelly        } else {
135831949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.d(TAG, "NFC-EE routing OFF");
135931949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.doDeselectSecureElement();
136031949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.d(TAG, "NFC-C polling OFF");
136131949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.disableDiscovery();
136265945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
136365945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
136465945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
13652436ffe91853535fad87b7a8e03d8883bae20f20Arnaud Ferir    /** Disconnect any target if present */
136631949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
136731949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (!isNfcEnabled()) {
1368a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1369a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
137031949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
137131949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
137231949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
137331949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
137431949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
137531949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
137631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
137731949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
137831949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
137931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
138031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
138131949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
138231949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
138331949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
138431949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
138531949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
138631949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
138731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
138831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
138931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
139031949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
139131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
139231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1393bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1394bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1395bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1396bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1397bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
139831949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
139931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
140031949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
140131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
140231949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
14032f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
140431949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
14050e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1406f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1407f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
140831949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
140931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
141031949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1411f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1412b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1413b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
141431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
141531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
141631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
141731949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
1418f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1419f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1420d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
14214a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
14224a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton            throws IOException, LlcpException {
14234a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1424d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1425d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1426d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
14274a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
14284a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton            int linearBufferLength) throws IOException, LlcpException {
14294a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1430d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1431d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
143257d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
1433b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
143457d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
143557d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
1436b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
1437b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
1438b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
1439b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
1440b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
1441b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1442b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
14433fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
1444b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
1445b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
144631949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
144731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
144831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
144931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
145031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
145131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
145231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
145331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
145431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
145531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new int[] { TagTechnology.NDEF },
145631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new Bundle[] { extras });
145731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
145831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
145931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean delivered = mNfcDispatcher.dispatchTag(tag,
146031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new NdefMessage[] { ndefMsg });
146131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (delivered) {
146231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        onP2pEnd();
146331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
146431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
146531949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
146657d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
146731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
146831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
146931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
147031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    playSound(mStartSound);
147131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage[] ndefMsgs = tag.findAndReadNdef();
1472c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
147331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (ndefMsgs != null) {
147431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        tag.startPresenceChecking();
147531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        dispatchTagEndpoint(tag, ndefMsgs);
147631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
147731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
147831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.startPresenceChecking();
147931949217328bf2357ff044f0d18677fe588c790cNick Pelly                            dispatchTagEndpoint(tag, null);
148031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
148131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
148231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            playSound(mErrorSound);
148331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
148431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
148531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
148631949217328bf2357ff044f0d18677fe588c790cNick Pelly
148731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_CARD_EMULATION:
148831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Emulation message");
148931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] aid = (byte[]) msg.obj;
149031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
149131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent aidIntent = new Intent();
149231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.setAction(ACTION_AID_SELECTED);
149331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.putExtra(EXTRA_AID, aid);
149431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
149531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendBroadcast(aidIntent, NFCEE_ADMIN_PERM);
149631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
149731949217328bf2357ff044f0d18677fe588c790cNick Pelly
149831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_EMV_CARD_REMOVAL:
149931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Removal message");
150031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
150131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent cardRemovalIntent = new Intent();
150231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
150331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
150431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendBroadcast(cardRemovalIntent, NFCEE_ADMIN_PERM);
150531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
150631949217328bf2357ff044f0d18677fe588c790cNick Pelly
150731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_APDU_RECEIVED:
150831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "APDU Received message");
150931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] apduBytes = (byte[]) msg.obj;
151031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
151131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent apduReceivedIntent = new Intent();
151231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
151331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (apduBytes != null && apduBytes.length > 0) {
151431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
151531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
151631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
151731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendBroadcast(apduReceivedIntent, NFCEE_ADMIN_PERM);
151831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
151931949217328bf2357ff044f0d18677fe588c790cNick Pelly
152031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_MIFARE_ACCESS:
152131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "MIFARE access message");
152231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
152331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] mifareCmd = (byte[]) msg.obj;
152431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent mifareAccessIntent = new Intent();
152531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
152631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mifareCmd != null && mifareCmd.length > 1) {
152731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        int mifareBlock = mifareCmd[1] & 0xff;
152831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
152931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
153031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
153131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
153231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendBroadcast(mifareAccessIntent, NFCEE_ADMIN_PERM);
153331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
1534c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
153531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
153631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
153731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
153831949217328bf2357ff044f0d18677fe588c790cNick Pelly
153931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
154031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
154131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
154231949217328bf2357ff044f0d18677fe588c790cNick Pelly
154331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
154431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
154531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
154631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
154731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
154831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
154931949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
155031949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
155131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
155231949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
155331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
155431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
155531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
155631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
155731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
155831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
155931949217328bf2357ff044f0d18677fe588c790cNick Pelly
156031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mP2pManager.onLlcpDeactivated();
156131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
156231949217328bf2357ff044f0d18677fe588c790cNick Pelly
156331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_TARGET_DESELECTED:
156431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Broadcast Intent Target Deselected */
156531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Target Deselected");
156631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent intent = new Intent();
156731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
156831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting Intent");
156931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
157031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
157131949217328bf2357ff044f0d18677fe588c790cNick Pelly
157231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_ACTIVATED: {
157331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
157431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOnIntent = new Intent();
157531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
157631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendBroadcast(eventFieldOnIntent, NFCEE_ADMIN_PERM);
157731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
157831949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
157931949217328bf2357ff044f0d18677fe588c790cNick Pelly
158031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_DEACTIVATED: {
158131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
158231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOffIntent = new Intent();
158331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
158431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendBroadcast(eventFieldOffIntent, NFCEE_ADMIN_PERM);
158531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
158631949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
158731949217328bf2357ff044f0d18677fe588c790cNick Pelly
158831949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
158931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
159031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
159131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
1592b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1593d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1594d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
1595d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
1596d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1597d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1598d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1599d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
1600d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
1601d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
1602d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
1603d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
1604d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
160531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            boolean isZeroClickOn;
160631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
160731949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
160831949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
1609d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
161031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mP2pManager.onLlcpActivated();
1611d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
1612d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
1613d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
1614d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1615d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
1616d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
1617d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
1618d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1619d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
1620d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1621d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1622d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1623d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
1624d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
1625d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
1626d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
1627d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1628d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1629d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1630d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
1631d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
1632d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
1633d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
1634d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
163531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        boolean isZeroClickOn;
163631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
163731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
163831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
1639d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
164031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mP2pManager.onLlcpActivated();
1641d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
1642d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1643d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1644d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
1645d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1646d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
1647d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1648d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
1649d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
1650d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1651f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, NdefMessage[] msgs) {
1652f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
1653f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
1654f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
165576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly            if (!mNfcDispatcher.dispatchTag(tag, msgs)) {
1656f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
1657d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                playSound(mErrorSound);
1658d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else {
1659d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                playSound(mEndSound);
16603fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
16613fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
1662b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
1663b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1664b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
166549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
166631949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableDiscoveryTask extends AsyncTask<Boolean, Void, Void> {
1667fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1668275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        protected Void doInBackground(Boolean... params) {
1669275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks            if (DBG) Log.d(TAG, "EnableDisableDiscoveryTask: enable = " + params[0]);
1670275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
1671275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks            if (params != null && params.length > 0 && params[0]) {
1672161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                synchronized (NfcService.this) {
167331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (!mIsScreenUnlocked) {
167431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mIsScreenUnlocked = true;
1675275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                        applyRouting();
1676275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                    } else {
1677275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                        if (DBG) Log.d(TAG, "Ignoring enable request");
1678275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                    }
1679161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
16807c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            } else {
1681533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly                mWakeLock.acquire();
1682161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                synchronized (NfcService.this) {
168331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mIsScreenUnlocked) {
168431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mIsScreenUnlocked = false;
1685275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                        applyRouting();
1686275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                        maybeDisconnectTarget();
1687275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                    } else {
1688275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                        if (DBG) Log.d(TAG, "Ignoring disable request");
1689275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                    }
1690161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
1691533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly                mWakeLock.release();
16927c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
16937c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            return null;
16947c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
16957c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
16967c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
16970e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
16980e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        @Override
16990e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public void onReceive(Context context, Intent intent) {
170031949217328bf2357ff044f0d18677fe588c790cNick Pelly            String action = intent.getAction();
170131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (action.equals(
1702f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
1703ef92efa7fd86d75cc35465b84e8740f941ff0f0aJeff Hamilton                if (DBG) Log.d(TAG, "INERNAL_TARGET_DESELECTED_ACTION");
17040e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
1705f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Restart polling loop for notification */
170649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                applyRouting();
1707f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
170831949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1709275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                // Only enable if the screen is unlocked. If the screen is locked
1710275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                // Intent.ACTION_USER_PRESENT will be broadcast when the screen is
1711275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                // unlocked.
17126ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                boolean enable = !mKeyguard.isKeyguardSecure() || !mKeyguard.isKeyguardLocked();
1713275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
17146ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                // Perform discovery enable in thread to protect against ANR when the
17156ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                // NFC stack wedges. This is *not* the correct way to fix this issue -
17166ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                // configuration of the local NFC adapter should be very quick and should
17176ec87aa54aad2c340c4ea0247ba4a8e0d9f10573Nick Pelly                // be safe on the main thread, and the NFC stack should not wedge.
1718275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                new EnableDisableDiscoveryTask().execute(enable);
171931949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
17207c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly                // Perform discovery disable in thread to protect against ANR when the
17217c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly                // NFC stack wedges. This is *not* the correct way to fix this issue -
17227c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly                // configuration of the local NFC adapter should be very quick and should
17237c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly                // be safe on the main thread, and the NFC stack should not wedge.
1724275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                new EnableDisableDiscoveryTask().execute(Boolean.FALSE);
172531949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1726275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                // The user has unlocked the screen. Enabled!
1727275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks                new EnableDisableDiscoveryTask().execute(Boolean.TRUE);
172831949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
172931949217328bf2357ff044f0d18677fe588c790cNick Pelly                EnableDisableTask eeWipeTask = new EnableDisableTask();
173031949217328bf2357ff044f0d18677fe588c790cNick Pelly                eeWipeTask.execute(TASK_EE_WIPE);
173131949217328bf2357ff044f0d18677fe588c790cNick Pelly                try {
173231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eeWipeTask.get();  // blocks until EE wipe is complete
173331949217328bf2357ff044f0d18677fe588c790cNick Pelly                } catch (ExecutionException e) {
173431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.w(TAG, "failed to wipe NFC-EE");
173531949217328bf2357ff044f0d18677fe588c790cNick Pelly                } catch (InterruptedException e) {
173631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.w(TAG, "failed to wipe NFC-EE");
173731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
173831949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
17397a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
17407a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                if (dataRemoved) {
17417a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                    Uri data = intent.getData();
17427a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                    if (data == null) return;
17437a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                    String packageName = data.getSchemeSpecificPart();
17447a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton
17457a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                    synchronized (NfcService.this) {
174684e1e0adc2516afd35ebab029a52e764e0490559Jason parks                        if (mSePackages.contains(packageName)) {
174731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new EnableDisableTask().execute(TASK_EE_WIPE);
174884e1e0adc2516afd35ebab029a52e764e0490559Jason parks                            mSePackages.remove(packageName);
17497a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                        }
1750bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                    }
1751bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
175231949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
175331949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
175431949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
175531949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
175631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
175731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
175831949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
175931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
176031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
176131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
176231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
176331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
176431949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
176531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
176631949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
1767f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1768f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1769f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
177031949217328bf2357ff044f0d18677fe588c790cNick Pelly
177131949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** Returns true if airplane mode is currently on */
177231949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
177331949217328bf2357ff044f0d18677fe588c790cNick Pelly        return Settings.System.getInt(mContext.getContentResolver(),
177431949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
177531949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
177631949217328bf2357ff044f0d18677fe588c790cNick Pelly
177731949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** for debugging only - no il8n */
177831949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
177931949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
178031949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
178131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
178231949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
178331949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
178431949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
178531949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
178631949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
178731949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
178831949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
178931949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
179031949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
179131949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
179231949217328bf2357ff044f0d18677fe588c790cNick Pelly
179331949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
179431949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
179531949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
179631949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsZeroClickRequested=" + mIsZeroClickRequested);
179731949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsScreenUnlocked=" + mIsScreenUnlocked);
179831949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
179931949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
180031949217328bf2357ff044f0d18677fe588c790cNick Pelly            mP2pManager.dump(fd, pw, args);
180131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
180231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
180374180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
1804