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;
5996e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenenimport android.os.Build;
60b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamiltonimport android.os.Bundle;
61b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Handler;
6249d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.os.IBinder;
63b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Message;
64533043d1003de2f6a20a29201100d94c3c7bc9caNick Pellyimport android.os.PowerManager;
654467dca5650a170af5020c10a8ccb25f86f1007fNick Pellyimport android.os.Process;
66f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.os.RemoteException;
6713d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.os.ServiceManager;
683e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenenimport android.os.SystemClock;
69525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.os.UserHandle;
70d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.provider.Settings;
71f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.util.Log;
72f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
7331949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.FileDescriptor;
7457d376f1ee1a3939977b95759525585abb9601fbJeff Hamiltonimport java.io.IOException;
7531949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.PrintWriter;
7631949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.Arrays;
773ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamiltonimport java.util.HashMap;
7884e1e0adc2516afd35ebab029a52e764e0490559Jason parksimport java.util.HashSet;
79c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.util.List;
8031949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.concurrent.ExecutionException;
813ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
82525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectpublic class NfcService implements DeviceHostListener {
83bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
84bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
85c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = false;
8676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
87fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
88d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
89fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
90c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** Regular NFC permission */
91bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM = android.Manifest.permission.NFC;
92bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM_ERROR = "NFC permission required";
93c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
94c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** NFC ADMIN permission - only for system apps */
95bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
96bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
97bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
9877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
99f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
100416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
101416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
102416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
103416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
104416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
105416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
1061668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
107a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
108b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
109b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_CARD_EMULATION = 1;
110b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_ACTIVATION = 2;
111b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
112b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_TARGET_DESELECTED = 4;
113b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    static final int MSG_MOCK_NDEF = 7;
114c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_ACTIVATED = 8;
115c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_DEACTIVATED = 9;
1162c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_APDU_RECEIVED = 10;
1172c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
1182c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_MIFARE_ACCESS = 12;
119525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_ACTIVATED = 13;
120525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_DEACTIVATED = 14;
12157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    static final int MSG_LLCP_LINK_FIRST_PACKET = 15;
122b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
12331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
12431949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
12531949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
12631949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_EE_WIPE = 4;
12731949217328bf2357ff044f0d18677fe588c790cNick Pelly
128fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    // Screen state, used by mScreenState
129fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_UNKNOWN = 0;
130fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_OFF = 1;
131fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_LOCKED = 2;
132fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_UNLOCKED = 3;
133fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
13449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Copied from com.android.nfc_extras to avoid library dependency
13549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Must keep in sync with com.android.nfc_extras
13649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_OFF = 1;
13749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
1387efbf69a37134ccbd86a1f6b4121f16b4a80eaaeNick Pelly
139c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // Return values from NfcEe.open() - these are 1:1 mapped
140c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // to the thrown EE_EXCEPTION_ exceptions in nfc-extras.
141c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_IO = -1;
142c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_ALREADY_OPEN = -2;
143c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_INIT = -3;
144c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_LISTEN_MODE = -4;
145c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_EXT_FIELD = -5;
146c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_NFC_DISABLED = -6;
147c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
148fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** minimum screen state that enables NFC polling (discovery) */
149fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
150fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
151525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for NFC controller to initialize before watchdog
152525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off. This time is chosen large, because firmware download
153525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // may be a part of initialization.
154525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int INIT_WATCHDOG_MS = 90000;
155525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
156525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for routing to be applied before watchdog
157525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off
158525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int ROUTING_WATCHDOG_MS = 10000;
159525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1603e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Amount of time to wait before closing the NFCEE connection
1613e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // in a disable/shutdown scenario.
1623e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_OPERATIONS_MS = 5000;
1633e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Polling interval for waiting on NFCEE operations
1643e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_POLL_MS = 100;
1653e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
166d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
167d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
168d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
169d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
170d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
17149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_ON_DETECTED =
17249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
17349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_OFF_DETECTED =
17449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
17549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_AID_SELECTED =
17649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.AID_SELECTED";
17749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
17849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
17996e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_UP =
18096e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_UP";
18196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
18296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_DOWN =
18396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_DOWN";
18496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
1852c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_APDU_RECEIVED =
1862c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.APDU_RECEIVED";
1872c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_APDU_BYTES =
1882c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.APDU_BYTES";
1892c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1902c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_EMV_CARD_REMOVAL =
1912c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
1922c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1932c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_MIFARE_ACCESS_DETECTED =
1942c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
1952c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_MIFARE_BLOCK =
1962c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.MIFARE_BLOCK";
1972c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
198525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_ACTIVATED =
199525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_ACTIVATED";
200525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_DEACTIVATED =
201525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_DEACTIVATED";
20249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
20349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
20449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
2050bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    private NativeNfcSecureElement mSecureElement;
20649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private OpenSecureElement mOpenEe;  // null when EE closed
20749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private int mEeRoutingState;  // contactless interface routing
2080bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
209d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    // fields below must be used only on the UI thread and therefore aren't synchronized
210d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    boolean mP2pStarted = false;
211d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
2122f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
213fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
214525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // mSePackages holds packages that accessed the SE, but only for the owner user,
215525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // as SE access is not granted for non-owner users.
216fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    HashSet<String> mSePackages = new HashSet<String>();
217fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int mScreenState;
2187d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
219fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mIsNdefPushEnabled;
220fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfceeRouteEnabled;  // current Device Host state of NFC-EE routing
221fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfcPollingEnabled;  // current Device Host state of NFC-C polling
222e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    List<PackageInfo> mInstalledPackages; // cached version of installed packages
22331949217328bf2357ff044f0d18677fe588c790cNick Pelly
22431949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
22531949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
22631949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
22731949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
2282f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
2292f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
23005973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
2314a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
2320e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
2330e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
234525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mRoutingWakeLock;
235525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mEeWakeLock;
236525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
237d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
238d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
239d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
240d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
24177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
2424a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
2434a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
2444a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterExtrasService mExtrasService;
24531949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
24631949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
24796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    boolean mIsDebugBuild;
248c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    NfceeAccessControl mNfceeAccessControl;
2492ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
25076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
251fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    private PowerManager mPowerManager;
252275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
2537d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private HandoverManager mHandoverManager;
2547d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private ContentResolver mContentResolver;
255d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
256d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    private static NfcService sService;
257d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
25893d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceAdminPerm(Context context) {
259c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
26093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
26193d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
262c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public void enforceNfceeAdminPerm(String pkg) {
263c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (pkg == null) {
264c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException("caller must pass a package name");
265c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
266c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
267c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (!mNfceeAccessControl.check(Binder.getCallingUid(), pkg)) {
268c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
269c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    " denies NFCEE access to " + pkg);
270c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
271525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
272525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            throw new SecurityException("only the owner is allowed to call SE APIs");
273525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
27493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
27593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
276d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
277d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
278d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
279f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2800e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
281f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
282f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
283f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
284f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
285f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
286f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
287f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
288d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
289f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationDeselected() {
290f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
291f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
292f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
293f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
294f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
295f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
296d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
297f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationAidSelected(byte[] aid) {
298f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_CARD_EMULATION, aid);
299f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
300f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
301f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
302f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
303f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
304f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
305f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
306f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
307f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
308f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
309f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
310f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
311f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
312d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
313f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
314f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
315f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
316f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
31757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    /**
31857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     * Notifies P2P Device detected, first packet received over LLCP link
31957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     */
32057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    @Override
32157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
32257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
32357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    }
32457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
325d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
326f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldActivated() {
327f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
328f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
329f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
330d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
331f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldDeactivated() {
332f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
333f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
334f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
335f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
336525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenActivated() {
337525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        sendMessage(NfcService.MSG_SE_LISTEN_ACTIVATED, null);
338525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
339525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
340525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
341525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenDeactivated() {
342525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        sendMessage(NfcService.MSG_SE_LISTEN_DEACTIVATED, null);
343525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
344525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
345525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
346525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
347442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeApduReceived(byte[] apdu) {
348442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
349442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
350442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
351442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
352442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeEmvCardRemoval() {
353442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
354442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
355442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
356442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
357442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeMifareAccess(byte[] block) {
358442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly        sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
359442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
360442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
361525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public NfcService(Application nfcApplication) {
3624a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
3634a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
364ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly        mExtrasService = new NfcAdapterExtrasService();
3654a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton
3662f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
3672f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
368d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
369d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
370525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext = nfcApplication;
3717d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mContentResolver = mContext.getContentResolver();
372525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDeviceHost = new NativeNfcManager(mContext, this);
37374180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
3747d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager = new HandoverManager(mContext);
3757d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        boolean isNfcProvisioningEnabled = false;
3767d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        try {
3777d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
3787d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    R.bool.enable_nfc_provisioning);
3797d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } catch (NotFoundException e) {
3807d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
3817d8987f233985a5ff29226890e11012275d325f5Martijn Coenen
3827d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        if (isNfcProvisioningEnabled) {
3837d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
3847d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
3857d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } else {
3867d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = false;
3877d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
388525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
3897d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager.setEnabled(!mInProvisionMode);
3907d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
3917d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
392525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
39324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
39437058bf7b59def2f9a565ae5b16aae54e80e9e95Sunil Jogi        mSecureElement = new NativeNfcSecureElement(mContext);
395eab09ad7204fe1f0feaca33efccf75c1bb388708Robert Tsai        mEeRoutingState = ROUTE_OFF;
3960bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
397525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mNfceeAccessControl = new NfceeAccessControl(mContext);
398c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
399525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
4000e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
401f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
40231949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
4030b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
404f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
40596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
40696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
407525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
408525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
409525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mRoutingWakeLock = mPowerManager.newWakeLock(
410525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
411525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock = mPowerManager.newWakeLock(
412525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock");
413275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
414525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
415fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        mScreenState = checkScreenState();
416533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
417d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
418f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
419525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents only for owner
420525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        IntentFilter ownerFilter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
421525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
422525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
423525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
424525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
425525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
426525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
427525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter = new IntentFilter();
428525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
429525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
430525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        ownerFilter.addDataScheme("package");
431525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
432525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
433525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
434525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents for all users
435eead88c5e2bdd34eb33fdf2c76717f9edb9e0396Jeff Hamilton        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
43665945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_OFF);
43765945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
438275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
4393859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        filter.addAction(Intent.ACTION_USER_SWITCHED);
44031949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
441525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
4420e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
443e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        updatePackageCache();
444e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
44531949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
44631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
44731949217328bf2357ff044f0d18677fe588c790cNick Pelly
448d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
449d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
450d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
451d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
452525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
453525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
454525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
455d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
456d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
457d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
458d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
459d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
460d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
461d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
462d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
463d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
464d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
465d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
466d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
467d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
46831949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
4697d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
4707d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_RADIOS);
4717d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String toggleableRadios = Settings.System.getString(mContentResolver,
4727d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
47331949217328bf2357ff044f0d18677fe588c790cNick Pelly
47431949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
4757d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
47631949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
4777d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            toggleableRadios.contains(Settings.Global.RADIO_NFC);
47831949217328bf2357ff044f0d18677fe588c790cNick Pelly
47931949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
48031949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
48131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
48231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
48331949217328bf2357ff044f0d18677fe588c790cNick Pelly
484e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    void updatePackageCache() {
485525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        PackageManager pm = mContext.getPackageManager();
486525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
487e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        synchronized (this) {
488e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            mInstalledPackages = packages;
489e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        }
490e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    }
491e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
492fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int checkScreenState() {
493fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        if (!mPowerManager.isScreenOn()) {
494fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_OFF;
495fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else if (mKeyguard.isKeyguardLocked()) {
496fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_LOCKED;
497fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else {
498fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_UNLOCKED;
499fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
500fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
501fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
502525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    int doOpenSecureElementConnection() {
503525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
504525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
505525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mSecureElement.doOpenSecureElementConnection();
506525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
507525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
508525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
509525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
510525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
511525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceive(int handle, byte[] cmd) {
512525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
513525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
514525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceiveNoLock(handle, cmd);
515525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
516525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
517525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
518525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
519525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
520525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceiveNoLock(int handle, byte[] cmd) {
521525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        return mSecureElement.doTransceive(handle, cmd);
522525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
523525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
524525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    void doDisconnect(int handle) {
525525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
526525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
527525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mSecureElement.doDisconnect(handle);
528525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
529525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
530525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
531525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
532525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
53331949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
53431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
53531949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
53631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
53731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
53831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
53931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
54031949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
54131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
54231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
54331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
54431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
54531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
54631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
54731949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
54831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
54931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
55031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
55131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
55231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
55331949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
55431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
55531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
55631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
55731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
55831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
55931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
56031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * process may temporarily enable the NFC adapter
56131949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
56231949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
56331949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
56431949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
56531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
56631949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
56731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
56831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
56931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
57031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
57131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
57231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
57331949217328bf2357ff044f0d18677fe588c790cNick Pelly
5744467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
5754467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
5764467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
5774467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
5784467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
5794467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
5804467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
5814467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
5824467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
58331949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
58431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
58531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
58631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
58731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
58831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
58931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
59031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
5910fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    Log.d(TAG,"checking on firmware download");
5921668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
59331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
5941668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
5950fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is on. Doing normal stuff");
59631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
5970fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
5980fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is off.  Checking firmware version");
5990fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
60031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
60131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
60231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
60331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
60431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
60531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        executeEeWipe();
60631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
60731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
60831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_EE_WIPE:
60931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    executeEeWipe();
61031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
61131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
612d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
613d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
614d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
61531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
61631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
61731949217328bf2357ff044f0d18677fe588c790cNick Pelly
61831949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
61931949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
62031949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
62131949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
62231949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
62331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
62431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
62531949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
62631949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
62731949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
62831949217328bf2357ff044f0d18677fe588c790cNick Pelly
629525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
630525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            watchDog.start();
631525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
632525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
633525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
634525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (!mDeviceHost.initialize()) {
635525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.w(TAG, "Error enabling NFC");
636525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        updateState(NfcAdapter.STATE_OFF);
637525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        return false;
638525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
639525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
640525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
641525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
642525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
643525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                watchDog.cancel();
64431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
64531949217328bf2357ff044f0d18677fe588c790cNick Pelly
64631949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized(NfcService.this) {
64731949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
64831949217328bf2357ff044f0d18677fe588c790cNick Pelly
6490b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
65031949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
65131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
65231949217328bf2357ff044f0d18677fe588c790cNick Pelly
653d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
654d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
65531949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
6560c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
657fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
65831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
65931949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
66031949217328bf2357ff044f0d18677fe588c790cNick Pelly
66131949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
66231949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
66331949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
66431949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
66531949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
66631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
66731949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
66831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
66931949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
67031949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
67131949217328bf2357ff044f0d18677fe588c790cNick Pelly
67231949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
67331949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
67431949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
67531949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
676525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
67731949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
67831949217328bf2357ff044f0d18677fe588c790cNick Pelly
67977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
68031949217328bf2357ff044f0d18677fe588c790cNick Pelly
6813e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            /* The NFC-EE may still be opened by another process,
6823e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * and a transceive() could still be in progress on
6833e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * another Binder thread.
6843e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * Give it a while to finish existing operations
6853e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * before we close it.
6863e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             */
6873e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            Long startTime = SystemClock.elapsedRealtime();
6883e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            do {
6893e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                synchronized (NfcService.this) {
6903e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    if (mOpenEe == null)
6913e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                        break;
6923e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
6933e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                try {
6943e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    Thread.sleep(WAIT_FOR_NFCEE_POLL_MS);
6953e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                } catch (InterruptedException e) {
6963e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    // Ignore
6973e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
6983e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            } while (SystemClock.elapsedRealtime() - startTime < WAIT_FOR_NFCEE_OPERATIONS_MS);
6993e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
7004ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            synchronized (NfcService.this) {
7014ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                if (mOpenEe != null) {
7024ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    try {
7034ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                        _nfcEeClose(-1, mOpenEe.binder);
7044ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    } catch (IOException e) { }
7054ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                }
7064ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            }
7074ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen
70831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
70931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
71031949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
71131949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
71231949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
71331949217328bf2357ff044f0d18677fe588c790cNick Pelly
7140b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
71531949217328bf2357ff044f0d18677fe588c790cNick Pelly
71631949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
71731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
71831949217328bf2357ff044f0d18677fe588c790cNick Pelly
71931949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
72031949217328bf2357ff044f0d18677fe588c790cNick Pelly
72131949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_OFF);
72231949217328bf2357ff044f0d18677fe588c790cNick Pelly
723d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
724d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
72531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
72631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
72731949217328bf2357ff044f0d18677fe588c790cNick Pelly
72831949217328bf2357ff044f0d18677fe588c790cNick Pelly        void executeEeWipe() {
72931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // TODO: read SE reset list from /system/etc
730525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            byte[][]apdus = mDeviceHost.getWipeApdus();
731525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
732525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (apdus == null) {
733525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.d(TAG, "No wipe APDUs found");
734525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                return;
735525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
73631949217328bf2357ff044f0d18677fe588c790cNick Pelly
73731949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
738525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Hold a wake-lock over the entire wipe procedure
739525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.acquire();
740525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
741525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (tempEnable && !enableInternal()) {
742ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
74331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
744f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
745525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
746525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    // NFC enabled
747525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    int handle = 0;
748525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    try {
749525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.i(TAG, "Executing SE wipe");
750525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        handle = doOpenSecureElementConnection();
7512b4dc11f4508cdb662a8069cccf9f2273004a4c8Martijn Coenen                        if (handle < 0) {
752525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Log.w(TAG, "Could not open the secure element");
753525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            return;
754525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
755525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        // TODO: remove this hack
756525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
757525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Thread.sleep(1000);
758525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } catch (InterruptedException e) {
759525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            // Ignore
760525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
76131949217328bf2357ff044f0d18677fe588c790cNick Pelly
762525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
763525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
764525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            for (byte[] cmd : apdus) {
765525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                byte[] resp = doTransceiveNoLock(handle, cmd);
766525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                if (resp == null) {
767525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
768525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    break;
769525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                }
770525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            }
771525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } finally {
772525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            mDeviceHost.resetTimeouts();
773525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
774525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    } finally {
7752b4dc11f4508cdb662a8069cccf9f2273004a4c8Martijn Coenen                        if (handle >= 0) {
776525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            doDisconnect(handle);
777525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
778525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
779525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
780525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (tempEnable) {
781525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        disableInternal();
782525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
783ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                }
784525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
785525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEeWakeLock.release();
78631949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
787525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            Log.i(TAG, "SE wipe done");
78831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
78931949217328bf2357ff044f0d18677fe588c790cNick Pelly
79031949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
7912a3f6f141fdaf746a81ce850a8ab0ef251041966mike wakerly            synchronized (NfcService.this) {
79231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
79331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
79431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
79531949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
79631949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
79731949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
79831949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
799525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
80031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
80131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
80231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
80331949217328bf2357ff044f0d18677fe588c790cNick Pelly
80431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
80531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
80631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
80731949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
80831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
8090e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
8100e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
811d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
812d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
813d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
814d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
815d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
816d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
817d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
818d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
819d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
820d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
821d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
822d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
823d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
824d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
825d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
826d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
827d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
828d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
829d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
830d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
8310e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
8324a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
833fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
8340e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
83593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
8360e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
83731949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
8381668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen
8391668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
8401668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                if (!mIsAirplaneToggleable) {
8411668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    Log.i(TAG, "denying enable() request (airplane mode)");
8421668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    return false;
8431668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                }
8441668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                // Make sure the override survives a reboot
8451668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
8461668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
847f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
84831949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
84931949217328bf2357ff044f0d18677fe588c790cNick Pelly
85031949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
851f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
852f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
853fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
854290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi        public boolean disable(boolean saveState) throws RemoteException {
85593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
8560e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
857290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            if (saveState) {
858290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi                saveNfcOnSetting(false);
859290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            }
860290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi
86131949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
86231949217328bf2357ff044f0d18677fe588c790cNick Pelly
86331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
864f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
865f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
866fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
8670b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
86831949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
8699993a5a96a862cea4512509b413d0de6cacb7c14Nick Pelly                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
87031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
871d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
872d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
873d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
8740b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
875d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
876d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
8770b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
87831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
87931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
8800b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
8810b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
88231949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
8830b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
88431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
88577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
886d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
887d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
888d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
889d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
890d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
891d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
8920b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
893d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
894d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
8950b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
89631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
89731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
8980b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
8990b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
90031949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
9010b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
90231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
90377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
904d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
905d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
906d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
907d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
908d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
909d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9100b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
91124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
91205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
913a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
9140b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
9150b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
9160b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
9170b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
918ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
919a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
920a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
921a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
922a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
923a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
924a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
925a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
926a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
927a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
928a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
929a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
930a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
931a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
932a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
93324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
93424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
93524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
93624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
93724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
93849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
9390b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
9402094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
9412094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
9422094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
943c96f982f8c0fa061701143a27395acf3b24dfb54Nick Pelly        public void setNdefPushCallback(INdefPushCallback callback) {
944ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
9453859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
946ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
947ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
948ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
9490e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
9500e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
9510e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
9520e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
953fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
954c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) {
955c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
95649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mExtrasService;
9570bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
9580bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
959fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
96031949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
96131949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
96231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
96331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
96431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
96531949217328bf2357ff044f0d18677fe588c790cNick Pelly
96631949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
96731949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
96831949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
9690e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
970391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly
971391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        @Override
972ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        public void dispatch(Tag tag) throws RemoteException {
973391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            enforceAdminPerm(mContext);
974ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            mNfcDispatcher.dispatchTag(tag);
975391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        }
9760c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
9770c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        @Override
9780c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
9790c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            enforceAdminPerm(mContext);
9800c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
9810c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pInitiatorModes(initiatorModes);
9820c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pTargetModes(targetModes);
9830c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.disableDiscovery();
9840c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.enableDiscovery();
9850c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        }
986c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
9870e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
9884a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
989fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
990f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
991d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
992bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
993f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
994f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
99531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
996f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
997f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
998f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
999f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1000f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1001f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1002b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
1003b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
100421545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
1005b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
1006f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1007f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
1008fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1009f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
1010f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1011f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1012fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1013ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
1014d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1015bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1016f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1017f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
101831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1019f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1020f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1021f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1022f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1023f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1024b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1025b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
1026f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1027ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
1028cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            if (!tag.isPresent()) {
1029cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1030cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            }
1031cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen
1032ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
1033ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
1034ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
1035ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
1036ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
1037ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
1038ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1039ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
1040f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1041f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1042fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1043aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
1044aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1045aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1046f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1047aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1048aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
104931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1050aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
1051aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1052aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1053aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
1054f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1055aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
1056aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
1057aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
1058aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
1059aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
1060aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
1061aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1062aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
1063aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
1064aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1065aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
1066b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
1067d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1068bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1069f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
107031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1071f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1072f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1073f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1074f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1075f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1076f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1077b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
1078f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1079f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1080f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1081f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1082fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1083b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
1084f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1085b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1086b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
108731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1088b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1089b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1090b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1091b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
1092f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1093b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1094b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1095b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1096b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1097ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
1098b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1099b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1100fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1101f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
1102182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1103182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen
1104f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1105f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1106f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
110731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
11082c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1109f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1110f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1111f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1112f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
11133ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
11142c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
11152c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1116f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
111770bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
1118f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1119f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1120fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11219d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
112297c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
1123d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1124bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1125f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1126f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
1127f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1128f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
112931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1130f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1131f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1132f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1133f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1134f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1135f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1136bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
1137bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1138bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1139bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
11409d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
11419d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
1142bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
1143bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
1144bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
1145bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
1146bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
1147bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
1148bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
1149bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
1150bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
1151f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1152f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1153f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1154f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1155fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11563fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1157d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1158bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1159f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1160f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1161f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
116231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1163f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1164f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1165f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1166f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1167f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1168f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1169f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
1170f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
1171f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1172f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
1173f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1174f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
1175f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
1176f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
1177f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
1178f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1179f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1180f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1181f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1182f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1183f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1184fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11853fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1186d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1187bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1188f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1189f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1190f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
119131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1192f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1193f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1194f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1195f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1196f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1197f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1198f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1199f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1200f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1201791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1202791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen
1203f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1204f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1205f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1206f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1207f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1208f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1209f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1210f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1211fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12123fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
12133fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1214f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1215f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1216fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12173fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
121803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
121903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1220f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
122103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
122203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
122331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
122403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
122503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
122603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
122703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1228f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
122903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
123003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
123103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
123203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1233f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
123403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1235f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
123603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
123703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1238f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1239f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
12400aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
12410aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
12420aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
12430aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1244f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
12450aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12460aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
124731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
12480aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
12490aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12500aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12510aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1252f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
12530aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
12540aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
12550aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12560aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12570aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
12580aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1259f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
12600aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
12610aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12620aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
12630aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12641b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
12653fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
12663fb14d0868594c78a777e805545209636814e223Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
12673fb14d0868594c78a777e805545209636814e223Martijn Coenen
1268f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
12693fb14d0868594c78a777e805545209636814e223Martijn Coenen
12703fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
127131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
12723fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
12733fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
12743fb14d0868594c78a777e805545209636814e223Martijn Coenen
12753fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1276f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
12773fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
12783fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
12793fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
12803fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
12813fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
12823fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
12833fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
12843fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
12853fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
12863fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
12873fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1288391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                tag.findAndReadNdef();
12893fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
12903fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
12914a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
12923fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
12933fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
12943fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
12953fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
12963fb14d0868594c78a777e805545209636814e223Martijn Coenen
12971b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1298fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
12991b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1300f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1301fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1302fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1303fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1304fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1305fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1306dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1307dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1308dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1309358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
1310358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1311358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1312358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1313358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1314358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1315358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1316dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
1317dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1318dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1319f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
13201b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1321bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1322bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1323bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1324bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1325bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1326bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1327bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1328bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1329bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1330bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1331ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen
1332ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        @Override
1333ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1334ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen            return mDeviceHost.getExtendedLengthApdusSupported();
1335ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        }
1336c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
1337f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
133892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly    void _nfcEeClose(int callingPid, IBinder binder) throws IOException {
1339dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // Blocks until a pending open() or transceive() times out.
1340dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        //TODO: This is incorrect behavior - the close should interrupt pending
1341dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // operations. However this is not supported by current hardware.
1342dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
13430571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly        synchronized (NfcService.this) {
13444ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            if (!isNfcEnabledOrShuttingDown()) {
1345dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC adapter is disabled");
1346dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1347dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (mOpenEe == null) {
1348dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC EE closed");
1349dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
135092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (callingPid != -1 && callingPid != mOpenEe.pid) {
1351dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new SecurityException("Wrong PID");
1352dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
135392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (mOpenEe.binder != binder) {
135492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                throw new SecurityException("Wrong binder handle");
135592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            }
1356dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
135792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            binder.unlinkToDeath(mOpenEe, 0);
1358f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
1359525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            doDisconnect(mOpenEe.handle);
1360dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mOpenEe = null;
1361dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1362fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1363dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        }
1364dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    }
1365dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
13664a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
136749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeNoException() {
136849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
136949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", 0);
137049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
137149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1372c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1373c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private Bundle writeEeException(int exceptionType, String message) {
137449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
1375c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putInt("e", exceptionType);
1376c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putString("m", message);
137749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
137849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
13790bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1380bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1381c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle open(String pkg, IBinder b) throws RemoteException {
1382c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1383bd555ee64250126b60b24814120a2049943920caNick Pelly
138449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
1385c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            int handle = _open(b);
1386c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            if (handle < 0) {
1387c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(handle, "NFCEE open exception.");
1388c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            } else {
138949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
13900bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
139149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
139249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
13930bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1394c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        /**
1395c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * Opens a connection to the secure element.
1396c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *
1397c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * @return A handle with a value >= 0 in case of success, or a
1398c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *         negative value in case of failure.
1399c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         */
1400c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private int _open(IBinder b) {
140149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
140231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
1403c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_NFC_DISABLED;
140449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
14057a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                if (mInProvisionMode) {
14067a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // Deny access to the NFCEE as long as the device is being setup
14077a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    return EE_ERROR_IO;
14087a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                }
14097a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                if (mDeviceHost.enablePN544Quirks() && mP2pLinkManager.isLlcpActive()) {
14107a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // Don't allow PN544-based devices to open the SE while the LLCP
14117a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // link is still up or in a debounce state. This avoids race
14127a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // conditions in the NXP stack around P2P/SMX switching.
14137a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    return EE_ERROR_EXT_FIELD;
14147a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                }
141549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe != null) {
1416c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_ALREADY_OPEN;
141749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
14180bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1419476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                boolean restorePolling = false;
1420476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                if (mDeviceHost.enablePN544Quirks() && mNfcPollingEnabled) {
1421476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // Disable polling for tags/P2P when connecting to the SMX
1422476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // on PN544-based devices. Whenever nfceeClose is called,
1423476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // the polling configuration will be restored.
1424476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    mDeviceHost.disableDiscovery();
1425476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    mNfcPollingEnabled = false;
1426476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    restorePolling = true;
1427476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                }
1428476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen
1429525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int handle = doOpenSecureElementConnection();
1430c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                if (handle < 0) {
1431476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen
1432476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    if (restorePolling) {
1433476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                        mDeviceHost.enableDiscovery();
1434476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                        mNfcPollingEnabled = true;
1435476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    }
1436c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return handle;
143749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
1438525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000);
1439ba6401757f8017faeb77423f2d08fd51be1d1051Nick Pelly
144092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
144149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                try {
144249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    b.linkToDeath(mOpenEe, 0);
144349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                } catch (RemoteException e) {
144449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    mOpenEe.binderDied();
144549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
144684e1e0adc2516afd35ebab029a52e764e0490559Jason parks
144784e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // Add the calling package to the list of packages that have accessed
144884e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // the secure element.
1449525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) {
145084e1e0adc2516afd35ebab029a52e764e0490559Jason parks                    mSePackages.add(packageName);
145184e1e0adc2516afd35ebab029a52e764e0490559Jason parks                }
1452c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1453c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                return handle;
145449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly           }
14550bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
14560bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1457bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
145892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public Bundle close(String pkg, IBinder binder) throws RemoteException {
1459c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1460c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
146149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
146249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
146392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                _nfcEeClose(getCallingPid(), binder);
146449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
146549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1466c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
14670bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
146849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
146949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
14700bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1471bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1472c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle transceive(String pkg, byte[] in) throws RemoteException {
1473c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1474bd555ee64250126b60b24814120a2049943920caNick Pelly
147549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
147649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            byte[] out;
147749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
147849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                out = _transceive(in);
147949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
148049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result.putByteArray("out", out);
148149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1482c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
14830bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
148449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
148549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
14860bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1487c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly        private byte[] _transceive(byte[] data) throws IOException {
148849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
148931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
149049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC is not enabled");
149149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
14920571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly                if (mOpenEe == null) {
149349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE is not open");
149449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
149549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (getCallingPid() != mOpenEe.pid) {
149649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new SecurityException("Wrong PID");
149749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
14980bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
14990bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1500525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceive(mOpenEe.handle, data);
15010bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
15020bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1503bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1504c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public int getCardEmulationRoute(String pkg) throws RemoteException {
1505c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
150649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mEeRoutingState;
15070bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
15080bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1509bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1510c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
1511c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
151249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            mEeRoutingState = route;
1513525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            ApplyRoutingTask applyRoutingTask = new ApplyRoutingTask();
1514525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            applyRoutingTask.execute();
1515525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
1516525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Block until route is set
1517525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                applyRoutingTask.get();
1518525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (ExecutionException e) {
1519525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1520525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (InterruptedException e) {
1521525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1522525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
15230bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
1524bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
1525bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1526c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void authenticate(String pkg, byte[] token) throws RemoteException {
1527c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1528bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1529525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1530525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
1531525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public String getDriverName(String pkg) throws RemoteException {
1532525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            NfcService.this.enforceNfceeAdminPerm(pkg);
1533525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mDeviceHost.getName();
1534525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1535c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
15360bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
153749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** resources kept while secure element is open */
153849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private class OpenSecureElement implements IBinder.DeathRecipient {
153949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int pid;  // pid that opened SE
154092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // binder handle used for DeathReceipient. Must keep
154192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // a reference to this, otherwise it can get GC'd and
154292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // the binder stub code might create a different BinderProxy
154392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // for the same remote IBinder, causing mismatched
154492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // link()/unlink()
154592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public IBinder binder;
154649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int handle; // low-level handle
154792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public OpenSecureElement(int pid, int handle, IBinder binder) {
154849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.pid = pid;
154949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.handle = handle;
155092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            this.binder = binder;
155149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1552bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
155349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void binderDied() {
155449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized (NfcService.this) {
155592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                Log.i(TAG, "Tracked app " + pid + " died");
155649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                pid = -1;
15570bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas                try {
155892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    _nfcEeClose(-1, binder);
1559dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                } catch (IOException e) { /* already closed */ }
15600bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
15610bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
156292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        @Override
156392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public String toString() {
156492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            return new StringBuilder('@').append(Integer.toHexString(hashCode())).append("[pid=")
156592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    .append(pid).append(" handle=").append(handle).append("]").toString();
156692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        }
15670bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    }
15680bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
15699a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    boolean isNfcEnabledOrShuttingDown() {
15709a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        synchronized (this) {
15719a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
15729a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        }
15739a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    }
15749a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen
157531949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
157631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
157731949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1578e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1579aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1580aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
158131949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
1582a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        final Object mCancelWaiter = new Object();
1583525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        final int mTimeout;
1584a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        boolean mCanceled = false;
1585525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1586525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public WatchDogThread(String threadName, int timeout) {
1587525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            super(threadName);
1588525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mTimeout = timeout;
1589525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1590525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
15912edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
15922edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
1593a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            try {
1594a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                synchronized (mCancelWaiter) {
1595a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    mCancelWaiter.wait(mTimeout);
1596a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    if (mCanceled) {
1597a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                        return;
1598a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    }
15992edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
1600a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            } catch (InterruptedException e) {
1601a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                // Should not happen; fall-through to abort.
1602a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                Log.w(TAG, "Watchdog thread interruped.");
1603a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                interrupt();
16042edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
1605a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            Log.e(TAG, "Watchdog triggered, aborting.");
1606a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            mDeviceHost.doAbort();
16072edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
1608a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project
16092edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
1610a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            synchronized (mCancelWaiter) {
1611a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCanceled = true;
1612a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCancelWaiter.notify();
1613a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            }
16142edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
16152edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
16162edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
1617fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /**
1618fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1619fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     */
1620fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    void applyRouting(boolean force) {
1621e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
16229a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            if (!isNfcEnabledOrShuttingDown() || mOpenEe != null) {
1623fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                // PN544 cannot be reconfigured while EE is open
1624e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1625e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1626525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
16277d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            if (mInProvisionMode) {
16287d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
16297d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
16307d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                if (!mInProvisionMode) {
16317d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Notify dispatcher it's fine to dispatch to any package now
16327d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // and allow handover transfers.
16337d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mNfcDispatcher.disableProvisioningMode();
16347d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mHandoverManager.setEnabled(true);
16357d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                }
16367d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            }
1637f439271150e4548f116919e0254d57655421581cMartijn Coenen            try {
1638f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.start();
1639f439271150e4548f116919e0254d57655421581cMartijn Coenen
1640525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) {
1641f439271150e4548f116919e0254d57655421581cMartijn Coenen                    /* TODO undo this after the LLCP stack is fixed.
1642f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * Use a different sequence when turning the screen off to
1643f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * workaround race conditions in pn544 libnfc. The race occurs
1644f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * when we change routing while there is a P2P target connect.
1645f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * The async LLCP callback will crash since the routing code
1646f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * is overwriting globals it relies on.
1647f439271150e4548f116919e0254d57655421581cMartijn Coenen                     */
1648f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (POLLING_MODE > SCREEN_STATE_OFF) {
1649f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfcPollingEnabled) {
1650f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-C OFF, disconnect");
1651f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfcPollingEnabled = false;
1652f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.disableDiscovery();
1653f439271150e4548f116919e0254d57655421581cMartijn Coenen                            maybeDisconnectTarget();
1654f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1655f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1656f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1657f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfceeRouteEnabled) {
1658f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-EE OFF");
1659f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfceeRouteEnabled = false;
1660f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.doDeselectSecureElement();
1661f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1662fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1663f439271150e4548f116919e0254d57655421581cMartijn Coenen                    return;
1664fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1665f439271150e4548f116919e0254d57655421581cMartijn Coenen
1666f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-EE routing
1667f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
1668f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1669f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfceeRouteEnabled) {
1670f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-EE ON");
1671f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfceeRouteEnabled = true;
1672f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.doSelectSecureElement();
1673f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1674f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1675f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force ||  mNfceeRouteEnabled) {
1676fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        Log.d(TAG, "NFC-EE OFF");
1677fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mNfceeRouteEnabled = false;
1678fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mDeviceHost.doDeselectSecureElement();
1679fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1680fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1681fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1682f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-C polling
1683f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= POLLING_MODE) {
1684f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfcPollingEnabled) {
1685f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C ON");
1686f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = true;
1687f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.enableDiscovery();
1688f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
16897d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                } else if (mInProvisionMode && mScreenState >= SCREEN_STATE_ON_LOCKED) {
16907d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Special case for setup provisioning
16917d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    if (!mNfcPollingEnabled) {
16927d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Log.d(TAG, "NFC-C ON");
16937d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mNfcPollingEnabled = true;
16947d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mDeviceHost.enableDiscovery();
16957d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    }
1696f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1697f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || mNfcPollingEnabled) {
1698f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C OFF");
1699f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = false;
1700f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.disableDiscovery();
1701f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1702fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1703f439271150e4548f116919e0254d57655421581cMartijn Coenen            } finally {
1704f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.cancel();
1705221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
170665945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
170765945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
170865945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
17092436ffe91853535fad87b7a8e03d8883bae20f20Arnaud Ferir    /** Disconnect any target if present */
171031949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
17119a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        if (!isNfcEnabledOrShuttingDown()) {
1712a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1713a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
171431949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
171531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
171631949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
171731949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
171831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
171931949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
172031949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
172131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
172231949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
172331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
172431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
172531949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
172631949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
172731949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
172831949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
172931949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
173031949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
173131949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
173231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
173331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
173431949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
173531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
173631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1737bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1738bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1739bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1740bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1741bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
174231949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
174331949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
174431949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
174531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
174631949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
17472f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
174831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
17490e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1750f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1751f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
175231949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
175331949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
175431949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1755f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1756b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1757b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
175831949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
175931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
176031949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
176131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
1762f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1763f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1764d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
17654a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1766c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            throws LlcpException {
17674a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1768d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1769d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1770d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
17713b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
1772e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen            throws LlcpException {
17733b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
1774e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    }
1775e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen
1776e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    /** For use by code in this process */
17774a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1778c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            int linearBufferLength) throws LlcpException {
17794a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1780d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1781d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
178257d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
1783b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
178457d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
178557d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
1786b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
1787b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
1788b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
1789b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
1790b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
1791b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1792b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
17933fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
1794b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
1795b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
179631949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
179731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
179831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
179931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
180031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
180131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
180231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
180331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
180431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
180531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new int[] { TagTechnology.NDEF },
180631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new Bundle[] { extras });
180731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
180831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
1809ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                    boolean delivered = mNfcDispatcher.dispatchTag(tag);
181031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (delivered) {
1811d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
181277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    } else {
1813d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
181431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
181531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
181631949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
181757d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
181831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
181931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
182031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
1821d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    playSound(SOUND_START);
182289baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
182389baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // When these tags start containing NDEF, they will require
182489baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // the stack to deal with them in a different way, since
182589baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // they are activated only really shortly.
182689baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // For now, don't consider NDEF on these.
182789baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
182889baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        tag.startPresenceChecking();
182989baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        dispatchTagEndpoint(tag);
183089baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        break;
183189baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    }
1832391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    NdefMessage ndefMsg = tag.findAndReadNdef();
1833c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
1834391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    if (ndefMsg != null) {
183531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        tag.startPresenceChecking();
1836ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                        dispatchTagEndpoint(tag);
183731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
183831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
183931949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.startPresenceChecking();
1840ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                            dispatchTagEndpoint(tag);
184131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
184231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
1843d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
184431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
184531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
184631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
184731949217328bf2357ff044f0d18677fe588c790cNick Pelly
184831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_CARD_EMULATION:
184931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Emulation message");
185031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] aid = (byte[]) msg.obj;
185131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
185231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent aidIntent = new Intent();
185331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.setAction(ACTION_AID_SELECTED);
185431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.putExtra(EXTRA_AID, aid);
185531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
185614a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(aidIntent);
185731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
185831949217328bf2357ff044f0d18677fe588c790cNick Pelly
185931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_EMV_CARD_REMOVAL:
186031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Removal message");
186131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
186231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent cardRemovalIntent = new Intent();
186331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
186431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
186514a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(cardRemovalIntent);
186631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
186731949217328bf2357ff044f0d18677fe588c790cNick Pelly
186831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_APDU_RECEIVED:
186931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "APDU Received message");
187031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] apduBytes = (byte[]) msg.obj;
187131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
187231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent apduReceivedIntent = new Intent();
187331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
187431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (apduBytes != null && apduBytes.length > 0) {
187531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
187631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
187731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
187814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(apduReceivedIntent);
187931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
188031949217328bf2357ff044f0d18677fe588c790cNick Pelly
188131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_MIFARE_ACCESS:
188231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "MIFARE access message");
188331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
188431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] mifareCmd = (byte[]) msg.obj;
188531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent mifareAccessIntent = new Intent();
188631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
188731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mifareCmd != null && mifareCmd.length > 1) {
188831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        int mifareBlock = mifareCmd[1] & 0xff;
188931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
189031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
189131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
189231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
189314a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(mifareAccessIntent);
189431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
1895c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
189631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
189796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
189896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent actIntent = new Intent(ACTION_LLCP_UP);
189996e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(actIntent);
190096e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
190131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
190231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
190331949217328bf2357ff044f0d18677fe588c790cNick Pelly
190431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
190596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
190696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
190796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(deactIntent);
190896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
190931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
191031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
191131949217328bf2357ff044f0d18677fe588c790cNick Pelly
191231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
191331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
191431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
191531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
191631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
191731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
191831949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
191931949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
192031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
192131949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
192231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
192331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
192431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
192531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
192631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
192731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
192831949217328bf2357ff044f0d18677fe588c790cNick Pelly
192977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
193031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
193157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                case MSG_LLCP_LINK_FIRST_PACKET:
193257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    mP2pLinkManager.onLlcpFirstPacketReceived();
193357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    break;
193431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_TARGET_DESELECTED:
193531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Broadcast Intent Target Deselected */
193631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Target Deselected");
193731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent intent = new Intent();
193831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
193931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting Intent");
194031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
194131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
194231949217328bf2357ff044f0d18677fe588c790cNick Pelly
194331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_ACTIVATED: {
194431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
194531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOnIntent = new Intent();
194631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
194714a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOnIntent);
194831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
194931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
195031949217328bf2357ff044f0d18677fe588c790cNick Pelly
195131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_DEACTIVATED: {
195231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
195331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOffIntent = new Intent();
195431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
195514a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOffIntent);
195631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
195731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
195831949217328bf2357ff044f0d18677fe588c790cNick Pelly
1959525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_ACTIVATED: {
1960525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE ACTIVATED");
1961525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeActivated = new Intent();
1962525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeActivated.setAction(ACTION_SE_LISTEN_ACTIVATED);
1963525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeActivated);
1964525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
1965525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
1966525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1967525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_DEACTIVATED: {
1968525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE DEACTIVATED");
1969525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeDeactivated = new Intent();
1970525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeDeactivated.setAction(ACTION_SE_LISTEN_DEACTIVATED);
1971525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeDeactivated);
1972525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
1973525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
197431949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
197531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
197631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
197731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
1978b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1979d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
198014a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        private void sendSeBroadcast(Intent intent) {
198114a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
1982c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            // Resume app switches so the receivers can start activites without delay
1983c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfcDispatcher.resumeAppSwitches();
1984c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
1985e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            synchronized(this) {
1986e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                for (PackageInfo pkg : mInstalledPackages) {
1987e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (pkg != null && pkg.applicationInfo != null) {
1988e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
1989e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            intent.setPackage(pkg.packageName);
1990e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            mContext.sendBroadcast(intent);
1991e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        }
1992c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
1993c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
1994c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
199514a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        }
199614a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton
1997d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
1998d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
1999d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2000d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
2001d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
2002d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
2003d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
2004d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
2005d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
2006d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
2007d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
200831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
200931949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
201031949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
2011d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
201277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                            mP2pLinkManager.onLlcpActivated();
2013d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
2014d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
2015d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
2016d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
2017d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
2018d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
2019d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
2020d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
2021d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
2022d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2023d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2024d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
2025d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
2026d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
2027d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
2028d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
2029d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2030d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
2031d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
2032d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
2033d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
2034d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
2035d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
2036d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
203731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
203831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
203931949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
2040d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
204177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
2042d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
2043d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2044d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2045d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
2046d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2047d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
2048d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2049d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
2050d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
2051d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2052ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        private void dispatchTagEndpoint(TagEndpoint tagEndpoint) {
2053f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
2054f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
2055f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
2056ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            if (!mNfcDispatcher.dispatchTag(tag)) {
2057f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
2058d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
2059d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else {
2060d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
20613fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
20623fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
2063b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
2064b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
2065b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
206649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
2067fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
2068fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
2069fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        protected Void doInBackground(Integer... params) {
2070fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            synchronized (NfcService.this) {
2071fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (params == null || params.length != 1) {
2072fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    // force apply current routing
2073fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    applyRouting(true);
2074fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    return null;
2075161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2076fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                mScreenState = params[0].intValue();
2077fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
2078525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
2079525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2080525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    applyRouting(false);
2081525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
2082525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
2083161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2084fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return null;
20857c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
20867c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
20877c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
20887c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
2089525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
20900e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        @Override
20910e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public void onReceive(Context context, Intent intent) {
209231949217328bf2357ff044f0d18677fe588c790cNick Pelly            String action = intent.getAction();
2093525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
2094e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
2095e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
2096e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
2097e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                updatePackageCache();
2098e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2099e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
2100e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    // Clear the NFCEE access cache in case a UID gets recycled
2101e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    mNfceeAccessControl.invalidateCache();
2102e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2103e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
2104e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (dataRemoved) {
2105e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        Uri data = intent.getData();
2106e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (data == null) return;
2107e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        String packageName = data.getSchemeSpecificPart();
21087a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton
2109e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        synchronized (NfcService.this) {
2110e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            if (mSePackages.contains(packageName)) {
2111e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                new EnableDisableTask().execute(TASK_EE_WIPE);
2112e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                mSePackages.remove(packageName);
2113e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            }
21147a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                        }
2115bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                    }
2116bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
2117525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
2118525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                EnableDisableTask eeWipeTask = new EnableDisableTask();
2119525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                eeWipeTask.execute(TASK_EE_WIPE);
2120525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2121525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    eeWipeTask.get();  // blocks until EE wipe is complete
2122525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (ExecutionException e) {
2123525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2124525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (InterruptedException e) {
2125525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2126525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2127525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
2128525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
2129525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    };
2130525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
2131525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2132525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
2133525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2134525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            String action = intent.getAction();
2135525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(
2136525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
2137525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2138525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute();
2139525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(Intent.ACTION_SCREEN_ON)
2140525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_SCREEN_OFF)
2141525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_USER_PRESENT)) {
2142525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2143525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int screenState = SCREEN_STATE_OFF;
2144525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
2145525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_OFF;
2146525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
2147525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = mKeyguard.isKeyguardLocked() ?
2148525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
2149525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
2150525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_ON_UNLOCKED;
2151525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2152525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
215331949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
215431949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
215531949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
215631949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
215731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
215831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
215931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
216031949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
216131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
216231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
21631668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
21641668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
216531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
216631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
216731949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
216831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
216931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
21703859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
21713859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                mP2pLinkManager.onUserSwitched();
2172f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
2173f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
2174f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
217531949217328bf2357ff044f0d18677fe588c790cNick Pelly
217631949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** Returns true if airplane mode is currently on */
217731949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
21787d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        return Settings.System.getInt(mContentResolver,
21797d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
218031949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
218131949217328bf2357ff044f0d18677fe588c790cNick Pelly
2182fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** for debugging only - no i18n */
218331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
218431949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
218531949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
218631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
218731949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
218831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
218931949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
219031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
219131949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
219231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
219331949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
219431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
219531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
219631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
219731949217328bf2357ff044f0d18677fe588c790cNick Pelly
2198fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** For debugging only - no i18n */
2199fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static String screenStateToString(int screenState) {
2200fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        switch (screenState) {
2201fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_OFF:
2202fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "OFF";
2203fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_LOCKED:
2204fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_LOCKED";
2205fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_UNLOCKED:
2206fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_UNLOCKED";
2207fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            default:
2208fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "UNKNOWN";
2209fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
2210fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
2211fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
221231949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
221350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
221450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
221550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
221650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
221750effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
221850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
221950effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
222050effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
222131949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
222231949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
22230b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
2224fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mScreenState=" + screenStateToString(mScreenState));
2225fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfcPollingEnabled=" + mNfcPollingEnabled);
2226fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfceeRouteEnabled=" + mNfceeRouteEnabled);
222731949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
222831949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
222992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            pw.println("mOpenEe=" + mOpenEe);
223077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
2231c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfceeAccessControl.dump(fd, pw, args);
2232391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            mNfcDispatcher.dump(fd, pw, args);
223356f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
2234c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
223531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
223631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
223774180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
2238