NfcService.java revision 3e38dca2bc7c7629d7159663d597a1e886d85527
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;
264bbd47e5507d4c47a4d722216606307e45195a0aMartijn Coenenimport com.android.nfc.dhimpl.NativeNfcManager;
274bbd47e5507d4c47a4d722216606307e45195a0aMartijn Coenenimport com.android.nfc.dhimpl.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;
407d8987f233985a5ff29226890e11012275d325f5Martijn Coenenimport android.content.res.Resources.NotFoundException;
41d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.AudioManager;
42d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.SoundPool;
433fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamiltonimport android.net.Uri;
44f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.ErrorCodes;
45f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.FormatException;
462094515fca0cfa0ac87e9cc260d3953d416afe3eJason parksimport android.nfc.INdefPushCallback;
470e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.INfcAdapter;
4849d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.nfc.INfcAdapterExtras;
49f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.INfcTag;
50f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NdefMessage;
51f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NfcAdapter;
520e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.Tag;
5324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.nfc.TechListParcel;
549d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenenimport android.nfc.TransceiveResult;
55aca0d055a82da850c27f6872405602ad5f3fee7bJeff Hamiltonimport android.nfc.tech.Ndef;
5681c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport android.nfc.tech.TagTechnology;
577c034a7fe7d36b1ab039af2c44717812ea02657eNick Pellyimport android.os.AsyncTask;
5850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Rootimport android.os.Binder;
59b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamiltonimport android.os.Bundle;
60b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Handler;
6149d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.os.IBinder;
62b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Message;
63533043d1003de2f6a20a29201100d94c3c7bc9caNick Pellyimport android.os.PowerManager;
644467dca5650a170af5020c10a8ccb25f86f1007fNick Pellyimport android.os.Process;
65f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.os.RemoteException;
6613d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.os.ServiceManager;
673e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenenimport android.os.SystemClock;
68525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.os.UserHandle;
69d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.provider.Settings;
70f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.util.Log;
71f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
7231949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.FileDescriptor;
7357d376f1ee1a3939977b95759525585abb9601fbJeff Hamiltonimport java.io.IOException;
7431949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.PrintWriter;
7531949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.Arrays;
763ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamiltonimport java.util.HashMap;
7784e1e0adc2516afd35ebab029a52e764e0490559Jason parksimport java.util.HashSet;
78c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.util.List;
7931949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.concurrent.ExecutionException;
803ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
81525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectpublic class NfcService implements DeviceHostListener {
82bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
83bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
84c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = false;
8576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
86fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
87d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
88fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
89c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** Regular NFC permission */
90bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM = android.Manifest.permission.NFC;
91bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM_ERROR = "NFC permission required";
92c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
93c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** NFC ADMIN permission - only for system apps */
94bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
95bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
96bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
9777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
98f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
99416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
100416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
101416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
102416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
103416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
104416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
1051668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
106a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
107b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
108b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_CARD_EMULATION = 1;
109b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_ACTIVATION = 2;
110b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
111b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_TARGET_DESELECTED = 4;
112b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    static final int MSG_MOCK_NDEF = 7;
113c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_ACTIVATED = 8;
114c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_DEACTIVATED = 9;
1152c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_APDU_RECEIVED = 10;
1162c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
1172c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_MIFARE_ACCESS = 12;
118525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_ACTIVATED = 13;
119525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_DEACTIVATED = 14;
12057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    static final int MSG_LLCP_LINK_FIRST_PACKET = 15;
121b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
12231949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
12331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
12431949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
12531949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_EE_WIPE = 4;
12631949217328bf2357ff044f0d18677fe588c790cNick Pelly
127fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    // Screen state, used by mScreenState
128fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_UNKNOWN = 0;
129fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_OFF = 1;
130fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_LOCKED = 2;
131fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_UNLOCKED = 3;
132fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
13349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Copied from com.android.nfc_extras to avoid library dependency
13449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Must keep in sync with com.android.nfc_extras
13549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_OFF = 1;
13649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
1377efbf69a37134ccbd86a1f6b4121f16b4a80eaaeNick Pelly
138c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // Return values from NfcEe.open() - these are 1:1 mapped
139c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // to the thrown EE_EXCEPTION_ exceptions in nfc-extras.
140c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_IO = -1;
141c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_ALREADY_OPEN = -2;
142c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_INIT = -3;
143c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_LISTEN_MODE = -4;
144c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_EXT_FIELD = -5;
145c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_NFC_DISABLED = -6;
146c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
147fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** minimum screen state that enables NFC polling (discovery) */
148fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
149fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
150525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for NFC controller to initialize before watchdog
151525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off. This time is chosen large, because firmware download
152525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // may be a part of initialization.
153525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int INIT_WATCHDOG_MS = 90000;
154525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
155525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for routing to be applied before watchdog
156525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off
157525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int ROUTING_WATCHDOG_MS = 10000;
158525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1593e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Amount of time to wait before closing the NFCEE connection
1603e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // in a disable/shutdown scenario.
1613e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_OPERATIONS_MS = 5000;
1623e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Polling interval for waiting on NFCEE operations
1633e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_POLL_MS = 100;
1643e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
165d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
166d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
167d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
168d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
169d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
17049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_ON_DETECTED =
17149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
17249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_OFF_DETECTED =
17349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
17449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_AID_SELECTED =
17549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.AID_SELECTED";
17649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
17749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
1782c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_APDU_RECEIVED =
1792c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.APDU_RECEIVED";
1802c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_APDU_BYTES =
1812c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.APDU_BYTES";
1822c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1832c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_EMV_CARD_REMOVAL =
1842c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
1852c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1862c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_MIFARE_ACCESS_DETECTED =
1872c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
1882c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_MIFARE_BLOCK =
1892c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.MIFARE_BLOCK";
1902c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
191525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_ACTIVATED =
192525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_ACTIVATED";
193525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_DEACTIVATED =
194525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_DEACTIVATED";
19549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
19649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
19749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
1980bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    private NativeNfcSecureElement mSecureElement;
19949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private OpenSecureElement mOpenEe;  // null when EE closed
20049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private int mEeRoutingState;  // contactless interface routing
2010bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
202d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    // fields below must be used only on the UI thread and therefore aren't synchronized
203d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    boolean mP2pStarted = false;
204d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
2052f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
206fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
207525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // mSePackages holds packages that accessed the SE, but only for the owner user,
208525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // as SE access is not granted for non-owner users.
209fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    HashSet<String> mSePackages = new HashSet<String>();
210fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int mScreenState;
2117d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
212fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mIsNdefPushEnabled;
213fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfceeRouteEnabled;  // current Device Host state of NFC-EE routing
214fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfcPollingEnabled;  // current Device Host state of NFC-C polling
215e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    List<PackageInfo> mInstalledPackages; // cached version of installed packages
21631949217328bf2357ff044f0d18677fe588c790cNick Pelly
21731949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
21831949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
21931949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
22031949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
2212f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
2222f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
22305973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
2244a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
2250e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
2260e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
227525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mRoutingWakeLock;
228525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mEeWakeLock;
229525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
230d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
231d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
232d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
233d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
23477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
2354a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
2364a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
2374a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterExtrasService mExtrasService;
23831949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
23931949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
240c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    NfceeAccessControl mNfceeAccessControl;
2412ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
24276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
243fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    private PowerManager mPowerManager;
244275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
2457d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private HandoverManager mHandoverManager;
2467d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private ContentResolver mContentResolver;
247d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
248d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    private static NfcService sService;
249d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
25093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceAdminPerm(Context context) {
251c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
25293d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
25393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
254c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public void enforceNfceeAdminPerm(String pkg) {
255c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (pkg == null) {
256c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException("caller must pass a package name");
257c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
258c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
259c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (!mNfceeAccessControl.check(Binder.getCallingUid(), pkg)) {
260c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
261c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    " denies NFCEE access to " + pkg);
262c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
263525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
264525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            throw new SecurityException("only the owner is allowed to call SE APIs");
265525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
26693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
26793d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
268d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
269d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
270d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
271f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2720e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
273f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
274f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
275f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
276f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
277f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
278f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
279f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
280d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
281f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationDeselected() {
282f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
283f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
284f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
285f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
286f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
287f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
288d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
289f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationAidSelected(byte[] aid) {
290f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_CARD_EMULATION, aid);
291f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
292f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
293f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
294f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
295f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
296f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
297f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
298f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
299f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
300f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
301f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
302f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
303f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
304d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
305f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
306f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
307f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
308f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
30957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    /**
31057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     * Notifies P2P Device detected, first packet received over LLCP link
31157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     */
31257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    @Override
31357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
31457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
31557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    }
31657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
317d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
318f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldActivated() {
319f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
320f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
321f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
322d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
323f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldDeactivated() {
324f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
325f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
326f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
327f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
328525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenActivated() {
329525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        sendMessage(NfcService.MSG_SE_LISTEN_ACTIVATED, null);
330525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
331525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
332525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
333525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenDeactivated() {
334525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        sendMessage(NfcService.MSG_SE_LISTEN_DEACTIVATED, null);
335525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
336525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
337525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
338525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
339442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeApduReceived(byte[] apdu) {
340442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
341442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
342442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
343442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
344442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeEmvCardRemoval() {
345442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
346442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
347442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
348442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
349442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeMifareAccess(byte[] block) {
350442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
351442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
352442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
353525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public NfcService(Application nfcApplication) {
3544a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
3554a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
356ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly        mExtrasService = new NfcAdapterExtrasService();
3574a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton
3582f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
3592f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
360d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
361d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
362525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext = nfcApplication;
3637d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mContentResolver = mContext.getContentResolver();
364525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDeviceHost = new NativeNfcManager(mContext, this);
36574180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
3667d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager = new HandoverManager(mContext);
3677d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        boolean isNfcProvisioningEnabled = false;
3687d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        try {
3697d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
3707d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    R.bool.enable_nfc_provisioning);
3717d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } catch (NotFoundException e) {
3727d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
3737d8987f233985a5ff29226890e11012275d325f5Martijn Coenen
3747d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        if (isNfcProvisioningEnabled) {
3757d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
3767d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
3777d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } else {
3787d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = false;
3797d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
380525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
3817d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager.setEnabled(!mInProvisionMode);
3827d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
3837d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
384525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
38524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
38637058bf7b59def2f9a565ae5b16aae54e80e9e95Sunil Jogi        mSecureElement = new NativeNfcSecureElement(mContext);
387eab09ad7204fe1f0feaca33efccf75c1bb388708Robert Tsai        mEeRoutingState = ROUTE_OFF;
3880bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
389525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mNfceeAccessControl = new NfceeAccessControl(mContext);
390c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
391525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
3920e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
393f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
39431949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
3950b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
396f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
397525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
398525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
399525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mRoutingWakeLock = mPowerManager.newWakeLock(
400525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
401525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock = mPowerManager.newWakeLock(
402525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock");
403275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
404525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
405fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        mScreenState = checkScreenState();
406533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
407d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
408f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
409525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents only for owner
410525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        IntentFilter ownerFilter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
411525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
412525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
413525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
414525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
415525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
416525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
417525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter = new IntentFilter();
418525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
419525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
420525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addDataScheme("package");
421525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
422525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
423525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
424525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents for all users
425eead88c5e2bdd34eb33fdf2c76717f9edb9e0396Jeff Hamilton        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
42665945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_OFF);
42765945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
428275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
4293859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        filter.addAction(Intent.ACTION_USER_SWITCHED);
43031949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
431525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
4320e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
433e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        updatePackageCache();
434e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
43531949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
43631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
43731949217328bf2357ff044f0d18677fe588c790cNick Pelly
438d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
439d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
440d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
441d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
442525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
443525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
444525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
445d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
446d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
447d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
448d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
449d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
450d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
451d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
452d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
453d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
454d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
455d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
456d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
457d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
45831949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
4597d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
4607d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_RADIOS);
4617d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String toggleableRadios = Settings.System.getString(mContentResolver,
4627d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
46331949217328bf2357ff044f0d18677fe588c790cNick Pelly
46431949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
4657d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
46631949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
4677d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            toggleableRadios.contains(Settings.Global.RADIO_NFC);
46831949217328bf2357ff044f0d18677fe588c790cNick Pelly
46931949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
47031949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
47131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
47231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
47331949217328bf2357ff044f0d18677fe588c790cNick Pelly
474e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    void updatePackageCache() {
475525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        PackageManager pm = mContext.getPackageManager();
476525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
477e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        synchronized (this) {
478e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            mInstalledPackages = packages;
479e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        }
480e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    }
481e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
482fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int checkScreenState() {
483fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        if (!mPowerManager.isScreenOn()) {
484fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_OFF;
485fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else if (mKeyguard.isKeyguardLocked()) {
486fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_LOCKED;
487fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else {
488fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_UNLOCKED;
489fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
490fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
491fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
492525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    int doOpenSecureElementConnection() {
493525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
494525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
495525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mSecureElement.doOpenSecureElementConnection();
496525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
497525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
498525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
499525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
500525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
501525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceive(int handle, byte[] cmd) {
502525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
503525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
504525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceiveNoLock(handle, cmd);
505525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
506525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
507525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
508525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
509525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
510525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceiveNoLock(int handle, byte[] cmd) {
511525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        return mSecureElement.doTransceive(handle, cmd);
512525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
513525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
514525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    void doDisconnect(int handle) {
515525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
516525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
517525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mSecureElement.doDisconnect(handle);
518525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
519525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
520525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
521525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
522525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
52331949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
52431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
52531949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
52631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
52731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
52831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
52931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
53031949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
53131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
53231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
53331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
53431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
53531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
53631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
53731949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
53831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
53931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
54031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
54131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
54231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
54331949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
54431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
54531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
54631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
54731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
54831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
54931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
55031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * process may temporarily enable the NFC adapter
55131949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
55231949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
55331949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
55431949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
55531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
55631949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
55731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
55831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
55931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
56031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
56131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
56231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
56331949217328bf2357ff044f0d18677fe588c790cNick Pelly
5644467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
5654467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
5664467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
5674467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
5684467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
5694467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
5704467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
5714467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
5724467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
57331949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
57431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
57531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
57631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
57731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
57831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
57931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
58031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
5810fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    Log.d(TAG,"checking on firmware download");
5821668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
58331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
5841668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
5850fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is on. Doing normal stuff");
58631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
5870fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
5880fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is off.  Checking firmware version");
5890fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
59031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
59131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
59231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
59331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
59431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
59531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        executeEeWipe();
59631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
59731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
59831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_EE_WIPE:
59931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    executeEeWipe();
60031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
60131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
602d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
603d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
604d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
60531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
60631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
60731949217328bf2357ff044f0d18677fe588c790cNick Pelly
60831949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
60931949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
61031949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
61131949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
61231949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
61331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
61431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
61531949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
61631949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
61731949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
61831949217328bf2357ff044f0d18677fe588c790cNick Pelly
619525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
620525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            watchDog.start();
621525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
622525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
623525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
624525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (!mDeviceHost.initialize()) {
625525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.w(TAG, "Error enabling NFC");
626525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        updateState(NfcAdapter.STATE_OFF);
627525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        return false;
628525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
629525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
630525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
631525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
632525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
633525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                watchDog.cancel();
63431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
63531949217328bf2357ff044f0d18677fe588c790cNick Pelly
63631949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized(NfcService.this) {
63731949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
63831949217328bf2357ff044f0d18677fe588c790cNick Pelly
6390b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
64031949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
64131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
64231949217328bf2357ff044f0d18677fe588c790cNick Pelly
643d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
644d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
64531949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
6460c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
647fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
64831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
64931949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
65031949217328bf2357ff044f0d18677fe588c790cNick Pelly
65131949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
65231949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
65331949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
65431949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
65531949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
65631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
65731949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
65831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
65931949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
66031949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
66131949217328bf2357ff044f0d18677fe588c790cNick Pelly
66231949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
66331949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
66431949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
66531949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
666525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
66731949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
66831949217328bf2357ff044f0d18677fe588c790cNick Pelly
66977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
67031949217328bf2357ff044f0d18677fe588c790cNick Pelly
6713e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            /* The NFC-EE may still be opened by another process,
6723e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * and a transceive() could still be in progress on
6733e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * another Binder thread.
6743e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * Give it a while to finish existing operations
6753e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * before we close it.
6763e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             */
6773e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            Long startTime = SystemClock.elapsedRealtime();
6783e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            do {
6793e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                synchronized (NfcService.this) {
6803e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    if (mOpenEe == null)
6813e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                        break;
6823e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
6833e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                try {
6843e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    Thread.sleep(WAIT_FOR_NFCEE_POLL_MS);
6853e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                } catch (InterruptedException e) {
6863e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    // Ignore
6873e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
6883e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            } while (SystemClock.elapsedRealtime() - startTime < WAIT_FOR_NFCEE_OPERATIONS_MS);
6893e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
6904ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            synchronized (NfcService.this) {
6914ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                if (mOpenEe != null) {
6924ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    try {
6934ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                        _nfcEeClose(-1, mOpenEe.binder);
6944ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    } catch (IOException e) { }
6954ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                }
6964ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            }
6974ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen
69831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
69931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
70031949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
70131949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
70231949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
70331949217328bf2357ff044f0d18677fe588c790cNick Pelly
7040b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
70531949217328bf2357ff044f0d18677fe588c790cNick Pelly
70631949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
70731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
70831949217328bf2357ff044f0d18677fe588c790cNick Pelly
70931949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
71031949217328bf2357ff044f0d18677fe588c790cNick Pelly
71131949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_OFF);
71231949217328bf2357ff044f0d18677fe588c790cNick Pelly
713d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
714d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
71531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
71631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
71731949217328bf2357ff044f0d18677fe588c790cNick Pelly
71831949217328bf2357ff044f0d18677fe588c790cNick Pelly        void executeEeWipe() {
71931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // TODO: read SE reset list from /system/etc
720525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            byte[][]apdus = mDeviceHost.getWipeApdus();
721525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
722525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (apdus == null) {
723525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.d(TAG, "No wipe APDUs found");
724525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                return;
725525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
72631949217328bf2357ff044f0d18677fe588c790cNick Pelly
72731949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
728525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Hold a wake-lock over the entire wipe procedure
729525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.acquire();
730525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
731525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (tempEnable && !enableInternal()) {
732ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
73331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
734f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
735525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
736525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    // NFC enabled
737525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    int handle = 0;
738525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    try {
739525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.i(TAG, "Executing SE wipe");
740525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        handle = doOpenSecureElementConnection();
741525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        if (handle == 0) {
742525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Log.w(TAG, "Could not open the secure element");
743525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            return;
744525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
745525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        // TODO: remove this hack
746525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
747525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Thread.sleep(1000);
748525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } catch (InterruptedException e) {
749525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            // Ignore
750525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
75131949217328bf2357ff044f0d18677fe588c790cNick Pelly
752525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
753525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
754525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            for (byte[] cmd : apdus) {
755525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                byte[] resp = doTransceiveNoLock(handle, cmd);
756525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                if (resp == null) {
757525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
758525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    break;
759525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                }
760525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            }
761525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } finally {
762525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            mDeviceHost.resetTimeouts();
763525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
764525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    } finally {
765525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        if (handle != 0) {
766525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            doDisconnect(handle);
767525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
768525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
769525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
770525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (tempEnable) {
771525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        disableInternal();
772525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
773ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                }
774525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
775525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEeWakeLock.release();
77631949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
777525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            Log.i(TAG, "SE wipe done");
77831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
77931949217328bf2357ff044f0d18677fe588c790cNick Pelly
78031949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
7812a3f6f141fdaf746a81ce850a8ab0ef251041966mike wakerly            synchronized (NfcService.this) {
78231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
78331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
78431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
78531949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
78631949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
78731949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
78831949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
789525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
79031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
79131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
79231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
79331949217328bf2357ff044f0d18677fe588c790cNick Pelly
79431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
79531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
79631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
79731949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
79831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
7990e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
8000e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
801d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
802d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
803d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
804d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
805d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
806d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
807d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
808d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
809d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
810d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
811d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
812d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
813d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
814d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
815d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
816d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
817d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
818d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
819d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
820d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
8210e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
8224a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
823fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
8240e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
82593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
8260e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
82731949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
8281668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen
8291668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
8301668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                if (!mIsAirplaneToggleable) {
8311668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    Log.i(TAG, "denying enable() request (airplane mode)");
8321668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    return false;
8331668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                }
8341668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                // Make sure the override survives a reboot
8351668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
8361668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
837f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
83831949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
83931949217328bf2357ff044f0d18677fe588c790cNick Pelly
84031949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
841f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
842f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
843fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
844290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi        public boolean disable(boolean saveState) throws RemoteException {
84593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
8460e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
847290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            if (saveState) {
848290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi                saveNfcOnSetting(false);
849290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            }
850290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi
85131949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
85231949217328bf2357ff044f0d18677fe588c790cNick Pelly
85331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
854f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
855f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
856fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
8570b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
85831949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
8599993a5a96a862cea4512509b413d0de6cacb7c14Nick Pelly                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
86031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
861d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
862d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
863d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
8640b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
865d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
866d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
8670b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
86831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
86931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
8700b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
8710b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
87231949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
8730b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
87431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
87577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
876d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
877d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
878d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
879d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
880d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
881d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
8820b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
883d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
884d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
8850b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
88631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
88731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
8880b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
8890b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
89031949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
8910b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
89231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
89377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
894d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
895d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
896d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
897d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
898d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
899d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9000b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
90124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
90205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
903a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
9040b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
9050b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
9060b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
9070b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
908ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
909a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
910a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
911a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
912a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
913a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
914a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
915a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
916a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
917a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
918a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
919a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
920a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
921a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
922a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
92324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
92424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
92524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
92624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
92724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
92849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
9290b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
9302094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
9312094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
9322094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
933c96f982f8c0fa061701143a27395acf3b24dfb54Nick Pelly        public void setNdefPushCallback(INdefPushCallback callback) {
934ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
9353859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
936ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
937ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
938ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
9390e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
9400e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
9410e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
9420e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
943fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
944c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) {
945c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
94649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mExtrasService;
9470bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
9480bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
949fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
95031949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
95131949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
95231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
95331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
95431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
95531949217328bf2357ff044f0d18677fe588c790cNick Pelly
95631949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
95731949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
95831949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
9590e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
960391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly
961391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        @Override
962ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        public void dispatch(Tag tag) throws RemoteException {
963391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            enforceAdminPerm(mContext);
964ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            mNfcDispatcher.dispatchTag(tag);
965391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        }
9660c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
9670c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        @Override
9680c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
9690c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            enforceAdminPerm(mContext);
9700c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
9710c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pInitiatorModes(initiatorModes);
9720c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pTargetModes(targetModes);
9730c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.disableDiscovery();
9740c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.enableDiscovery();
9750c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        }
976c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
9770e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
9784a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
979fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
980f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
981d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
982bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
983f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
984f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
98531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
986f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
987f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
988f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
989f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
990f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
991f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
992b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
993b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
99421545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
995b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
996f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
997f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
998fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
999f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
1000f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1001f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1002fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1003ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
1004d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1005bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1006f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1007f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
100831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1009f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1010f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1011f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1012f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1013f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1014b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1015b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
1016f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1017ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
1018cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            if (!tag.isPresent()) {
1019cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1020cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            }
1021cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen
1022ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
1023ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
1024ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
1025ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
1026ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
1027ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
1028ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1029ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
1030f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1031f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1032fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1033aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
1034aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1035aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1036f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1037aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1038aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
103931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1040aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
1041aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1042aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1043aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
1044f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1045aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
1046aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
1047aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
1048aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
1049aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
1050aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
1051aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1052aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
1053aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
1054aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1055aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
1056b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
1057d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1058bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1059f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
106031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1061f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1062f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1063f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1064f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1065f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1066f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1067b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
1068f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1069f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1070f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1071f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1072fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1073b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
1074f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1075b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1076b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
107731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1078b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1079b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1080b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1081b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
1082f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1083b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1084b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1085b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1086b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1087ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
1088b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1089b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1090fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1091f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
1092182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1093182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen
1094f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1095f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1096f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
109731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
10982c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1099f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1100f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1101f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1102f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
11033ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
11042c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
11052c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1106f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
110770bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
1108f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1109f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1110fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11119d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
111297c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
1113d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1114bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1115f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1116f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
1117f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1118f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
111931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1120f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1121f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1122f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1123f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1124f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1125f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1126bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
1127bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1128bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1129bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
11309d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
11319d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
1132bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
1133bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
1134bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
1135bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
1136bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
1137bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
1138bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
1139bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
1140bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
1141f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1142f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1143f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1144f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1145fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11463fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1147d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1148bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1149f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1150f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1151f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
115231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1153f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1154f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1155f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1156f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1157f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1158f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1159f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
1160f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
1161f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1162f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
1163f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1164f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
1165f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
1166f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
1167f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
1168f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1169f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1170f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1171f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1172f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1173f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1174fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11753fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1176d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1177bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1178f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1179f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1180f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
118131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1182f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1183f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1184f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1185f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1186f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1187f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1188f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1189f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1190f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1191791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1192791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen
1193f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1194f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1195f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1196f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1197f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1198f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1199f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1200f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1201fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12023fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
12033fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1204f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1205f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1206fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12073fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
120803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
120903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1210f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
121103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
121203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
121331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
121403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
121503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
121603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
121703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1218f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
121903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
122003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
122103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
122203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1223f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
122403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1225f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
122603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
122703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1228f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1229f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
12300aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
12310aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
12320aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
12330aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1234f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
12350aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12360aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
123731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
12380aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
12390aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12400aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12410aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1242f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
12430aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
12440aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
12450aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12460aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12470aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
12480aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1249f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
12500aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
12510aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12520aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
12530aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12541b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
12553fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
12563fb14d0868594c78a777e805545209636814e223Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
12573fb14d0868594c78a777e805545209636814e223Martijn Coenen
1258f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
12593fb14d0868594c78a777e805545209636814e223Martijn Coenen
12603fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
126131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
12623fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
12633fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
12643fb14d0868594c78a777e805545209636814e223Martijn Coenen
12653fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1266f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
12673fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
12683fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
12693fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
12703fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
12713fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
12723fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
12733fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
12743fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
12753fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
12763fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
12773fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1278391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                tag.findAndReadNdef();
12793fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
12803fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
12814a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
12823fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
12833fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
12843fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
12853fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
12863fb14d0868594c78a777e805545209636814e223Martijn Coenen
12871b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1288fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
12891b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1290f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1291fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1292fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1293fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1294fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1295fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1296dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1297dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1298dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1299358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
1300358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1301358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1302358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1303358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1304358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1305358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1306dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
1307dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1308dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1309f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
13101b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1311bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1312bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1313bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1314bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1315bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1316bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1317bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1318bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1319bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1320bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1321ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen
1322ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        @Override
1323ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1324ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen            return mDeviceHost.getExtendedLengthApdusSupported();
1325ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        }
1326c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
1327f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
132892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly    void _nfcEeClose(int callingPid, IBinder binder) throws IOException {
1329dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // Blocks until a pending open() or transceive() times out.
1330dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        //TODO: This is incorrect behavior - the close should interrupt pending
1331dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // operations. However this is not supported by current hardware.
1332dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
13330571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly        synchronized (NfcService.this) {
13344ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            if (!isNfcEnabledOrShuttingDown()) {
1335dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC adapter is disabled");
1336dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1337dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (mOpenEe == null) {
1338dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC EE closed");
1339dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
134092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (callingPid != -1 && callingPid != mOpenEe.pid) {
1341dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new SecurityException("Wrong PID");
1342dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
134392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (mOpenEe.binder != binder) {
134492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                throw new SecurityException("Wrong binder handle");
134592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            }
1346dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
134792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            binder.unlinkToDeath(mOpenEe, 0);
1348f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
1349525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            doDisconnect(mOpenEe.handle);
1350dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mOpenEe = null;
1351dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1352fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1353dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        }
1354dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    }
1355dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
13564a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
135749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeNoException() {
135849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
135949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", 0);
136049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
136149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1362c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1363c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private Bundle writeEeException(int exceptionType, String message) {
136449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
1365c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putInt("e", exceptionType);
1366c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putString("m", message);
136749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
136849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
13690bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1370bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1371c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle open(String pkg, IBinder b) throws RemoteException {
1372c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1373bd555ee64250126b60b24814120a2049943920caNick Pelly
137449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
1375c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            int handle = _open(b);
1376c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            if (handle < 0) {
1377c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(handle, "NFCEE open exception.");
1378c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            } else {
137949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
13800bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
138149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
138249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
13830bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1384c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        /**
1385c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * Opens a connection to the secure element.
1386c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *
1387c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * @return A handle with a value >= 0 in case of success, or a
1388c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *         negative value in case of failure.
1389c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         */
1390c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private int _open(IBinder b) {
139149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
139231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
1393c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_NFC_DISABLED;
139449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
139549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe != null) {
1396c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_ALREADY_OPEN;
139749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
13980bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1399525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int handle = doOpenSecureElementConnection();
1400c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                if (handle < 0) {
1401c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return handle;
140249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
1403525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000);
1404ba6401757f8017faeb77423f2d08fd51be1d1051Nick Pelly
140592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
140649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                try {
140749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    b.linkToDeath(mOpenEe, 0);
140849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                } catch (RemoteException e) {
140949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    mOpenEe.binderDied();
141049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
141184e1e0adc2516afd35ebab029a52e764e0490559Jason parks
141284e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // Add the calling package to the list of packages that have accessed
141384e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // the secure element.
1414525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) {
141584e1e0adc2516afd35ebab029a52e764e0490559Jason parks                    mSePackages.add(packageName);
141684e1e0adc2516afd35ebab029a52e764e0490559Jason parks                }
1417c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1418c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                return handle;
141949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly           }
14200bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
14210bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1422bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
142392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public Bundle close(String pkg, IBinder binder) throws RemoteException {
1424c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1425c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
142649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
142749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
142892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                _nfcEeClose(getCallingPid(), binder);
142949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
143049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1431c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
14320bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
143349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
143449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
14350bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1436bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1437c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle transceive(String pkg, byte[] in) throws RemoteException {
1438c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1439bd555ee64250126b60b24814120a2049943920caNick Pelly
144049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
144149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            byte[] out;
144249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
144349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                out = _transceive(in);
144449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
144549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result.putByteArray("out", out);
144649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1447c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
14480bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
144949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
145049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
14510bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1452c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly        private byte[] _transceive(byte[] data) throws IOException {
145349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
145431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
145549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC is not enabled");
145649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
14570571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly                if (mOpenEe == null) {
145849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE is not open");
145949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
146049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (getCallingPid() != mOpenEe.pid) {
146149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new SecurityException("Wrong PID");
146249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
14630bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
14640bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1465525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceive(mOpenEe.handle, data);
14660bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
14670bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1468bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1469c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public int getCardEmulationRoute(String pkg) throws RemoteException {
1470c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
147149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mEeRoutingState;
14720bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
14730bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1474bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1475c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
1476c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
147749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            mEeRoutingState = route;
1478525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            ApplyRoutingTask applyRoutingTask = new ApplyRoutingTask();
1479525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            applyRoutingTask.execute();
1480525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
1481525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Block until route is set
1482525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                applyRoutingTask.get();
1483525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (ExecutionException e) {
1484525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1485525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (InterruptedException e) {
1486525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1487525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
14880bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
1489bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
1490bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1491c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void authenticate(String pkg, byte[] token) throws RemoteException {
1492c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1493bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1494525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1495525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
1496525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public String getDriverName(String pkg) throws RemoteException {
1497525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            NfcService.this.enforceNfceeAdminPerm(pkg);
1498525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mDeviceHost.getName();
1499525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1500c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
15010bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
150249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** resources kept while secure element is open */
150349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private class OpenSecureElement implements IBinder.DeathRecipient {
150449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int pid;  // pid that opened SE
150592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // binder handle used for DeathReceipient. Must keep
150692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // a reference to this, otherwise it can get GC'd and
150792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // the binder stub code might create a different BinderProxy
150892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // for the same remote IBinder, causing mismatched
150992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // link()/unlink()
151092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public IBinder binder;
151149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int handle; // low-level handle
151292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public OpenSecureElement(int pid, int handle, IBinder binder) {
151349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.pid = pid;
151449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.handle = handle;
151592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            this.binder = binder;
151649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1517bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
151849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void binderDied() {
151949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized (NfcService.this) {
152092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                Log.i(TAG, "Tracked app " + pid + " died");
152149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                pid = -1;
15220bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas                try {
152392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    _nfcEeClose(-1, binder);
1524dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                } catch (IOException e) { /* already closed */ }
15250bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
15260bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
152792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        @Override
152892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public String toString() {
152992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            return new StringBuilder('@').append(Integer.toHexString(hashCode())).append("[pid=")
153092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    .append(pid).append(" handle=").append(handle).append("]").toString();
153192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        }
15320bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    }
15330bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
15349a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    boolean isNfcEnabledOrShuttingDown() {
15359a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        synchronized (this) {
15369a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
15379a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        }
15389a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    }
15399a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen
154031949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
154131949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
154231949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1543e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1544aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1545aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
154631949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
1547a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        final Object mCancelWaiter = new Object();
1548525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        final int mTimeout;
1549a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        boolean mCanceled = false;
1550525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1551525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public WatchDogThread(String threadName, int timeout) {
1552525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            super(threadName);
1553525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mTimeout = timeout;
1554525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1555525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
15562edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
15572edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
1558a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            try {
1559a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                synchronized (mCancelWaiter) {
1560a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    mCancelWaiter.wait(mTimeout);
1561a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    if (mCanceled) {
1562a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                        return;
1563a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    }
15642edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
1565a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            } catch (InterruptedException e) {
1566a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                // Should not happen; fall-through to abort.
1567a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                Log.w(TAG, "Watchdog thread interruped.");
1568a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                interrupt();
15692edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
1570a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            Log.e(TAG, "Watchdog triggered, aborting.");
1571a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            mDeviceHost.doAbort();
15722edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
1573a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project
15742edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
1575a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            synchronized (mCancelWaiter) {
1576a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCanceled = true;
1577a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCancelWaiter.notify();
1578a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            }
15792edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
15802edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
15812edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
1582fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /**
1583fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1584fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     */
1585fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    void applyRouting(boolean force) {
1586e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
15879a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            if (!isNfcEnabledOrShuttingDown() || mOpenEe != null) {
1588fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                // PN544 cannot be reconfigured while EE is open
1589e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1590e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1591525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
15927d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            if (mInProvisionMode) {
15937d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
15947d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
15957d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                if (!mInProvisionMode) {
15967d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Notify dispatcher it's fine to dispatch to any package now
15977d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // and allow handover transfers.
15987d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mNfcDispatcher.disableProvisioningMode();
15997d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mHandoverManager.setEnabled(true);
16007d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                }
16017d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            }
1602f439271150e4548f116919e0254d57655421581cMartijn Coenen            try {
1603f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.start();
1604f439271150e4548f116919e0254d57655421581cMartijn Coenen
1605525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) {
1606f439271150e4548f116919e0254d57655421581cMartijn Coenen                    /* TODO undo this after the LLCP stack is fixed.
1607f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * Use a different sequence when turning the screen off to
1608f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * workaround race conditions in pn544 libnfc. The race occurs
1609f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * when we change routing while there is a P2P target connect.
1610f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * The async LLCP callback will crash since the routing code
1611f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * is overwriting globals it relies on.
1612f439271150e4548f116919e0254d57655421581cMartijn Coenen                     */
1613f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (POLLING_MODE > SCREEN_STATE_OFF) {
1614f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfcPollingEnabled) {
1615f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-C OFF, disconnect");
1616f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfcPollingEnabled = false;
1617f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.disableDiscovery();
1618f439271150e4548f116919e0254d57655421581cMartijn Coenen                            maybeDisconnectTarget();
1619f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1620f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1621f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1622f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfceeRouteEnabled) {
1623f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-EE OFF");
1624f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfceeRouteEnabled = false;
1625f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.doDeselectSecureElement();
1626f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1627fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1628f439271150e4548f116919e0254d57655421581cMartijn Coenen                    return;
1629fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1630f439271150e4548f116919e0254d57655421581cMartijn Coenen
1631f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-EE routing
1632f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
1633f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1634f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfceeRouteEnabled) {
1635f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-EE ON");
1636f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfceeRouteEnabled = true;
1637f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.doSelectSecureElement();
1638f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1639f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1640f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force ||  mNfceeRouteEnabled) {
1641fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        Log.d(TAG, "NFC-EE OFF");
1642fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mNfceeRouteEnabled = false;
1643fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mDeviceHost.doDeselectSecureElement();
1644fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1645fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1646fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1647f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-C polling
1648f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= POLLING_MODE) {
1649f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfcPollingEnabled) {
1650f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C ON");
1651f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = true;
1652f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.enableDiscovery();
1653f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
16547d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                } else if (mInProvisionMode && mScreenState >= SCREEN_STATE_ON_LOCKED) {
16557d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Special case for setup provisioning
16567d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    if (!mNfcPollingEnabled) {
16577d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Log.d(TAG, "NFC-C ON");
16587d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mNfcPollingEnabled = true;
16597d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mDeviceHost.enableDiscovery();
16607d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    }
1661f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1662f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || mNfcPollingEnabled) {
1663f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C OFF");
1664f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = false;
1665f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.disableDiscovery();
1666f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1667fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1668f439271150e4548f116919e0254d57655421581cMartijn Coenen            } finally {
1669f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.cancel();
1670221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
167165945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
167265945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
167365945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
16742436ffe91853535fad87b7a8e03d8883bae20f20Arnaud Ferir    /** Disconnect any target if present */
167531949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
16769a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        if (!isNfcEnabledOrShuttingDown()) {
1677a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1678a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
167931949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
168031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
168131949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
168231949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
168331949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
168431949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
168531949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
168631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
168731949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
168831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
168931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
169031949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
169131949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
169231949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
169331949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
169431949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
169531949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
169631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
169731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
169831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
169931949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
170031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
170131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1702bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1703bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1704bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1705bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1706bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
170731949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
170831949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
170931949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
171031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
171131949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
17122f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
171331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
17140e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1715f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1716f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
171731949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
171831949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
171931949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1720f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1721b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1722b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
172331949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
172431949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
172531949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
172631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
1727f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1728f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1729d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
17304a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1731c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            throws LlcpException {
17324a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1733d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1734d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1735d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
17363b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
1737e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen            throws LlcpException {
17383b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
1739e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    }
1740e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen
1741e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    /** For use by code in this process */
17424a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1743c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            int linearBufferLength) throws LlcpException {
17444a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1745d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1746d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
174757d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
1748b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
174957d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
175057d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
1751b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
1752b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
1753b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
1754b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
1755b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
1756b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1757b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
17583fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
1759b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
1760b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
176131949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
176231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
176331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
176431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
176531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
176631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
176731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
176831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
176931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
177031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new int[] { TagTechnology.NDEF },
177131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new Bundle[] { extras });
177231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
177331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
1774ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                    boolean delivered = mNfcDispatcher.dispatchTag(tag);
177531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (delivered) {
1776d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
177777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    } else {
1778d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
177931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
178031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
178131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
178257d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
178331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
178431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
178531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
1786d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    playSound(SOUND_START);
178789baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
178889baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // When these tags start containing NDEF, they will require
178989baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // the stack to deal with them in a different way, since
179089baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // they are activated only really shortly.
179189baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // For now, don't consider NDEF on these.
179289baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
179389baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        tag.startPresenceChecking();
179489baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        dispatchTagEndpoint(tag);
179589baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        break;
179689baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    }
1797391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    NdefMessage ndefMsg = tag.findAndReadNdef();
1798c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
1799391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    if (ndefMsg != null) {
180031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        tag.startPresenceChecking();
1801ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                        dispatchTagEndpoint(tag);
180231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
180331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
180431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.startPresenceChecking();
1805ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                            dispatchTagEndpoint(tag);
180631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
180731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
1808d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
180931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
181031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
181131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
181231949217328bf2357ff044f0d18677fe588c790cNick Pelly
181331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_CARD_EMULATION:
181431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Emulation message");
181531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] aid = (byte[]) msg.obj;
181631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
181731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent aidIntent = new Intent();
181831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.setAction(ACTION_AID_SELECTED);
181931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.putExtra(EXTRA_AID, aid);
182031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
182114a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(aidIntent);
182231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
182331949217328bf2357ff044f0d18677fe588c790cNick Pelly
182431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_EMV_CARD_REMOVAL:
182531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Removal message");
182631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
182731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent cardRemovalIntent = new Intent();
182831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
182931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
183014a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(cardRemovalIntent);
183131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
183231949217328bf2357ff044f0d18677fe588c790cNick Pelly
183331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_APDU_RECEIVED:
183431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "APDU Received message");
183531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] apduBytes = (byte[]) msg.obj;
183631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
183731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent apduReceivedIntent = new Intent();
183831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
183931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (apduBytes != null && apduBytes.length > 0) {
184031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
184131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
184231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
184314a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(apduReceivedIntent);
184431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
184531949217328bf2357ff044f0d18677fe588c790cNick Pelly
184631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_MIFARE_ACCESS:
184731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "MIFARE access message");
184831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
184931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] mifareCmd = (byte[]) msg.obj;
185031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent mifareAccessIntent = new Intent();
185131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
185231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mifareCmd != null && mifareCmd.length > 1) {
185331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        int mifareBlock = mifareCmd[1] & 0xff;
185431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
185531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
185631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
185731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
185814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(mifareAccessIntent);
185931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
1860c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
186131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
186231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
186331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
186431949217328bf2357ff044f0d18677fe588c790cNick Pelly
186531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
186631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
186731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
186831949217328bf2357ff044f0d18677fe588c790cNick Pelly
186931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
187031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
187131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
187231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
187331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
187431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
187531949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
187631949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
187731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
187831949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
187931949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
188031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
188131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
188231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
188331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
188431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
188531949217328bf2357ff044f0d18677fe588c790cNick Pelly
188677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
188731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
188857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                case MSG_LLCP_LINK_FIRST_PACKET:
188957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    mP2pLinkManager.onLlcpFirstPacketReceived();
189057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    break;
189131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_TARGET_DESELECTED:
189231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Broadcast Intent Target Deselected */
189331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Target Deselected");
189431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent intent = new Intent();
189531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
189631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting Intent");
189731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
189831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
189931949217328bf2357ff044f0d18677fe588c790cNick Pelly
190031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_ACTIVATED: {
190131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
190231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOnIntent = new Intent();
190331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
190414a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOnIntent);
190531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
190631949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
190731949217328bf2357ff044f0d18677fe588c790cNick Pelly
190831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_DEACTIVATED: {
190931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
191031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOffIntent = new Intent();
191131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
191214a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOffIntent);
191331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
191431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
191531949217328bf2357ff044f0d18677fe588c790cNick Pelly
1916525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_ACTIVATED: {
1917525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE ACTIVATED");
1918525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeActivated = new Intent();
1919525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeActivated.setAction(ACTION_SE_LISTEN_ACTIVATED);
1920525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeActivated);
1921525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
1922525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
1923525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1924525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_DEACTIVATED: {
1925525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE DEACTIVATED");
1926525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeDeactivated = new Intent();
1927525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeDeactivated.setAction(ACTION_SE_LISTEN_DEACTIVATED);
1928525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeDeactivated);
1929525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
1930525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
1931525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
193231949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
193331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
193431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
193531949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
1936b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1937d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
193814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        private void sendSeBroadcast(Intent intent) {
193914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
1940c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            // Resume app switches so the receivers can start activites without delay
1941c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfcDispatcher.resumeAppSwitches();
1942c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
1943e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            synchronized(this) {
1944e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                for (PackageInfo pkg : mInstalledPackages) {
1945e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (pkg != null && pkg.applicationInfo != null) {
1946e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
1947e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            intent.setPackage(pkg.packageName);
1948e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            mContext.sendBroadcast(intent);
1949e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        }
1950c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
1951c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
1952c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
195314a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        }
195414a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton
1955d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
1956d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
1957d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1958d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1959d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1960d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
1961d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
1962d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
1963d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
1964d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
1965d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
196631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
196731949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
196831949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
1969d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
197077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                            mP2pLinkManager.onLlcpActivated();
1971d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
1972d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
1973d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
1974d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1975d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
1976d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
1977d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
1978d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1979d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
1980d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1981d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1982d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1983d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
1984d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
1985d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
1986d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
1987d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1988d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1989d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1990d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
1991d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
1992d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
1993d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
1994d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
199531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
199631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
199731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
1998d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
199977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
2000d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
2001d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2002d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2003d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
2004d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2005d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
2006d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2007d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
2008d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
2009d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2010ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        private void dispatchTagEndpoint(TagEndpoint tagEndpoint) {
2011f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
2012f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
2013f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
2014ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            if (!mNfcDispatcher.dispatchTag(tag)) {
2015f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
2016d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
2017d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else {
2018d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
20193fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
20203fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
2021b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
2022b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
2023b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
202449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
2025fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
2026fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
2027fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        protected Void doInBackground(Integer... params) {
2028fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            synchronized (NfcService.this) {
2029fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (params == null || params.length != 1) {
2030fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    // force apply current routing
2031fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    applyRouting(true);
2032fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    return null;
2033161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2034fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                mScreenState = params[0].intValue();
2035fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
2036525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
2037525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2038525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    applyRouting(false);
2039525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
2040525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
2041161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2042fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return null;
20437c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
20447c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
20457c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
20467c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
2047525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
20480e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        @Override
20490e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public void onReceive(Context context, Intent intent) {
205031949217328bf2357ff044f0d18677fe588c790cNick Pelly            String action = intent.getAction();
2051525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
2052e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
2053e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
2054e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
2055e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                updatePackageCache();
2056e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2057e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
2058e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    // Clear the NFCEE access cache in case a UID gets recycled
2059e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    mNfceeAccessControl.invalidateCache();
2060e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2061e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
2062e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (dataRemoved) {
2063e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        Uri data = intent.getData();
2064e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (data == null) return;
2065e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        String packageName = data.getSchemeSpecificPart();
20667a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton
2067e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        synchronized (NfcService.this) {
2068e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            if (mSePackages.contains(packageName)) {
2069e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                new EnableDisableTask().execute(TASK_EE_WIPE);
2070e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                mSePackages.remove(packageName);
2071e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            }
20727a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                        }
2073bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                    }
2074bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
2075525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
2076525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                EnableDisableTask eeWipeTask = new EnableDisableTask();
2077525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                eeWipeTask.execute(TASK_EE_WIPE);
2078525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2079525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    eeWipeTask.get();  // blocks until EE wipe is complete
2080525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (ExecutionException e) {
2081525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2082525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (InterruptedException e) {
2083525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2084525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2085525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
2086525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
2087525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    };
2088525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
2089525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2090525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
2091525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2092525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            String action = intent.getAction();
2093525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(
2094525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
2095525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2096525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute();
2097525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(Intent.ACTION_SCREEN_ON)
2098525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_SCREEN_OFF)
2099525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_USER_PRESENT)) {
2100525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2101525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int screenState = SCREEN_STATE_OFF;
2102525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
2103525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_OFF;
2104525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
2105525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = mKeyguard.isKeyguardLocked() ?
2106525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
2107525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
2108525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_ON_UNLOCKED;
2109525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2110525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
211131949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
211231949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
211331949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
211431949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
211531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
211631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
211731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
211831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
211931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
212031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
21211668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
21221668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
212331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
212431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
212531949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
212631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
212731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
21283859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
21293859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                mP2pLinkManager.onUserSwitched();
2130f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
2131f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
2132f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
213331949217328bf2357ff044f0d18677fe588c790cNick Pelly
213431949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** Returns true if airplane mode is currently on */
213531949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
21367d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        return Settings.System.getInt(mContentResolver,
21377d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
213831949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
213931949217328bf2357ff044f0d18677fe588c790cNick Pelly
2140fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** for debugging only - no i18n */
214131949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
214231949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
214331949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
214431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
214531949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
214631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
214731949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
214831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
214931949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
215031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
215131949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
215231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
215331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
215431949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
215531949217328bf2357ff044f0d18677fe588c790cNick Pelly
2156fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** For debugging only - no i18n */
2157fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static String screenStateToString(int screenState) {
2158fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        switch (screenState) {
2159fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_OFF:
2160fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "OFF";
2161fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_LOCKED:
2162fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_LOCKED";
2163fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_UNLOCKED:
2164fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_UNLOCKED";
2165fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            default:
2166fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "UNKNOWN";
2167fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
2168fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
2169fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
217031949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
217150effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
217250effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
217350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
217450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
217550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
217650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
217750effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
217850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
217931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
218031949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
21810b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
2182fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mScreenState=" + screenStateToString(mScreenState));
2183fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfcPollingEnabled=" + mNfcPollingEnabled);
2184fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfceeRouteEnabled=" + mNfceeRouteEnabled);
218531949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
218631949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
218792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            pw.println("mOpenEe=" + mOpenEe);
218877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
2189c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfceeAccessControl.dump(fd, pw, args);
2190391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            mNfcDispatcher.dump(fd, pw, args);
219156f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
2192c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
219331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
219431949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
219574180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
2196