NfcService.java revision 37058bf7b59def2f9a565ae5b16aae54e80e9e95
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;
20e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenenimport com.android.nfc.DeviceHost.LlcpConnectionlessSocket;
214a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamiltonimport com.android.nfc.DeviceHost.LlcpServerSocket;
224a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamiltonimport com.android.nfc.DeviceHost.LlcpSocket;
23f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamiltonimport com.android.nfc.DeviceHost.NfcDepEndpoint;
24f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamiltonimport com.android.nfc.DeviceHost.TagEndpoint;
2543f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pellyimport com.android.nfc.handover.HandoverManager;
2681c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport com.android.nfc.nxp.NativeNfcManager;
2781c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport com.android.nfc.nxp.NativeNfcSecureElement;
28d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
292f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pellyimport android.app.Application;
30275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parksimport android.app.KeyguardManager;
3105973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamiltonimport android.app.PendingIntent;
3213d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.BroadcastReceiver;
3331949217328bf2357ff044f0d18677fe588c790cNick Pellyimport android.content.ContentResolver;
3413d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Context;
3513d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Intent;
3613d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.IntentFilter;
370e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.content.SharedPreferences;
38483f3065021c878468ab0921140aa9a2c89b4246Martijn Coenenimport android.content.pm.PackageInfo;
3993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamiltonimport android.content.pm.PackageManager;
40d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.AudioManager;
41d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.SoundPool;
423fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamiltonimport android.net.Uri;
43f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.ErrorCodes;
44f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.FormatException;
452094515fca0cfa0ac87e9cc260d3953d416afe3eJason parksimport android.nfc.INdefPushCallback;
460e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.INfcAdapter;
4749d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.nfc.INfcAdapterExtras;
48f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.INfcTag;
49f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NdefMessage;
50f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NfcAdapter;
510e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.Tag;
5224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.nfc.TechListParcel;
539d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenenimport android.nfc.TransceiveResult;
54aca0d055a82da850c27f6872405602ad5f3fee7bJeff Hamiltonimport android.nfc.tech.Ndef;
5581c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport android.nfc.tech.TagTechnology;
567c034a7fe7d36b1ab039af2c44717812ea02657eNick Pellyimport android.os.AsyncTask;
5750effe4645b6ea57a1dc90777995f41dd9624e55Kenny Rootimport android.os.Binder;
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;
75c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.util.List;
7631949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.concurrent.ExecutionException;
773ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
7877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pellypublic class NfcService extends Application implements DeviceHostListener {
79bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
80bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
81c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = false;
8276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
83fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
84d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
85fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
86c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** Regular NFC permission */
87bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM = android.Manifest.permission.NFC;
88bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM_ERROR = "NFC permission required";
89c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
90c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** NFC ADMIN permission - only for system apps */
91bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
92bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
93bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
9477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
95f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
96416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
97416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
98416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
99416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
100416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
101416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
1021668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
103a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
104fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final boolean PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE = true;
105fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
106b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
107b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_CARD_EMULATION = 1;
108b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_ACTIVATION = 2;
109b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
110b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_TARGET_DESELECTED = 4;
111b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    static final int MSG_MOCK_NDEF = 7;
112c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_ACTIVATED = 8;
113c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_DEACTIVATED = 9;
1142c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_APDU_RECEIVED = 10;
1152c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
1162c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_MIFARE_ACCESS = 12;
117b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
11831949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
11931949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
12031949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
12131949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_EE_WIPE = 4;
12231949217328bf2357ff044f0d18677fe588c790cNick Pelly
123fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    // Screen state, used by mScreenState
124fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_UNKNOWN = 0;
125fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_OFF = 1;
126fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_LOCKED = 2;
127fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_UNLOCKED = 3;
128fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
12949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Copied from com.android.nfc_extras to avoid library dependency
13049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Must keep in sync with com.android.nfc_extras
13149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_OFF = 1;
13249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
1337efbf69a37134ccbd86a1f6b4121f16b4a80eaaeNick Pelly
134fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** minimum screen state that enables NFC polling (discovery) */
135fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
136fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
137d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
138d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
139d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
140d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
141d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
14249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_ON_DETECTED =
14349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
14449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_OFF_DETECTED =
14549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
14649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_AID_SELECTED =
14749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.AID_SELECTED";
14849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
14949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
1502c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_APDU_RECEIVED =
1512c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.APDU_RECEIVED";
1522c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_APDU_BYTES =
1532c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.APDU_BYTES";
1542c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1552c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_EMV_CARD_REMOVAL =
1562c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
1572c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1582c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_MIFARE_ACCESS_DETECTED =
1592c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
1602c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_MIFARE_BLOCK =
1612c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.MIFARE_BLOCK";
1622c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
16331949217328bf2357ff044f0d18677fe588c790cNick Pelly    //TODO: dont hardcode this
16431949217328bf2357ff044f0d18677fe588c790cNick Pelly    private static final byte[][] EE_WIPE_APDUS = {
16531949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
16631949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
16731949217328bf2357ff044f0d18677fe588c790cNick Pelly                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
16831949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
16931949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
17031949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
17131949217328bf2357ff044f0d18677fe588c790cNick Pelly                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
17231949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
17331949217328bf2357ff044f0d18677fe588c790cNick Pelly        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
17431949217328bf2357ff044f0d18677fe588c790cNick Pelly    };
17549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
17649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
17749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
1780bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    private NativeNfcSecureElement mSecureElement;
17949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private OpenSecureElement mOpenEe;  // null when EE closed
18049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private int mEeRoutingState;  // contactless interface routing
1810bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
182d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    // fields below must be used only on the UI thread and therefore aren't synchronized
183d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    boolean mP2pStarted = false;
184d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
1852f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
186fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
187fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    HashSet<String> mSePackages = new HashSet<String>();
188fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int mScreenState;
189fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mIsNdefPushEnabled;
190fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfceeRouteEnabled;  // current Device Host state of NFC-EE routing
191fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfcPollingEnabled;  // current Device Host state of NFC-C polling
192e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    List<PackageInfo> mInstalledPackages; // cached version of installed packages
19331949217328bf2357ff044f0d18677fe588c790cNick Pelly
19431949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
19531949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
19631949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
19731949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
1982f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
1992f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
20005973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
2014a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
2020e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
2030e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
204533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly    private PowerManager.WakeLock mWakeLock;
205d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
206d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
207d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
208d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
20977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
2104a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
2114a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
2124a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterExtrasService mExtrasService;
21331949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
21431949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
215c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    NfceeAccessControl mNfceeAccessControl;
2162ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
21776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
218fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    private PowerManager mPowerManager;
219275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
220d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
221d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    private static NfcService sService;
222d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
22393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceAdminPerm(Context context) {
224c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
22593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
22693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
227c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public void enforceNfceeAdminPerm(String pkg) {
228c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (pkg == null) {
229c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException("caller must pass a package name");
230c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
231c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
232c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (!mNfceeAccessControl.check(Binder.getCallingUid(), pkg)) {
233c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
234c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    " denies NFCEE access to " + pkg);
235c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
23693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
23793d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
238d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
239d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
240d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
241f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2420e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
243f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
244f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
245f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
246f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
247f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
248f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
249f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
250d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
251f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationDeselected() {
252f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
253f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
254f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
255f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
256f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
257f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
258d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
259f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationAidSelected(byte[] aid) {
260f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_CARD_EMULATION, aid);
261f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
262f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
263f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
264f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
265f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
266f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
267f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
268f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
269f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
270f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
271f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
272f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
273f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
274d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
275f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
276f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
277f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
278f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
279d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
280f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldActivated() {
281f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
282f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
283f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
284d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
285f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldDeactivated() {
286f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
287f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
288f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
289f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
290442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeApduReceived(byte[] apdu) {
291442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
292442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
293442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
294442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
295442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeEmvCardRemoval() {
296442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
297442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
298442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
299442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
300442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeMifareAccess(byte[] block) {
301442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
302442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
303442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
304442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
3050e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    public void onCreate() {
3062f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        super.onCreate();
3072f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
3084a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
3094a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
310ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly        mExtrasService = new NfcAdapterExtrasService();
3114a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton
3122f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
3132f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
314d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
315d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
3160e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mContext = this;
317f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        mDeviceHost = new NativeNfcManager(this, this);
31874180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
31943f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly        HandoverManager handoverManager = new HandoverManager(mContext);
32043f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly        mNfcDispatcher = new NfcDispatcher(this, handoverManager);
32143f2fa7ad4c72ef4849f2d2b78a963c1925c63a3Nick Pelly        mP2pLinkManager = new P2pLinkManager(mContext, handoverManager);
32224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
32337058bf7b59def2f9a565ae5b16aae54e80e9e95Sunil Jogi        mSecureElement = new NativeNfcSecureElement(mContext);
324eab09ad7204fe1f0feaca33efccf75c1bb388708Robert Tsai        mEeRoutingState = ROUTE_OFF;
3250bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
326c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mNfceeAccessControl = new NfceeAccessControl(this);
327c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
328275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        mPrefs = getSharedPreferences(PREF, Context.MODE_PRIVATE);
3290e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
330f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
33131949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
3320b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
333f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
334fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
335275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
336fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
337275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
338fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        mScreenState = checkScreenState();
339533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
340d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
341f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
342eead88c5e2bdd34eb33fdf2c76717f9edb9e0396Jeff Hamilton        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
34365945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_OFF);
34465945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
345bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
346275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
347e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
348e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
34931949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
350275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        registerReceiver(mReceiver, filter);
351bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
352bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter = new IntentFilter();
353e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
354bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
355bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        filter.addDataScheme("package");
356bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
357275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        registerReceiver(mReceiver, filter);
3580e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
359e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        updatePackageCache();
360e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
36131949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
36231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
36331949217328bf2357ff044f0d18677fe588c790cNick Pelly
364d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
365d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
366d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
367d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
368d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mStartSound = mSoundPool.load(this, R.raw.start, 1);
369d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mEndSound = mSoundPool.load(this, R.raw.end, 1);
370d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mErrorSound = mSoundPool.load(this, R.raw.error, 1);
371d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
372d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
373d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
374d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
375d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
376d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
377d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
378d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
379d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
380d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
381d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
382d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
383d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
38431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
38531949217328bf2357ff044f0d18677fe588c790cNick Pelly        final ContentResolver resolver = mContext.getContentResolver();
38631949217328bf2357ff044f0d18677fe588c790cNick Pelly        final String airplaneModeRadios = Settings.System.getString(resolver,
38731949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_RADIOS);
38831949217328bf2357ff044f0d18677fe588c790cNick Pelly        final String toggleableRadios = Settings.System.getString(resolver,
38931949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
39031949217328bf2357ff044f0d18677fe588c790cNick Pelly
39131949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
39231949217328bf2357ff044f0d18677fe588c790cNick Pelly                airplaneModeRadios.contains(Settings.System.RADIO_NFC);
39331949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
39431949217328bf2357ff044f0d18677fe588c790cNick Pelly            toggleableRadios.contains(Settings.System.RADIO_NFC);
39531949217328bf2357ff044f0d18677fe588c790cNick Pelly
39631949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
39731949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
39831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
39931949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
40031949217328bf2357ff044f0d18677fe588c790cNick Pelly
401e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    void updatePackageCache() {
402e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        PackageManager pm = getPackageManager();
403e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        List<PackageInfo> packages = pm.getInstalledPackages(0);
404e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        synchronized (this) {
405e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            mInstalledPackages = packages;
406e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        }
407e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    }
408e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
409fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int checkScreenState() {
410fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        if (!mPowerManager.isScreenOn()) {
411fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_OFF;
412fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else if (mKeyguard.isKeyguardLocked()) {
413fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_LOCKED;
414fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else {
415fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_UNLOCKED;
416fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
417fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
418fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
41931949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
42031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
42131949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
42231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
42331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
42431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
42531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
42631949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
42731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
42831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
42931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
43031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
43131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
43231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
43331949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
43431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
43531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
43631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
43731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
43831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
43931949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
44031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
44131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
44231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
44331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
44431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
44531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
44631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * process may temporarily enable the NFC adapter
44731949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
44831949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
44931949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
45031949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
45131949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
45231949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
45331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
45431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
45531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
45631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
45731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
45831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
45931949217328bf2357ff044f0d18677fe588c790cNick Pelly
4604467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
4614467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
4624467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
4634467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
4644467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
4654467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
4664467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
4674467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
4684467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
46931949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
47031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
47131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
47231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
47331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
47431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
47531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
47631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
4770fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    Log.d(TAG,"checking on firmware download");
4781668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
47931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
4801668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
4810fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is on. Doing normal stuff");
48231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
4830fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
4840fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is off.  Checking firmware version");
4850fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
48631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
48731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
48831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
48931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
49031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
49131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        executeEeWipe();
49231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
49331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
49431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_EE_WIPE:
49531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    executeEeWipe();
49631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
49731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
498d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
499d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
500d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
50131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
50231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
50331949217328bf2357ff044f0d18677fe588c790cNick Pelly
50431949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
50531949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
50631949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
50731949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
50831949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
50931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
51031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
51131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
51231949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
51331949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
51431949217328bf2357ff044f0d18677fe588c790cNick Pelly
5150c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
51631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!mDeviceHost.initialize()) {
51731949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Error enabling NFC");
51831949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_OFF);
51931949217328bf2357ff044f0d18677fe588c790cNick Pelly                return false;
52031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
52131949217328bf2357ff044f0d18677fe588c790cNick Pelly
52231949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized(NfcService.this) {
52331949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
52431949217328bf2357ff044f0d18677fe588c790cNick Pelly
5250b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
52631949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
52731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
52831949217328bf2357ff044f0d18677fe588c790cNick Pelly
529d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
530d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
53131949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
5320c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
533fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
53431949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
53531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
53631949217328bf2357ff044f0d18677fe588c790cNick Pelly
53731949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
53831949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
53931949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
54031949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
54131949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
54231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
54331949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
54431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
54531949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
54631949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
54731949217328bf2357ff044f0d18677fe588c790cNick Pelly
54831949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
54931949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
55031949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
55131949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
55231949217328bf2357ff044f0d18677fe588c790cNick Pelly            WatchDogThread watchDog = new WatchDogThread();
55331949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
55431949217328bf2357ff044f0d18677fe588c790cNick Pelly
55577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
55631949217328bf2357ff044f0d18677fe588c790cNick Pelly
55731949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
55831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
55931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
56031949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
561fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
56231949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
56331949217328bf2357ff044f0d18677fe588c790cNick Pelly
5640b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
56531949217328bf2357ff044f0d18677fe588c790cNick Pelly
56631949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
56731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
56831949217328bf2357ff044f0d18677fe588c790cNick Pelly
56931949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
57031949217328bf2357ff044f0d18677fe588c790cNick Pelly
57131949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_OFF);
57231949217328bf2357ff044f0d18677fe588c790cNick Pelly
573d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
574d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
57531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
57631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
57731949217328bf2357ff044f0d18677fe588c790cNick Pelly
57831949217328bf2357ff044f0d18677fe588c790cNick Pelly        void executeEeWipe() {
57931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // TODO: read SE reset list from /system/etc
58031949217328bf2357ff044f0d18677fe588c790cNick Pelly            byte[][]apdus = EE_WIPE_APDUS;
58131949217328bf2357ff044f0d18677fe588c790cNick Pelly
58231949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
58331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (tempEnable) {
58431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!enableInternal()) {
585ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
58631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
587f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
588f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
58931949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Executing SE wipe");
59031949217328bf2357ff044f0d18677fe588c790cNick Pelly            int handle = mSecureElement.doOpenSecureElementConnection();
59131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (handle == 0) {
59231949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Could not open the secure element");
59331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (tempEnable) {
59431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
59531949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
59631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return;
59731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
59831949217328bf2357ff044f0d18677fe588c790cNick Pelly
59931949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
60031949217328bf2357ff044f0d18677fe588c790cNick Pelly
60131949217328bf2357ff044f0d18677fe588c790cNick Pelly            for (byte[] cmd : apdus) {
602ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                byte[] resp = mSecureElement.doTransceive(handle, cmd);
603ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                if (resp == null) {
604ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
605ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    break;
606ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                }
60731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
60831949217328bf2357ff044f0d18677fe588c790cNick Pelly
60931949217328bf2357ff044f0d18677fe588c790cNick Pelly            mDeviceHost.resetTimeouts();
61031949217328bf2357ff044f0d18677fe588c790cNick Pelly            mSecureElement.doDisconnect(handle);
61131949217328bf2357ff044f0d18677fe588c790cNick Pelly
61231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (tempEnable) {
61331949217328bf2357ff044f0d18677fe588c790cNick Pelly                disableInternal();
61431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
61531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
61631949217328bf2357ff044f0d18677fe588c790cNick Pelly
61731949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
6182a3f6f141fdaf746a81ce850a8ab0ef251041966mike wakerly            synchronized (NfcService.this) {
61931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
62031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
62131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
62231949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
62331949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
62431949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
62531949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
62631949217328bf2357ff044f0d18677fe588c790cNick Pelly                mContext.sendBroadcast(intent);
62731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
62831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
62931949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
63031949217328bf2357ff044f0d18677fe588c790cNick Pelly
63131949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
63231949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
63331949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
63431949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
63531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
6360e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
6370e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
638d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
639d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
640d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
641d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
642d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
643d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
644d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
645d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
646d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
647d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
648d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
649d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
650d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
651d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
652d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
653d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
654d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
655d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
656d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
657d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
6580e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
6592f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    public void onTerminate() {
6602f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        super.onTerminate();
6612f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        // NFC application is persistent, it should not be destroyed by framework
6620e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        Log.wtf(TAG, "NFC service is under attack!");
6630e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
6640e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
6654a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
666fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
6670e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
66893d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
6690e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
67031949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
6711668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen
6721668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
6731668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                if (!mIsAirplaneToggleable) {
6741668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    Log.i(TAG, "denying enable() request (airplane mode)");
6751668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    return false;
6761668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                }
6771668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                // Make sure the override survives a reboot
6781668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
6791668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
680f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
68131949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
68231949217328bf2357ff044f0d18677fe588c790cNick Pelly
68331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
684f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
685f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
686fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
687290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi        public boolean disable(boolean saveState) throws RemoteException {
68893d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
6890e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
690290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            if (saveState) {
691290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi                saveNfcOnSetting(false);
692290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            }
693290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi
69431949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
69531949217328bf2357ff044f0d18677fe588c790cNick Pelly
69631949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
697f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
698f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
699fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
7000b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
70131949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
7029993a5a96a862cea4512509b413d0de6cacb7c14Nick Pelly                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
70331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
704d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
705d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
706d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
7070b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
708d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
709d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
7100b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
71131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
71231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
7130b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
7140b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
71531949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
7160b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
71731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
71877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
719d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
720d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
721d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
722d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
723d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
724d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
7250b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
726d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
727d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
7280b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
72931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
73031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
7310b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
7320b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
73331949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
7340b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
73531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
73677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
737d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
738d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
739d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
740d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
741d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
742d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
7430b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
74424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
74505973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
746a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
7470b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
7480b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
7490b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
7500b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
751ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
752a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
753a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
754a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
755a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
756a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
757a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
758a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
759a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
760a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
761a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
762a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
763a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
764a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
765a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
76624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
76724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
76824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
76924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
77024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
77149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
7720b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
7732094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
7742094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
7752094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
776c96f982f8c0fa061701143a27395acf3b24dfb54Nick Pelly        public void setNdefPushCallback(INdefPushCallback callback) {
777ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
778c96f982f8c0fa061701143a27395acf3b24dfb54Nick Pelly            mP2pLinkManager.setNdefCallback(callback);
779ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
780ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
781ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
7820e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
7830e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
7840e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
7850e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
786fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
787c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) {
788c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
78949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mExtrasService;
7900bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
7910bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
792fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
79331949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
79431949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
79531949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
79631949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
79731949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
79831949217328bf2357ff044f0d18677fe588c790cNick Pelly
79931949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
80031949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
80131949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
8020e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
803391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly
804391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        @Override
805ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        public void dispatch(Tag tag) throws RemoteException {
806391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            enforceAdminPerm(mContext);
807ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            mNfcDispatcher.dispatchTag(tag);
808391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        }
8090c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
8100c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        @Override
8110c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
8120c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            enforceAdminPerm(mContext);
8130c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
8140c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pInitiatorModes(initiatorModes);
8150c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pTargetModes(targetModes);
8160c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.disableDiscovery();
8170c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.enableDiscovery();
8180c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        }
819c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
8200e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
8214a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
822fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
823f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
824d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
825bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
826f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
827f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
82831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
829f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
830f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
831f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
832f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
833f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
834f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
835b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
836b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
83721545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
838b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
839f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
840f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
841fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
842f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
843f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
844f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
845fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
846ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
847d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
848bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
849f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
850f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
85131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
852f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
853f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
854f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
855f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
856f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
857b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
858b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
859f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
860ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
861cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            if (!tag.isPresent()) {
862cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
863cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            }
864cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen
8651b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen            if (technology == TagTechnology.NFC_B) {
8661b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen                return ErrorCodes.ERROR_NOT_SUPPORTED;
8671b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen            }
8681b1e68327701225b728d43226049ad7a5dee4bcdMartijn Coenen
869ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
870ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
871ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
872ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
873ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
874ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
875ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
876ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
877f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
878f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
879fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
880aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
881aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
882aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
883f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
884aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
885aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
88631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
887aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
888aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
889aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
890aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
891f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
892aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
893aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
894aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
895aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
896aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
897aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
898aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
899aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
900aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
901aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
902aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
903b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
904d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
905bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
906f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
90731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
908f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
909f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
910f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
911f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
912f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
913f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
914b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
915f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
916f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
917f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
918f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
919fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
920b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
921f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
922b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
923b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
92431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
925b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
926b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
927b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
928b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
929f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
930b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
931b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
932b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
933b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
934ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
935b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
936b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
937fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
938f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
939182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
940182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen
941f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
942f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
943f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
94431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
9452c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
946f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
947f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
948f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
949f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
9503ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
9512c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
9522c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
953f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
95470bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
955f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
956f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
957fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9589d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
95997c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
960d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
961bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
962f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
963f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
964f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
965f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
96631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
967f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
968f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
969f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
970f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
971f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
972f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
973bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
974bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
975bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
976bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
9779d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
9789d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
979bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
980bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
981bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
982bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
983bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
984bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
985bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
986bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
987bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
988f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
989f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
990f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
991f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
992fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9933fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
994d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
995bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
996f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
997f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
998f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
99931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1000f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1001f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1002f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1003f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1004f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1005f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1006f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
1007f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
1008f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1009f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
1010f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1011f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
1012f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
1013f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
1014f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
1015f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1016f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1017f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1018f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1019f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1020f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1021fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
10223fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1023d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1024bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1025f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1026f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1027f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
102831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1029f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1030f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1031f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1032f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1033f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1034f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1035f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1036f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1037f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1038791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1039791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen
1040f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1041f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1042f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1043f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1044f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1045f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1046f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1047f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1048fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
10493fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
10503fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1051f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1052f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1053fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
10543fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
105503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
105603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1057f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
105803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
105903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
106031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
106103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
106203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
106303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
106403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1065f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
106603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
106703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
106803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
106903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1070f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
107103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1072f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
107303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
107403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1075f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1076f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
10770aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
10780aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
10790aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
10800aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1081f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
10820aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10830aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
108431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
10850aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
10860aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10870aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10880aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1089f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
10900aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
10910aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
10920aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10930aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
10940aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
10950aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1096f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
10970aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
10980aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
10990aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
11000aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
11011b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
11023fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
11033fb14d0868594c78a777e805545209636814e223Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
11043fb14d0868594c78a777e805545209636814e223Martijn Coenen
1105f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
11063fb14d0868594c78a777e805545209636814e223Martijn Coenen
11073fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
110831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
11093fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
11103fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
11113fb14d0868594c78a777e805545209636814e223Martijn Coenen
11123fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1113f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
11143fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
11153fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
11163fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
11173fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
11183fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
11193fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
11203fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
11213fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
11223fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
11233fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
11243fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1125391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                tag.findAndReadNdef();
11263fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
11273fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
11284a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
11293fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
11303fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
11313fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
11323fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
11333fb14d0868594c78a777e805545209636814e223Martijn Coenen
11341b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1135fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
11361b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1137f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1138fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1139fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1140fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1141fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1142fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1143dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1144dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1145dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1146358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
1147358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1148358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1149358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1150358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1151358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1152358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1153dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
1154dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1155dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1156f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
11571b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1158bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1159bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1160bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1161bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1162bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1163bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1164bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1165bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1166bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1167bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1168ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen
1169ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        @Override
1170ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1171ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen            return mDeviceHost.getExtendedLengthApdusSupported();
1172ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        }
1173c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
1174f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
117592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly    void _nfcEeClose(int callingPid, IBinder binder) throws IOException {
1176dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // Blocks until a pending open() or transceive() times out.
1177dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        //TODO: This is incorrect behavior - the close should interrupt pending
1178dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // operations. However this is not supported by current hardware.
1179dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
11800571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly        synchronized (NfcService.this) {
118131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1182dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC adapter is disabled");
1183dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1184dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (mOpenEe == null) {
1185dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC EE closed");
1186dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
118792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (callingPid != -1 && callingPid != mOpenEe.pid) {
1188dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new SecurityException("Wrong PID");
1189dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
119092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (mOpenEe.binder != binder) {
119192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                throw new SecurityException("Wrong binder handle");
119292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            }
1193dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
119492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            binder.unlinkToDeath(mOpenEe, 0);
1195f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
1196dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mSecureElement.doDisconnect(mOpenEe.handle);
1197dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mOpenEe = null;
1198dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1199fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1200dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        }
1201dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    }
1202dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
12034a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
120449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeNoException() {
120549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
120649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", 0);
120749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
120849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
120949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeIoException(IOException e) {
121049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
121149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", -1);
121249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putString("m", e.getMessage());
121349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
121449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
12150bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1216bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1217c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle open(String pkg, IBinder b) throws RemoteException {
1218c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1219bd555ee64250126b60b24814120a2049943920caNick Pelly
122049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
122149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
122249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                _open(b);
122349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
122449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
122549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
12260bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
122749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
122849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
12290bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1230c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly        private void _open(IBinder b) throws IOException {
123149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
123231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
123349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC adapter is disabled");
123449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
123549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe != null) {
123649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE already open");
123749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
12380bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
123949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                int handle = mSecureElement.doOpenSecureElementConnection();
124049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (handle == 0) {
124149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE failed to open");
124249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
1243f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
1244ba6401757f8017faeb77423f2d08fd51be1d1051Nick Pelly
124592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
124649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                try {
124749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    b.linkToDeath(mOpenEe, 0);
124849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                } catch (RemoteException e) {
124949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    mOpenEe.binderDied();
125049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
125184e1e0adc2516afd35ebab029a52e764e0490559Jason parks
125284e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // Add the calling package to the list of packages that have accessed
125384e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // the secure element.
125484e1e0adc2516afd35ebab029a52e764e0490559Jason parks                for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) {
125584e1e0adc2516afd35ebab029a52e764e0490559Jason parks                    mSePackages.add(packageName);
125684e1e0adc2516afd35ebab029a52e764e0490559Jason parks                }
125749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly           }
12580bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
12590bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1260bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
126192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public Bundle close(String pkg, IBinder binder) throws RemoteException {
1262c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1263c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
126449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
126549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
126692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                _nfcEeClose(getCallingPid(), binder);
126749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
126849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
126949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
12700bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
127149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
127249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
12730bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1274bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1275c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle transceive(String pkg, byte[] in) throws RemoteException {
1276c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1277bd555ee64250126b60b24814120a2049943920caNick Pelly
127849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
127949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            byte[] out;
128049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
128149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                out = _transceive(in);
128249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
128349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result.putByteArray("out", out);
128449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
128549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeIoException(e);
12860bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
128749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
128849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
12890bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1290c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly        private byte[] _transceive(byte[] data) throws IOException {
129149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
129231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
129349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC is not enabled");
129449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
12950571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly                if (mOpenEe == null) {
129649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE is not open");
129749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
129849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (getCallingPid() != mOpenEe.pid) {
129949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new SecurityException("Wrong PID");
130049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
13010bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
13020bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
130349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mSecureElement.doTransceive(mOpenEe.handle, data);
13040bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
13050bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1306bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1307c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public int getCardEmulationRoute(String pkg) throws RemoteException {
1308c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
130949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mEeRoutingState;
13100bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
13110bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1312bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1313c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
1314c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
131549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            mEeRoutingState = route;
1316fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
13170bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
1318bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
1319bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1320c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void authenticate(String pkg, byte[] token) throws RemoteException {
1321c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1322bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1323c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
13240bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
132549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** resources kept while secure element is open */
132649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private class OpenSecureElement implements IBinder.DeathRecipient {
132749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int pid;  // pid that opened SE
132892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // binder handle used for DeathReceipient. Must keep
132992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // a reference to this, otherwise it can get GC'd and
133092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // the binder stub code might create a different BinderProxy
133192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // for the same remote IBinder, causing mismatched
133292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // link()/unlink()
133392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public IBinder binder;
133449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int handle; // low-level handle
133592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public OpenSecureElement(int pid, int handle, IBinder binder) {
133649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.pid = pid;
133749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.handle = handle;
133892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            this.binder = binder;
133949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1340bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
134149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void binderDied() {
134249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized (NfcService.this) {
134392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                Log.i(TAG, "Tracked app " + pid + " died");
134449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                pid = -1;
13450bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas                try {
134692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    _nfcEeClose(-1, binder);
1347dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                } catch (IOException e) { /* already closed */ }
13480bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
13490bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
135092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        @Override
135192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public String toString() {
135292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            return new StringBuilder('@').append(Integer.toHexString(hashCode())).append("[pid=")
135392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    .append(pid).append(" handle=").append(handle).append("]").toString();
135492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        }
13550bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    }
13560bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
13579a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    boolean isNfcEnabledOrShuttingDown() {
13589a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        synchronized (this) {
13599a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
13609a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        }
13619a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    }
13629a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen
136331949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
136431949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
136531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1366e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1367aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1368aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
136931949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
13702edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        boolean mWatchDogCanceled = false;
13712edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
13722edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
13732edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            boolean slept = false;
13742edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            while (!slept) {
13752edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                try {
13762edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    Thread.sleep(10000);
13772edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    slept = true;
13782edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                } catch (InterruptedException e) { }
13792edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
13802edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            synchronized (this) {
13812edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                if (!mWatchDogCanceled) {
13822edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    // Trigger watch-dog
13832edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                    Log.e(TAG, "Watch dog triggered");
13842083287b83a587d8f6e9ad829ea18041dc17d842Nick Pelly                    mDeviceHost.doAbort();
13852edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
13862edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
13872edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
13882edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
13892edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            mWatchDogCanceled = true;
13902edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
13912edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
13922edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
1393fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /**
1394fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1395fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     */
1396fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    void applyRouting(boolean force) {
1397e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
13989a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            if (!isNfcEnabledOrShuttingDown() || mOpenEe != null) {
1399fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                // PN544 cannot be reconfigured while EE is open
1400e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1401e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1402fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1403fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            if (PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE && mScreenState == SCREEN_STATE_OFF) {
1404fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                /* TODO undo this after the LLCP stack is fixed.
1405fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                 * Use a different sequence when turning the screen off to
1406fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                 * workaround race conditions in pn544 libnfc. The race occurs
1407fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                 * when we change routing while there is a P2P target connect.
1408fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                 * The async LLCP callback will crash since the routing code
1409fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                 * is overwriting globals it relies on.
1410fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                 */
1411fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (POLLING_MODE > SCREEN_STATE_OFF) {
1412fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    if (force || mNfcPollingEnabled) {
1413fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        Log.d(TAG, "NFC-C OFF, disconnect");
1414fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mNfcPollingEnabled = false;
1415fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mDeviceHost.disableDiscovery();
1416fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        maybeDisconnectTarget();
1417fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1418fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1419e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1420fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    if (force || mNfceeRouteEnabled) {
1421fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        Log.d(TAG, "NFC-EE OFF");
1422fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mNfceeRouteEnabled = false;
1423fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mDeviceHost.doDeselectSecureElement();
1424fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1425fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1426fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return;
1427fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            }
1428fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1429fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            // configure NFC-EE routing
1430fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
1431fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1432fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (force || !mNfceeRouteEnabled) {
1433fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    Log.d(TAG, "NFC-EE ON");
1434fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mNfceeRouteEnabled = true;
1435e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                    mDeviceHost.doSelectSecureElement();
1436fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1437fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            } else {
1438fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (force ||  mNfceeRouteEnabled) {
1439fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    Log.d(TAG, "NFC-EE OFF");
1440fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mNfceeRouteEnabled = false;
1441e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                    mDeviceHost.doDeselectSecureElement();
1442e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                }
1443fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            }
1444fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1445fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            // configure NFC-C polling
1446fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            if (mScreenState >= POLLING_MODE) {
1447fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (force || !mNfcPollingEnabled) {
1448fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    Log.d(TAG, "NFC-C ON");
1449fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mNfcPollingEnabled = true;
1450fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mDeviceHost.enableDiscovery();
1451fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1452221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            } else {
1453fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (force || mNfcPollingEnabled) {
1454fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    Log.d(TAG, "NFC-C OFF");
1455fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mNfcPollingEnabled = false;
1456fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mDeviceHost.disableDiscovery();
1457fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1458221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
145965945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
146065945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
146165945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
14622436ffe91853535fad87b7a8e03d8883bae20f20Arnaud Ferir    /** Disconnect any target if present */
146331949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
14649a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        if (!isNfcEnabledOrShuttingDown()) {
1465a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1466a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
146731949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
146831949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
146931949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
147031949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
147131949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
147231949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
147331949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
147431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
147531949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
147631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
147731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
147831949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
147931949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
148031949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
148131949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
148231949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
148331949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
148431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
148531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
148631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
148731949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
148831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
148931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1490bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1491bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1492bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1493bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1494bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
149531949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
149631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
149731949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
149831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
149931949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
15002f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
150131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
15020e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1503f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1504f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
150531949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
150631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
150731949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1508f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1509b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1510b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
151131949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
151231949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
151331949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
151431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
1515f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1516f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1517d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
15184a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1519c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            throws LlcpException {
15204a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1521d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1522d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1523d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
15243b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
1525e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen            throws LlcpException {
15263b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
1527e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    }
1528e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen
1529e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    /** For use by code in this process */
15304a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1531c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            int linearBufferLength) throws LlcpException {
15324a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1533d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1534d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
153557d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
1536b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
153757d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
153857d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
1539b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
1540b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
1541b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
1542b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
1543b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
1544b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1545b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
15463fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
1547b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
1548b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
154931949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
155031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
155131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
155231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
155331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
155431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
155531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
155631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
155731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
155831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new int[] { TagTechnology.NDEF },
155931949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new Bundle[] { extras });
156031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
156131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
1562ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                    boolean delivered = mNfcDispatcher.dispatchTag(tag);
156331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (delivered) {
1564d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
156577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    } else {
1566d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
156731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
156831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
156931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
157057d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
157131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
157231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
157331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
1574d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    playSound(SOUND_START);
1575391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    NdefMessage ndefMsg = tag.findAndReadNdef();
1576c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
1577391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    if (ndefMsg != null) {
157831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        tag.startPresenceChecking();
1579ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                        dispatchTagEndpoint(tag);
158031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
158131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
158231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.startPresenceChecking();
1583ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                            dispatchTagEndpoint(tag);
158431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
158531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
1586d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
158731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
158831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
158931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
159031949217328bf2357ff044f0d18677fe588c790cNick Pelly
159131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_CARD_EMULATION:
159231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Emulation message");
159331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] aid = (byte[]) msg.obj;
159431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
159531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent aidIntent = new Intent();
159631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.setAction(ACTION_AID_SELECTED);
159731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.putExtra(EXTRA_AID, aid);
159831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
159914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(aidIntent);
160031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
160131949217328bf2357ff044f0d18677fe588c790cNick Pelly
160231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_EMV_CARD_REMOVAL:
160331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Removal message");
160431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
160531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent cardRemovalIntent = new Intent();
160631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
160731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
160814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(cardRemovalIntent);
160931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
161031949217328bf2357ff044f0d18677fe588c790cNick Pelly
161131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_APDU_RECEIVED:
161231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "APDU Received message");
161331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] apduBytes = (byte[]) msg.obj;
161431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
161531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent apduReceivedIntent = new Intent();
161631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
161731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (apduBytes != null && apduBytes.length > 0) {
161831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
161931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
162031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
162114a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(apduReceivedIntent);
162231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
162331949217328bf2357ff044f0d18677fe588c790cNick Pelly
162431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_MIFARE_ACCESS:
162531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "MIFARE access message");
162631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
162731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] mifareCmd = (byte[]) msg.obj;
162831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent mifareAccessIntent = new Intent();
162931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
163031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mifareCmd != null && mifareCmd.length > 1) {
163131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        int mifareBlock = mifareCmd[1] & 0xff;
163231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
163331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
163431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
163531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
163614a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(mifareAccessIntent);
163731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
1638c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
163931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
164031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
164131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
164231949217328bf2357ff044f0d18677fe588c790cNick Pelly
164331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
164431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
164531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
164631949217328bf2357ff044f0d18677fe588c790cNick Pelly
164731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
164831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
164931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
165031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
165131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
165231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
165331949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
165431949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
165531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
165631949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
165731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
165831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
165931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
166031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
166131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
166231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
166331949217328bf2357ff044f0d18677fe588c790cNick Pelly
166477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
166531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
166631949217328bf2357ff044f0d18677fe588c790cNick Pelly
166731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_TARGET_DESELECTED:
166831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Broadcast Intent Target Deselected */
166931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Target Deselected");
167031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent intent = new Intent();
167131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
167231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting Intent");
167331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
167431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
167531949217328bf2357ff044f0d18677fe588c790cNick Pelly
167631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_ACTIVATED: {
167731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
167831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOnIntent = new Intent();
167931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
168014a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOnIntent);
168131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
168231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
168331949217328bf2357ff044f0d18677fe588c790cNick Pelly
168431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_DEACTIVATED: {
168531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
168631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOffIntent = new Intent();
168731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
168814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOffIntent);
168931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
169031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
169131949217328bf2357ff044f0d18677fe588c790cNick Pelly
169231949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
169331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
169431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
169531949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
1696b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1697d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
169814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        private void sendSeBroadcast(Intent intent) {
169914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
1700c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            // Resume app switches so the receivers can start activites without delay
1701c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfcDispatcher.resumeAppSwitches();
1702c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
1703e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            synchronized(this) {
1704e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                for (PackageInfo pkg : mInstalledPackages) {
1705e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (pkg != null && pkg.applicationInfo != null) {
1706e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
1707e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            intent.setPackage(pkg.packageName);
1708e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            mContext.sendBroadcast(intent);
1709e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        }
1710c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
1711c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
1712c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
171314a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        }
171414a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton
1715d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
1716d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
1717d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1718d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1719d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1720d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
1721d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
1722d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
1723d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
1724d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
1725d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
172631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
172731949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
172831949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
1729d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
173077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                            mP2pLinkManager.onLlcpActivated();
1731d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
1732d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
1733d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
1734d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1735d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
1736d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
1737d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
1738d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1739d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
1740d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1741d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1742d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1743d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
1744d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
1745d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
1746d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
1747d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1748d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1749d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1750d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
1751d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
1752d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
1753d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
1754d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
175531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
175631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
175731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
1758d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
175977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
1760d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
1761d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1762d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1763d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
1764d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1765d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
1766d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1767d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
1768d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
1769d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1770ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        private void dispatchTagEndpoint(TagEndpoint tagEndpoint) {
1771f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
1772f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
1773f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
1774ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            if (!mNfcDispatcher.dispatchTag(tag)) {
1775f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
1776d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
1777d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else {
1778d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
17793fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
17803fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
1781b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
1782b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1783b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
178449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
1785fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
1786fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1787fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        protected Void doInBackground(Integer... params) {
1788fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            synchronized (NfcService.this) {
1789fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (params == null || params.length != 1) {
1790fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    // force apply current routing
1791fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    applyRouting(true);
1792fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    return null;
1793161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
1794fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                mScreenState = params[0].intValue();
1795fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1796fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                boolean needWakelock = mScreenState == SCREEN_STATE_OFF;
1797fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (needWakelock) {
1798fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mWakeLock.acquire();
1799fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1800fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                applyRouting(false);
1801fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (needWakelock) {
1802fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    mWakeLock.release();
1803161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
1804fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return null;
18057c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
18067c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
18077c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
18087c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
18090e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
18100e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        @Override
18110e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public void onReceive(Context context, Intent intent) {
181231949217328bf2357ff044f0d18677fe588c790cNick Pelly            String action = intent.getAction();
181331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (action.equals(
1814f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
1815fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                // Perform applyRouting() in AsyncTask to serialize blocking calls
1816fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                new ApplyRoutingTask().execute();
1817fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            } else if (action.equals(Intent.ACTION_SCREEN_ON)
1818fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    || action.equals(Intent.ACTION_SCREEN_OFF)
1819fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    || action.equals(Intent.ACTION_USER_PRESENT)) {
1820fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                // Perform applyRouting() in AsyncTask to serialize blocking calls
1821fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                int screenState = SCREEN_STATE_OFF;
1822fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1823fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    screenState = SCREEN_STATE_OFF;
1824fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1825fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    screenState = mKeyguard.isKeyguardLocked() ?
1826fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                            SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
1827fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1828fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    screenState = SCREEN_STATE_ON_UNLOCKED;
1829fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1830fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
183131949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
183231949217328bf2357ff044f0d18677fe588c790cNick Pelly                EnableDisableTask eeWipeTask = new EnableDisableTask();
183331949217328bf2357ff044f0d18677fe588c790cNick Pelly                eeWipeTask.execute(TASK_EE_WIPE);
183431949217328bf2357ff044f0d18677fe588c790cNick Pelly                try {
183531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eeWipeTask.get();  // blocks until EE wipe is complete
183631949217328bf2357ff044f0d18677fe588c790cNick Pelly                } catch (ExecutionException e) {
183731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.w(TAG, "failed to wipe NFC-EE");
183831949217328bf2357ff044f0d18677fe588c790cNick Pelly                } catch (InterruptedException e) {
183931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.w(TAG, "failed to wipe NFC-EE");
184031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
1841e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
1842e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
1843e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
1844e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1845e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                updatePackageCache();
1846e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
1847e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
1848e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    // Clear the NFCEE access cache in case a UID gets recycled
1849e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    mNfceeAccessControl.invalidateCache();
1850e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
1851e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
1852e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (dataRemoved) {
1853e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        Uri data = intent.getData();
1854e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (data == null) return;
1855e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        String packageName = data.getSchemeSpecificPart();
18567a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton
1857e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        synchronized (NfcService.this) {
1858e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            if (mSePackages.contains(packageName)) {
1859e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                new EnableDisableTask().execute(TASK_EE_WIPE);
1860e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                mSePackages.remove(packageName);
1861e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            }
18627a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                        }
1863bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                    }
1864bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
186531949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
186631949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
186731949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
186831949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
186931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
187031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
187131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
187231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
187331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
187431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
18751668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
18761668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
187731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
187831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
187931949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
188031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
188131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
1882f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1883f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1884f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
188531949217328bf2357ff044f0d18677fe588c790cNick Pelly
188631949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** Returns true if airplane mode is currently on */
188731949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
188831949217328bf2357ff044f0d18677fe588c790cNick Pelly        return Settings.System.getInt(mContext.getContentResolver(),
188931949217328bf2357ff044f0d18677fe588c790cNick Pelly                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
189031949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
189131949217328bf2357ff044f0d18677fe588c790cNick Pelly
1892fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** for debugging only - no i18n */
189331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
189431949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
189531949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
189631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
189731949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
189831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
189931949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
190031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
190131949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
190231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
190331949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
190431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
190531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
190631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
190731949217328bf2357ff044f0d18677fe588c790cNick Pelly
1908fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** For debugging only - no i18n */
1909fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static String screenStateToString(int screenState) {
1910fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        switch (screenState) {
1911fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_OFF:
1912fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "OFF";
1913fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_LOCKED:
1914fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_LOCKED";
1915fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_UNLOCKED:
1916fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_UNLOCKED";
1917fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            default:
1918fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "UNKNOWN";
1919fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
1920fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
1921fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
192231949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
192350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
192450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
192550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
192650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
192750effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
192850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
192950effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
193050effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
193131949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
193231949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
19330b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
1934fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mScreenState=" + screenStateToString(mScreenState));
1935fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfcPollingEnabled=" + mNfcPollingEnabled);
1936fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfceeRouteEnabled=" + mNfceeRouteEnabled);
193731949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
193831949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
193992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            pw.println("mOpenEe=" + mOpenEe);
194077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
1941c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfceeAccessControl.dump(fd, pw, args);
1942391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            mNfcDispatcher.dump(fd, pw, args);
194356f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
1944c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
194531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
194631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
194774180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
1948