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;
26d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenenimport com.android.nfc.cardemulation.AidRoutingManager;
279f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenenimport com.android.nfc.cardemulation.HostEmulationManager;
2878976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenenimport com.android.nfc.cardemulation.RegisteredAidCache;
294bbd47e5507d4c47a4d722216606307e45195a0aMartijn Coenenimport com.android.nfc.dhimpl.NativeNfcManager;
304bbd47e5507d4c47a4d722216606307e45195a0aMartijn Coenenimport com.android.nfc.dhimpl.NativeNfcSecureElement;
31c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
32efb7a3df560585994cebd40fcf5ffbc864f8c358Martijn Coenenimport android.app.ActivityManager;
332f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pellyimport android.app.Application;
34275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parksimport android.app.KeyguardManager;
3505973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamiltonimport android.app.PendingIntent;
3613d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.BroadcastReceiver;
37a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenenimport android.content.ComponentName;
3831949217328bf2357ff044f0d18677fe588c790cNick Pellyimport android.content.ContentResolver;
3913d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Context;
4013d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Intent;
4113d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.IntentFilter;
420e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.content.SharedPreferences;
43483f3065021c878468ab0921140aa9a2c89b4246Martijn Coenenimport android.content.pm.PackageInfo;
4493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamiltonimport android.content.pm.PackageManager;
457d8987f233985a5ff29226890e11012275d325f5Martijn Coenenimport android.content.res.Resources.NotFoundException;
46d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.AudioManager;
47d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.SoundPool;
483fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamiltonimport android.net.Uri;
49f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.ErrorCodes;
50f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.FormatException;
5131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenenimport android.nfc.IAppCallback;
520e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.INfcAdapter;
5349d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.nfc.INfcAdapterExtras;
54a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenenimport android.nfc.INfcCardEmulation;
55f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.INfcTag;
56f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NdefMessage;
57f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NfcAdapter;
580e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.Tag;
5924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.nfc.TechListParcel;
609d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenenimport android.nfc.TransceiveResult;
61a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenenimport android.nfc.cardemulation.ApduServiceInfo;
62aca0d055a82da850c27f6872405602ad5f3fee7bJeff Hamiltonimport android.nfc.tech.Ndef;
6381c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport android.nfc.tech.TagTechnology;
647c034a7fe7d36b1ab039af2c44717812ea02657eNick Pellyimport android.os.AsyncTask;
6550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Rootimport android.os.Binder;
6696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenenimport android.os.Build;
67b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamiltonimport android.os.Bundle;
68b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Handler;
6949d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.os.IBinder;
70b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Message;
71533043d1003de2f6a20a29201100d94c3c7bc9caNick Pellyimport android.os.PowerManager;
724467dca5650a170af5020c10a8ccb25f86f1007fNick Pellyimport android.os.Process;
73f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.os.RemoteException;
7413d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.os.ServiceManager;
753e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenenimport android.os.SystemClock;
76525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.os.UserHandle;
77d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.provider.Settings;
78f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.util.Log;
7931949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.FileDescriptor;
8057d376f1ee1a3939977b95759525585abb9601fbJeff Hamiltonimport java.io.IOException;
8131949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.PrintWriter;
8231949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.Arrays;
833ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamiltonimport java.util.HashMap;
8484e1e0adc2516afd35ebab029a52e764e0490559Jason parksimport java.util.HashSet;
85c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.util.List;
86c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenenimport java.util.NoSuchElementException;
8731949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.concurrent.ExecutionException;
883ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
89525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectpublic class NfcService implements DeviceHostListener {
90bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
91bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
92c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = false;
9376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
94fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
95d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
96fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
97c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** Regular NFC permission */
98bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM = android.Manifest.permission.NFC;
99bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM_ERROR = "NFC permission required";
100c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
101c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** NFC ADMIN permission - only for system apps */
102bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
103bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
104bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
10577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
106f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
107416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
108416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
109416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
110416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
111416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
112416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
1131668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
114a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen    static final boolean SE_BROADCASTS_WITH_HCE = true;
115a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
116b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
117b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_CARD_EMULATION = 1;
118b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_ACTIVATION = 2;
119b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
120b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_TARGET_DESELECTED = 4;
121b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    static final int MSG_MOCK_NDEF = 7;
122c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_ACTIVATED = 8;
123c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_DEACTIVATED = 9;
1242c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_APDU_RECEIVED = 10;
1252c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
1262c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_MIFARE_ACCESS = 12;
127525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_ACTIVATED = 13;
128525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_DEACTIVATED = 14;
12957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    static final int MSG_LLCP_LINK_FIRST_PACKET = 15;
130d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_ROUTE_AID = 16;
131d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_UNROUTE_AID = 17;
132d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_COMMIT_ROUTING = 18;
133b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
13431949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
13531949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
13631949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
13731949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_EE_WIPE = 4;
13831949217328bf2357ff044f0d18677fe588c790cNick Pelly
139fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    // Screen state, used by mScreenState
140fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_UNKNOWN = 0;
141fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_OFF = 1;
142fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_LOCKED = 2;
143fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_UNLOCKED = 3;
144fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
14549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Copied from com.android.nfc_extras to avoid library dependency
14649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Must keep in sync with com.android.nfc_extras
14749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_OFF = 1;
14849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
1497efbf69a37134ccbd86a1f6b4121f16b4a80eaaeNick Pelly
150c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // Return values from NfcEe.open() - these are 1:1 mapped
151c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // to the thrown EE_EXCEPTION_ exceptions in nfc-extras.
152c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_IO = -1;
153c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_ALREADY_OPEN = -2;
154c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_INIT = -3;
155c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_LISTEN_MODE = -4;
156c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_EXT_FIELD = -5;
157c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_NFC_DISABLED = -6;
158c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
159fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** minimum screen state that enables NFC polling (discovery) */
160fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
161fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
162525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for NFC controller to initialize before watchdog
163525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off. This time is chosen large, because firmware download
164525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // may be a part of initialization.
165525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int INIT_WATCHDOG_MS = 90000;
166525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
167525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for routing to be applied before watchdog
168525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off
169525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int ROUTING_WATCHDOG_MS = 10000;
170525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1713e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Amount of time to wait before closing the NFCEE connection
1723e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // in a disable/shutdown scenario.
1733e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_OPERATIONS_MS = 5000;
1743e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Polling interval for waiting on NFCEE operations
1753e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_POLL_MS = 100;
1763e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
17731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    // Default delay used for presence checks
17831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    static final int DEFAULT_PRESENCE_CHECK_DELAY = 125;
17931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
180d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
181d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
182d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
183d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
184d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
18549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_ON_DETECTED =
18649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
18749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_OFF_DETECTED =
18849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
18949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_AID_SELECTED =
19049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.AID_SELECTED";
19149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
19249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
19396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_UP =
19496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_UP";
19596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
19696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_DOWN =
19796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_DOWN";
19896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
1992c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_APDU_RECEIVED =
2002c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.APDU_RECEIVED";
2012c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_APDU_BYTES =
2022c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.APDU_BYTES";
2032c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
2042c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_EMV_CARD_REMOVAL =
2052c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
2062c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
2072c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_MIFARE_ACCESS_DETECTED =
2082c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
2092c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_MIFARE_BLOCK =
2102c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.MIFARE_BLOCK";
2112c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
212525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_ACTIVATED =
213525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_ACTIVATED";
214525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_DEACTIVATED =
215525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_DEACTIVATED";
21649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
21749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
21849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
2190bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    private NativeNfcSecureElement mSecureElement;
22049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private OpenSecureElement mOpenEe;  // null when EE closed
221c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    private final ReaderModeDeathRecipient mReaderModeDeathRecipient =
222c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            new ReaderModeDeathRecipient();
22349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private int mEeRoutingState;  // contactless interface routing
2240bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
225d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    // fields below must be used only on the UI thread and therefore aren't synchronized
226d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    boolean mP2pStarted = false;
227d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
2282f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
229fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
230525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // mSePackages holds packages that accessed the SE, but only for the owner user,
231525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // as SE access is not granted for non-owner users.
232fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    HashSet<String> mSePackages = new HashSet<String>();
233fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int mScreenState;
2347d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
235fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mIsNdefPushEnabled;
236fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfceeRouteEnabled;  // current Device Host state of NFC-EE routing
237fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfcPollingEnabled;  // current Device Host state of NFC-C polling
2389f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    boolean mHostRouteEnabled;   // current Device Host state of host-based routing
239c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    boolean mReaderModeEnabled;  // current Device Host state of reader mode
24031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    ReaderModeParams mReaderModeParams;
24131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
242e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    List<PackageInfo> mInstalledPackages; // cached version of installed packages
24331949217328bf2357ff044f0d18677fe588c790cNick Pelly
24431949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
24531949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
24631949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
24731949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
2482f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
2492f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
25005973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
2514a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
2520e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
2530e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
254525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mRoutingWakeLock;
255525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mEeWakeLock;
256525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
257d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
258d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
259d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
260d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
26177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
2624a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
2634a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
2644a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterExtrasService mExtrasService;
265a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    CardEmulationService mCardEmulationService;
26631949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
26731949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
26896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    boolean mIsDebugBuild;
2690a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen    boolean mIsHceCapable;
270c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    NfceeAccessControl mNfceeAccessControl;
2712ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
27276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
273fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    private PowerManager mPowerManager;
274275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
2757d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private HandoverManager mHandoverManager;
2767d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private ContentResolver mContentResolver;
27778976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen    private RegisteredAidCache mAidCache;
2789f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    private HostEmulationManager mHostEmulationManager;
279d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    private AidRoutingManager mAidRoutingManager;
280d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
281d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    private static NfcService sService;
282d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
28393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceAdminPerm(Context context) {
284c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
28593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
28693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
28789c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen    public static void validateUserId(int userId) {
28889c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        if (userId != UserHandle.getCallingUserId()) {
28989c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            throw new SecurityException("userId passed in it not the calling user.");
29089c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        }
29189c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen    }
29289c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen
293c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public void enforceNfceeAdminPerm(String pkg) {
294c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (pkg == null) {
295c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException("caller must pass a package name");
296c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
297c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
298c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (!mNfceeAccessControl.check(Binder.getCallingUid(), pkg)) {
299c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
300c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    " denies NFCEE access to " + pkg);
301c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
302525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
303525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            throw new SecurityException("only the owner is allowed to call SE APIs");
304525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
30593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
30693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
307d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
308d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
309d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
310f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
3110e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
312f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
313f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
314f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
315f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
316f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
317f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
318f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
319d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
320f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationDeselected() {
321a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3220a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
3230a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
324f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
325f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
326f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
327f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
328f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
329d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
330f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationAidSelected(byte[] aid) {
331a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3320a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_CARD_EMULATION, aid);
3330a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
334f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
335f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
336f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
3379f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen     * Notifies transaction
3389f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen     */
3399f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3409f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationActivated() {
3410a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3420a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyHostEmulationActivated();
3430a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3449f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3459f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3469f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3479f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationData(byte[] data) {
3480a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3490a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyHostEmulationData(data);
3500a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3519f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3529f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3539f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3549f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationDeactivated() {
3550a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3560a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyNostEmulationDeactivated();
3570a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3589f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3599f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3609f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    /**
361f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
362f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
363f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
364f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
365f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
366f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
367f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
368f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
369f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
370f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
371d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
372f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
373f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
374f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
375f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
37657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    /**
37757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     * Notifies P2P Device detected, first packet received over LLCP link
37857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     */
37957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    @Override
38057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
38157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
38257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    }
38357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
384d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
385f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldActivated() {
386a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3870a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
3880a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
389f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
390f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
391d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
392f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldDeactivated() {
393a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3940a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
3950a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
396f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
397f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
398f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
399525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenActivated() {
400a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4010a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_LISTEN_ACTIVATED, null);
4020a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
403525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
404525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
405525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
406525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenDeactivated() {
407a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4080a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_LISTEN_DEACTIVATED, null);
4090a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
410525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
411525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
412525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
413525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
414442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeApduReceived(byte[] apdu) {
415a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4160a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
4170a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
418442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
419442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
420442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
421442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeEmvCardRemoval() {
422a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4230a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
4240a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
425442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
426442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
427442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
428442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeMifareAccess(byte[] block) {
429a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4300a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
4310a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
432442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
433442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
43431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    final class ReaderModeParams {
43531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public int flags;
43631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public IAppCallback callback;
43731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public int presenceCheckDelay;
43831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    }
43931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
440525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public NfcService(Application nfcApplication) {
4414a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
4424a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
443ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly        mExtrasService = new NfcAdapterExtrasService();
444a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        mCardEmulationService = new CardEmulationService();
4454a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton
4462f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
4472f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
448d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
449d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
450525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext = nfcApplication;
4517d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mContentResolver = mContext.getContentResolver();
452525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDeviceHost = new NativeNfcManager(mContext, this);
45374180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
4547d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager = new HandoverManager(mContext);
4557d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        boolean isNfcProvisioningEnabled = false;
4567d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        try {
4577d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
4587d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    R.bool.enable_nfc_provisioning);
4597d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } catch (NotFoundException e) {
4607d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
4617d8987f233985a5ff29226890e11012275d325f5Martijn Coenen
4627d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        if (isNfcProvisioningEnabled) {
4637d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
4647d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
4657d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } else {
4667d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = false;
4677d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
468525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
4697d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager.setEnabled(!mInProvisionMode);
4707d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
4717d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
472525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
47324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
47437058bf7b59def2f9a565ae5b16aae54e80e9e95Sunil Jogi        mSecureElement = new NativeNfcSecureElement(mContext);
475eab09ad7204fe1f0feaca33efccf75c1bb388708Robert Tsai        mEeRoutingState = ROUTE_OFF;
4760bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
477525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mNfceeAccessControl = new NfceeAccessControl(mContext);
478c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
479525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
4800e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
481f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
48231949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
4830b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
484f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
48596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
48696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
487525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
488525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
489525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mRoutingWakeLock = mPowerManager.newWakeLock(
490525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
491525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock = mPowerManager.newWakeLock(
492525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock");
493275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
494525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
495fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        mScreenState = checkScreenState();
496533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
497d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
498f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
499525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents for all users
500eead88c5e2bdd34eb33fdf2c76717f9edb9e0396Jeff Hamilton        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
50165945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_OFF);
50265945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
503275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
5043859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        filter.addAction(Intent.ACTION_USER_SWITCHED);
50531949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
506525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
5070e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
5080a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        PackageManager pm = mContext.getPackageManager();
509341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen        mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
5100a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mIsHceCapable) {
5110a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mAidRoutingManager = new AidRoutingManager();
512451ba48faa87d78bfbec0597ff06af1747cf6acbMartijn Coenen            mAidCache = new RegisteredAidCache(mContext, mAidRoutingManager);
51378976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            mHostEmulationManager = new HostEmulationManager(mContext, mAidCache);
514a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        }
515a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
5160a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            IntentFilter ownerFilter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
5170a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
5180a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
5190a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
5200a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5210a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mContext.registerReceiver(mOwnerReceiver, ownerFilter);
5220a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5230a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter = new IntentFilter();
5240a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
5250a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
5260a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addDataScheme("package");
5270a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5280a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mContext.registerReceiver(mOwnerReceiver, ownerFilter);
5290a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5300a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            updatePackageCache();
5310a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
532e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
53331949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
53431949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
53531949217328bf2357ff044f0d18677fe588c790cNick Pelly
536d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
537d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
538d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
539d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
540525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
541525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
542525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
543d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
544d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
545d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
546d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
547d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
548d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
549d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
550d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
551d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
552d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
553d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
554d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
555d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
55631949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
5577d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
5587d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_RADIOS);
5597d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String toggleableRadios = Settings.System.getString(mContentResolver,
5607d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
56131949217328bf2357ff044f0d18677fe588c790cNick Pelly
56231949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
5637d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
56431949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
5657d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            toggleableRadios.contains(Settings.Global.RADIO_NFC);
56631949217328bf2357ff044f0d18677fe588c790cNick Pelly
56731949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
56831949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
56931949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
57031949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
57131949217328bf2357ff044f0d18677fe588c790cNick Pelly
572e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    void updatePackageCache() {
573525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        PackageManager pm = mContext.getPackageManager();
574525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
575e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        synchronized (this) {
576e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            mInstalledPackages = packages;
577e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        }
578e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    }
579e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
580fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int checkScreenState() {
581fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        if (!mPowerManager.isScreenOn()) {
582fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_OFF;
583fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else if (mKeyguard.isKeyguardLocked()) {
584fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_LOCKED;
585fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else {
586fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_UNLOCKED;
587fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
588fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
589fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
590525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    int doOpenSecureElementConnection() {
591525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
592525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
593525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mSecureElement.doOpenSecureElementConnection();
594525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
595525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
596525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
597525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
598525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
599525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceive(int handle, byte[] cmd) {
600525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
601525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
602525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceiveNoLock(handle, cmd);
603525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
604525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
605525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
606525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
607525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
608525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceiveNoLock(int handle, byte[] cmd) {
609525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        return mSecureElement.doTransceive(handle, cmd);
610525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
611525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
612525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    void doDisconnect(int handle) {
613525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
614525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
615525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mSecureElement.doDisconnect(handle);
616525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
617525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
618525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
619525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
620525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
62131949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
62231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
62331949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
62431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
62531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
62631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
62731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
62831949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
62931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
63031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
63131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
63231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
63331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
63431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
63531949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
63631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
63731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
63831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
63931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
64031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
64131949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
64231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
64331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
64431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
64531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
64631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
64731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
64831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * process may temporarily enable the NFC adapter
64931949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
65031949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
65131949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
65231949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
65331949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
65431949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
65531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
65631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
65731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
65831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
65931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
66031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
66131949217328bf2357ff044f0d18677fe588c790cNick Pelly
6624467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
6634467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
6644467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
6654467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
6664467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
6674467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
6684467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
6694467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
6704467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
67131949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
67231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
67331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
67431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
67531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
67631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
67731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
67831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
6790fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    Log.d(TAG,"checking on firmware download");
6801668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
68131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
6821668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
6830fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is on. Doing normal stuff");
68431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
6850fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
6860fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is off.  Checking firmware version");
6870fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
688efb7a3df560585994cebd40fcf5ffbc864f8c358Martijn Coenen                        // Build initial AID cache even if NFC is off
689341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen                        if (mIsHceCapable) {
69043dc7d3d2160c5fbd063e27c2810b87f4626e75fMartijn Coenen                            mAidCache.invalidateCache(ActivityManager.getCurrentUser());
69143dc7d3d2160c5fbd063e27c2810b87f4626e75fMartijn Coenen                        }
69231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
69331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
69431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
69531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
69631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
69731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        executeEeWipe();
69831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
69931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
70031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_EE_WIPE:
70131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    executeEeWipe();
70231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
70331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
704d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
705d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
706d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
70731949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
70831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
70931949217328bf2357ff044f0d18677fe588c790cNick Pelly
71031949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
71131949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
71231949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
71331949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
71431949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
71531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
71631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
71731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
71831949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
71931949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
72031949217328bf2357ff044f0d18677fe588c790cNick Pelly
721525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
722525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            watchDog.start();
723525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
724525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
725525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
726525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (!mDeviceHost.initialize()) {
727525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.w(TAG, "Error enabling NFC");
728525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        updateState(NfcAdapter.STATE_OFF);
729525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        return false;
730525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
731525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
732525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
733525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
734525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
735525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                watchDog.cancel();
73631949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
73731949217328bf2357ff044f0d18677fe588c790cNick Pelly
7380a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            if (mIsHceCapable) {
7390a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen                // Generate the initial card emulation routing table
740f5cd84c3a7ffb66196ab3c0745569da937d7533bMartijn Coenen                mAidCache.onNfcEnabled();
7410a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            }
742d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
74331949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized(NfcService.this) {
74431949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
7450b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
74631949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
74731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
74831949217328bf2357ff044f0d18677fe588c790cNick Pelly
749d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
750d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
75131949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
7520c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
753fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
75431949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
75531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
75631949217328bf2357ff044f0d18677fe588c790cNick Pelly
75731949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
75831949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
75931949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
76031949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
76131949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
76231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
76331949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
76431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
76531949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
76631949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
76731949217328bf2357ff044f0d18677fe588c790cNick Pelly
76831949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
76931949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
77031949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
77131949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
772525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
77331949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
77431949217328bf2357ff044f0d18677fe588c790cNick Pelly
775953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            if (mIsHceCapable) {
776f5cd84c3a7ffb66196ab3c0745569da937d7533bMartijn Coenen                mAidCache.onNfcDisabled();
777953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            }
778d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
77977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
78031949217328bf2357ff044f0d18677fe588c790cNick Pelly
7813e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            /* The NFC-EE may still be opened by another process,
7823e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * and a transceive() could still be in progress on
7833e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * another Binder thread.
7843e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * Give it a while to finish existing operations
7853e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * before we close it.
7863e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             */
7873e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            Long startTime = SystemClock.elapsedRealtime();
7883e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            do {
7893e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                synchronized (NfcService.this) {
7903e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    if (mOpenEe == null)
7913e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                        break;
7923e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
7933e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                try {
7943e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    Thread.sleep(WAIT_FOR_NFCEE_POLL_MS);
7953e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                } catch (InterruptedException e) {
7963e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    // Ignore
7973e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
7983e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            } while (SystemClock.elapsedRealtime() - startTime < WAIT_FOR_NFCEE_OPERATIONS_MS);
7993e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
8004ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            synchronized (NfcService.this) {
8014ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                if (mOpenEe != null) {
8024ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    try {
8034ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                        _nfcEeClose(-1, mOpenEe.binder);
8044ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    } catch (IOException e) { }
8054ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                }
8064ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            }
8074ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen
80831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
80931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
81031949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
81131949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
81231949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
81331949217328bf2357ff044f0d18677fe588c790cNick Pelly
8140b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
81531949217328bf2357ff044f0d18677fe588c790cNick Pelly
81631949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
81731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
81831949217328bf2357ff044f0d18677fe588c790cNick Pelly
81931949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
82031949217328bf2357ff044f0d18677fe588c790cNick Pelly
82131949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_OFF);
82231949217328bf2357ff044f0d18677fe588c790cNick Pelly
823d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
824d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
82531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
82631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
82731949217328bf2357ff044f0d18677fe588c790cNick Pelly
82831949217328bf2357ff044f0d18677fe588c790cNick Pelly        void executeEeWipe() {
82931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // TODO: read SE reset list from /system/etc
830525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            byte[][]apdus = mDeviceHost.getWipeApdus();
831525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
832525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (apdus == null) {
833525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.d(TAG, "No wipe APDUs found");
834525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                return;
835525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
83631949217328bf2357ff044f0d18677fe588c790cNick Pelly
83731949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
838525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Hold a wake-lock over the entire wipe procedure
839525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.acquire();
840525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
841525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (tempEnable && !enableInternal()) {
842ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
84331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
844f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
845525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
846525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    // NFC enabled
847525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    int handle = 0;
848525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    try {
849525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.i(TAG, "Executing SE wipe");
850525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        handle = doOpenSecureElementConnection();
8512b4dc11f4508cdb662a8069cccf9f2273004a4c8Martijn Coenen                        if (handle < 0) {
852525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Log.w(TAG, "Could not open the secure element");
853525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            return;
854525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
855525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        // TODO: remove this hack
856525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
857525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Thread.sleep(1000);
858525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } catch (InterruptedException e) {
859525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            // Ignore
860525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
86131949217328bf2357ff044f0d18677fe588c790cNick Pelly
862525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
863525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
864525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            for (byte[] cmd : apdus) {
865525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                byte[] resp = doTransceiveNoLock(handle, cmd);
866525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                if (resp == null) {
867525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
868525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    break;
869525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                }
870525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            }
871525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } finally {
872525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            mDeviceHost.resetTimeouts();
873525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
874525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    } finally {
8752b4dc11f4508cdb662a8069cccf9f2273004a4c8Martijn Coenen                        if (handle >= 0) {
876525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            doDisconnect(handle);
877525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
878525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
879525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
880525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (tempEnable) {
881525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        disableInternal();
882525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
883ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                }
884525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
885525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEeWakeLock.release();
88631949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
887525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            Log.i(TAG, "SE wipe done");
88831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
88931949217328bf2357ff044f0d18677fe588c790cNick Pelly
89031949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
8912a3f6f141fdaf746a81ce850a8ab0ef251041966mike wakerly            synchronized (NfcService.this) {
89231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
89331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
89431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
89531949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
89631949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
89731949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
89831949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
899525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
90031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
90131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
90231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
90331949217328bf2357ff044f0d18677fe588c790cNick Pelly
90431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
90531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
90631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
90731949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
90831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
9090e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
9100e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
911d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
912d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
913d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
914d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
915d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
916d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
917d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
918d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
919d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
920d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
921d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
922d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
923d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
924d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
925d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
926d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
927d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
928d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
929d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
930d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
9310e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
9324a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
933fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9340e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
93593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
9360e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
93731949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
9381668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen
9391668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
9401668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                if (!mIsAirplaneToggleable) {
9411668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    Log.i(TAG, "denying enable() request (airplane mode)");
9421668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    return false;
9431668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                }
9441668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                // Make sure the override survives a reboot
9451668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
9461668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
947f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
94831949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
94931949217328bf2357ff044f0d18677fe588c790cNick Pelly
95031949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
951f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
952f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
953fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
954290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi        public boolean disable(boolean saveState) throws RemoteException {
95593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
9560e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
957290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            if (saveState) {
958290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi                saveNfcOnSetting(false);
959290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            }
960290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi
96131949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
96231949217328bf2357ff044f0d18677fe588c790cNick Pelly
96331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
964f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
965f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
966fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9670b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
96831949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
9699993a5a96a862cea4512509b413d0de6cacb7c14Nick Pelly                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
97031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
971d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
972d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
973d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9740b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
975d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
976d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
9770b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
97831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
97931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
9800b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
9810b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
98231949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
9830b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
98431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
98577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
986d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
987d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
988d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
989d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
990d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
991d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9920b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
993d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
994d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
9950b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
99631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
99731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
9980b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
9990b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
100031949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
10010b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
100231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
100377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
1004d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
1005d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
1006d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
1007d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
1008d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
1009d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
10100b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
101124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
101205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1013a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
10140b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
10150b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
10160b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
10170b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
1018ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
1019a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
1020a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
1021a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
1022a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
1023a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
1024a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
1025a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
1026a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
1027a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
1028a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
1029a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
1030a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
1031a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
1032a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
103324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
103424dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
103524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
103624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
103724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
103849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
10390b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
10402094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
10412094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
10422094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
104331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public void setAppCallback(IAppCallback callback) {
1044ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
10453859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
1046ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
1047ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
1048ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
10490e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
10500e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
10510e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
10520e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
1053fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1054c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) {
1055c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
105649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mExtrasService;
10570bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
10580bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1059fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1060a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public INfcCardEmulation getNfcCardEmulationInterface() {
1061a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            return mCardEmulationService;
1062a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1063a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
1064a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
106531949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
106631949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
106731949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
106831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
106931949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
107031949217328bf2357ff044f0d18677fe588c790cNick Pelly
107131949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
107231949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
107331949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
10740e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1075391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly
1076391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        @Override
1077ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        public void dispatch(Tag tag) throws RemoteException {
1078391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            enforceAdminPerm(mContext);
1079ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            mNfcDispatcher.dispatchTag(tag);
1080391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        }
10810c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
10820c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        @Override
10830c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
10840c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            enforceAdminPerm(mContext);
10850c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
10860c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pInitiatorModes(initiatorModes);
10870c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pTargetModes(targetModes);
10880c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.disableDiscovery();
10890c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.enableDiscovery();
10900c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        }
1091c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
1092c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        @Override
109331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public void setReaderMode(IBinder binder, IAppCallback callback, int flags, Bundle extras)
109431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                throws RemoteException {
1095c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            synchronized (NfcService.this) {
1096c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                if (flags != 0) {
1097c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    try {
109831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams = new ReaderModeParams();
109931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.callback = callback;
110031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.flags = flags;
110131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.presenceCheckDelay = extras != null ?
110231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                                (extras.getInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY,
110331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                                DEFAULT_PRESENCE_CHECK_DELAY)) : DEFAULT_PRESENCE_CHECK_DELAY;
1104c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        binder.linkToDeath(mReaderModeDeathRecipient, 0);
1105c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    } catch (RemoteException e) {
1106c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        Log.e(TAG, "Remote binder has already died.");
1107c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        return;
1108c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
1109c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                } else {
1110c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    try {
111131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams = null;
1112c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        binder.unlinkToDeath(mReaderModeDeathRecipient, 0);
1113c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    } catch (NoSuchElementException e) {
1114c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        Log.e(TAG, "Reader mode Binder was never registered.");
1115c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
1116c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                }
1117c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                applyRouting(false);
1118c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            }
1119c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        }
1120c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    }
1121c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
1122c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    final class ReaderModeDeathRecipient implements IBinder.DeathRecipient {
1123c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        @Override
1124c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        public void binderDied() {
1125c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            synchronized (NfcService.this) {
112631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                if (mReaderModeParams != null) {
112731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    mReaderModeParams = null;
1128c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    applyRouting(false);
1129c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                }
1130c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            }
1131c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        }
1132c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
11330e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
1134a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    final class CardEmulationService extends INfcCardEmulation.Stub {
1135a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
1136a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public boolean isDefaultServiceForCategory(int userId, ComponentName service,
1137a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                String category) throws RemoteException {
1138a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1139a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return false;
1140a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
114189c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
114289c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
114306645f1a5dc19e01f61895797f7b4c2204ae7b62Martijn Coenen            return mAidCache.isDefaultServiceForCategory(userId, category, service);
1144a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1145a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
1146a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
114789c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        public boolean isDefaultServiceForAid(int userId, ComponentName service, String aid)
114889c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen                throws RemoteException {
114989c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            if (!mIsHceCapable) {
115089c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen                return false;
115189c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            }
115289c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
115389c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
115478976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return mAidCache.isDefaultServiceForAid(userId, service, aid);
115589c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        }
115689c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen
115789c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        @Override
1158a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public boolean setDefaultServiceForCategory(int userId, ComponentName service,
1159a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                String category) throws RemoteException {
1160a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1161a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return false;
1162a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
116389c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
116489c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            enforceAdminPerm(mContext);
116578976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return mAidCache.setDefaultServiceForCategory(userId, service, category);
1166a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
116775f63db568f953e935e62cb3046d167b881979c8Martijn Coenen
116875f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        @Override
116975f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        public boolean setDefaultForNextTap(int userId, ComponentName service)
117075f63db568f953e935e62cb3046d167b881979c8Martijn Coenen                throws RemoteException {
117175f63db568f953e935e62cb3046d167b881979c8Martijn Coenen            if (!mIsHceCapable) {
117275f63db568f953e935e62cb3046d167b881979c8Martijn Coenen                return false;
117375f63db568f953e935e62cb3046d167b881979c8Martijn Coenen            }
117489c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
117589c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            enforceAdminPerm(mContext);
117689c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            mHostEmulationManager.setDefaultForNextTap(service);
117778976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return mAidCache.setDefaultForNextTap(userId, service);
117875f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        }
117975f63db568f953e935e62cb3046d167b881979c8Martijn Coenen
1180a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
1181a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public List<ApduServiceInfo> getServices(int userId, String category)
1182a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                throws RemoteException {
1183a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1184a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return null;
1185a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
118689c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
118789c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            enforceAdminPerm(mContext);
118878976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return mAidCache.getServicesForCategory(userId, category);
1189a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1190a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    };
1191a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
11924a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
1193fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1194f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
1195d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1196bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1197f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1198f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
119931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1200f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1201f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1202f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1203f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1204f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1205f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1206b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
1207b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
120821545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
1209b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
1210f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1211f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
1212fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1213f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
1214f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1215f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1216fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1217ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
1218d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1219bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1220f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1221f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
122231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1223f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1224f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1225f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1226f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1227f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1228b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1229b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
1230f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1231ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
1232cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            if (!tag.isPresent()) {
1233cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1234cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            }
1235cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen
1236ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
1237ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
1238ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
1239ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
1240ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
1241ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
1242ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1243ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
1244f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1245f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1246fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1247aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
1248aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1249aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1250f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1251aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1252aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
125331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1254aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
1255aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1256aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1257aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
1258f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1259aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
1260aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
1261aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
1262aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
1263aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
1264aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
1265aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1266aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
1267aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
1268aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1269aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
1270b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
1271d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1272bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1273f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
127431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1275f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1276f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1277f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1278f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1279f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1280f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1281b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
1282f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1283f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1284f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1285f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1286fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1287b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
1288f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1289b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1290b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
129131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1292b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1293b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1294b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1295b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
1296f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1297b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1298b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1299b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1300b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1301ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
1302b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1303b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1304fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1305f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
1306182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1307182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen
1308f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1309f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1310f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
131131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
13122c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1313f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1314f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1315f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1316f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
13173ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
13182c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
13192c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1320f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
132170bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
1322f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1323f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1324fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13259d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
132697c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
1327d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1328bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1329f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1330f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
1331f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1332f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
133331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1334f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1335f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1336f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1337f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1338f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1339f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1340bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
1341bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1342bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1343bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
13449d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
13459d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
1346bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
1347bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
1348bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
1349bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
1350bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
1351bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
1352bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
1353bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
1354bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
1355f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1356f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1357f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1358f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1359fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13603fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1361d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1362bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1363f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1364f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1365f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
136631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1367f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1368f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1369f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1370f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1371f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1372f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1373f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
1374f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
1375f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1376f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
1377f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1378f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
1379f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
1380f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
1381f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
1382f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1383f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1384f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1385f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1386f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1387f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1388fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13893fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1390d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1391bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1392f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1393f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1394f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
139531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1396f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1397f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1398f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1399f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1400f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1401f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1402f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1403f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1404f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1405791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1406791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen
1407f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1408f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1409f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1410f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1411f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1412f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1413f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1414f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1415fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
14163fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
14173fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1418f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1419f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1420fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
14213fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
142203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
142303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1424f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
142503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
142603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
142731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
142803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
142903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
143003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
143103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1432f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
143303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
143403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
143503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
143603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1437f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
143803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1439f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
144003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
144103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1442f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1443f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
14440aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
14450aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
14460aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
14470aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1448f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
14490aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
14500aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
145131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
14520aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
14530aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
14540aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
14550aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1456f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
14570aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
14580aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
14590aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
14600aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
14610aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
14620aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1463f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
14640aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
14650aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
14660aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
14670aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
14681b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
14693fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
14703fb14d0868594c78a777e805545209636814e223Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
14713fb14d0868594c78a777e805545209636814e223Martijn Coenen
1472f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
14733fb14d0868594c78a777e805545209636814e223Martijn Coenen
14743fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
147531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
14763fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
14773fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
14783fb14d0868594c78a777e805545209636814e223Martijn Coenen
14793fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1480f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
14813fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
14823fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
14833fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
14843fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
14853fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
14863fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
14873fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
14883fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
14893fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
14903fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
14913fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1492391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                tag.findAndReadNdef();
14933fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
14943fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
14954a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
14963fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
14973fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
14983fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
14993fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
15003fb14d0868594c78a777e805545209636814e223Martijn Coenen
15011b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1502fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
15031b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1504f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1505fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1506fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1507fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1508fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1509fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1510dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1511dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1512dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1513358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
1514358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1515358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1516358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1517358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1518358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1519358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1520dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
1521dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1522dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1523f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
15241b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1525bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1526bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1527bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1528bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1529bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1530bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1531bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1532bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1533bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1534bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1535ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen
1536ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        @Override
1537ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1538ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen            return mDeviceHost.getExtendedLengthApdusSupported();
1539ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        }
1540c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
1541f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
154292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly    void _nfcEeClose(int callingPid, IBinder binder) throws IOException {
1543dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // Blocks until a pending open() or transceive() times out.
1544dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        //TODO: This is incorrect behavior - the close should interrupt pending
1545dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // operations. However this is not supported by current hardware.
1546dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
15470571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly        synchronized (NfcService.this) {
15484ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            if (!isNfcEnabledOrShuttingDown()) {
1549dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC adapter is disabled");
1550dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1551dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (mOpenEe == null) {
1552dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC EE closed");
1553dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
155492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (callingPid != -1 && callingPid != mOpenEe.pid) {
1555dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new SecurityException("Wrong PID");
1556dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
155792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (mOpenEe.binder != binder) {
155892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                throw new SecurityException("Wrong binder handle");
155992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            }
1560dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
156192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            binder.unlinkToDeath(mOpenEe, 0);
1562f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
1563525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            doDisconnect(mOpenEe.handle);
1564dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mOpenEe = null;
1565dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1566fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1567dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        }
1568dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    }
1569dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
15704a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
157149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeNoException() {
157249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
157349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", 0);
157449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
157549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1576c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1577c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private Bundle writeEeException(int exceptionType, String message) {
157849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
1579c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putInt("e", exceptionType);
1580c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putString("m", message);
158149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
158249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
15830bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1584bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1585c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle open(String pkg, IBinder b) throws RemoteException {
1586c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1587bd555ee64250126b60b24814120a2049943920caNick Pelly
158849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
1589c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            int handle = _open(b);
1590c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            if (handle < 0) {
1591c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(handle, "NFCEE open exception.");
1592c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            } else {
159349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
15940bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
159549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
159649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
15970bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1598c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        /**
1599c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * Opens a connection to the secure element.
1600c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *
1601c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * @return A handle with a value >= 0 in case of success, or a
1602c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *         negative value in case of failure.
1603c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         */
1604c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private int _open(IBinder b) {
160549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
160631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
1607c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_NFC_DISABLED;
160849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16097a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                if (mInProvisionMode) {
16107a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // Deny access to the NFCEE as long as the device is being setup
16117a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    return EE_ERROR_IO;
16127a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                }
16137a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                if (mDeviceHost.enablePN544Quirks() && mP2pLinkManager.isLlcpActive()) {
16147a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // Don't allow PN544-based devices to open the SE while the LLCP
16157a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // link is still up or in a debounce state. This avoids race
16167a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // conditions in the NXP stack around P2P/SMX switching.
16177a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    return EE_ERROR_EXT_FIELD;
16187a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                }
161949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe != null) {
1620c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_ALREADY_OPEN;
162149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16220bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1623476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                boolean restorePolling = false;
1624476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                if (mDeviceHost.enablePN544Quirks() && mNfcPollingEnabled) {
1625476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // Disable polling for tags/P2P when connecting to the SMX
1626476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // on PN544-based devices. Whenever nfceeClose is called,
1627476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // the polling configuration will be restored.
1628476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    mDeviceHost.disableDiscovery();
1629476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    mNfcPollingEnabled = false;
1630476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    restorePolling = true;
1631476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                }
1632476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen
1633525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int handle = doOpenSecureElementConnection();
1634c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                if (handle < 0) {
1635476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen
1636476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    if (restorePolling) {
1637476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                        mDeviceHost.enableDiscovery();
1638476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                        mNfcPollingEnabled = true;
1639476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    }
1640c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return handle;
164149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
1642525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000);
1643ba6401757f8017faeb77423f2d08fd51be1d1051Nick Pelly
164492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
164549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                try {
164649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    b.linkToDeath(mOpenEe, 0);
164749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                } catch (RemoteException e) {
164849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    mOpenEe.binderDied();
164949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
165084e1e0adc2516afd35ebab029a52e764e0490559Jason parks
165184e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // Add the calling package to the list of packages that have accessed
165284e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // the secure element.
1653525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) {
165484e1e0adc2516afd35ebab029a52e764e0490559Jason parks                    mSePackages.add(packageName);
165584e1e0adc2516afd35ebab029a52e764e0490559Jason parks                }
1656c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1657c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                return handle;
165849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly           }
16590bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
16600bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1661bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
166292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public Bundle close(String pkg, IBinder binder) throws RemoteException {
1663c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1664c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
166549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
166649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
166792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                _nfcEeClose(getCallingPid(), binder);
166849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
166949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1670c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
16710bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
167249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
167349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
16740bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1675bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1676c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle transceive(String pkg, byte[] in) throws RemoteException {
1677c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1678bd555ee64250126b60b24814120a2049943920caNick Pelly
167949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
168049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            byte[] out;
168149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
168249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                out = _transceive(in);
168349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
168449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result.putByteArray("out", out);
168549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1686c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
16870bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
168849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
168949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
16900bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1691c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly        private byte[] _transceive(byte[] data) throws IOException {
169249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
169331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
169449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC is not enabled");
169549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16960571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly                if (mOpenEe == null) {
169749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE is not open");
169849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
169949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (getCallingPid() != mOpenEe.pid) {
170049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new SecurityException("Wrong PID");
170149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
17020bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
17030bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1704525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceive(mOpenEe.handle, data);
17050bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
17060bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1707bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1708c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public int getCardEmulationRoute(String pkg) throws RemoteException {
1709c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
171049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mEeRoutingState;
17110bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
17120bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1713bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1714c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
1715c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
171649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            mEeRoutingState = route;
1717525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            ApplyRoutingTask applyRoutingTask = new ApplyRoutingTask();
1718525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            applyRoutingTask.execute();
1719525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
1720525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Block until route is set
1721525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                applyRoutingTask.get();
1722525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (ExecutionException e) {
1723525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1724525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (InterruptedException e) {
1725525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1726525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
17270bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
1728bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
1729bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1730c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void authenticate(String pkg, byte[] token) throws RemoteException {
1731c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1732bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1733525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1734525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
1735525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public String getDriverName(String pkg) throws RemoteException {
1736525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            NfcService.this.enforceNfceeAdminPerm(pkg);
1737525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mDeviceHost.getName();
1738525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1739c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
17400bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
174149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** resources kept while secure element is open */
174249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private class OpenSecureElement implements IBinder.DeathRecipient {
174349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int pid;  // pid that opened SE
174492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // binder handle used for DeathReceipient. Must keep
174592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // a reference to this, otherwise it can get GC'd and
174692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // the binder stub code might create a different BinderProxy
174792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // for the same remote IBinder, causing mismatched
174892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // link()/unlink()
174992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public IBinder binder;
175049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int handle; // low-level handle
175192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public OpenSecureElement(int pid, int handle, IBinder binder) {
175249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.pid = pid;
175349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.handle = handle;
175492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            this.binder = binder;
175549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1756bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
175749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void binderDied() {
175849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized (NfcService.this) {
175992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                Log.i(TAG, "Tracked app " + pid + " died");
176049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                pid = -1;
17610bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas                try {
176292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    _nfcEeClose(-1, binder);
1763dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                } catch (IOException e) { /* already closed */ }
17640bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
17650bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
176692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        @Override
176792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public String toString() {
176892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            return new StringBuilder('@').append(Integer.toHexString(hashCode())).append("[pid=")
176992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    .append(pid).append(" handle=").append(handle).append("]").toString();
177092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        }
17710bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    }
17720bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
17739a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    boolean isNfcEnabledOrShuttingDown() {
17749a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        synchronized (this) {
17759a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
17769a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        }
17779a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    }
17789a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen
177931949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
178031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
178131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1782e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1783aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1784aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
178531949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
1786a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        final Object mCancelWaiter = new Object();
1787525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        final int mTimeout;
1788a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        boolean mCanceled = false;
1789525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1790525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public WatchDogThread(String threadName, int timeout) {
1791525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            super(threadName);
1792525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mTimeout = timeout;
1793525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1794525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
17952edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
17962edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
1797a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            try {
1798a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                synchronized (mCancelWaiter) {
1799a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    mCancelWaiter.wait(mTimeout);
1800a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    if (mCanceled) {
1801a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                        return;
1802a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    }
18032edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
1804a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            } catch (InterruptedException e) {
1805a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                // Should not happen; fall-through to abort.
1806a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                Log.w(TAG, "Watchdog thread interruped.");
1807a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                interrupt();
18082edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
1809a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            Log.e(TAG, "Watchdog triggered, aborting.");
1810a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            mDeviceHost.doAbort();
18112edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
1812a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project
18132edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
1814a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            synchronized (mCancelWaiter) {
1815a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCanceled = true;
1816a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCancelWaiter.notify();
1817a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            }
18182edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
18192edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
18202edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
18219f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    static byte[] hexStringToBytes(String s) {
18229f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (s == null || s.length() == 0) return null;
18239f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        int len = s.length();
18249f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (len % 2 != 0) {
18259f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            s = '0' + s;
18269f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            len++;
18279f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
18289f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        byte[] data = new byte[len / 2];
18299f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        for (int i = 0; i < len; i += 2) {
18309f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
18319f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                                 + Character.digit(s.charAt(i+1), 16));
18329f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
18339f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        return data;
18349f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
18359f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1836fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /**
1837fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1838fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     */
1839fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    void applyRouting(boolean force) {
1840e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
18419a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            if (!isNfcEnabledOrShuttingDown() || mOpenEe != null) {
1842fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                // PN544 cannot be reconfigured while EE is open
1843e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1844e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1845525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
18467d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            if (mInProvisionMode) {
18477d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
18487d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
18497d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                if (!mInProvisionMode) {
18507d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Notify dispatcher it's fine to dispatch to any package now
18517d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // and allow handover transfers.
18527d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mNfcDispatcher.disableProvisioningMode();
18537d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mHandoverManager.setEnabled(true);
18547d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                }
18557d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            }
1856f439271150e4548f116919e0254d57655421581cMartijn Coenen            try {
1857f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.start();
1858f439271150e4548f116919e0254d57655421581cMartijn Coenen
1859525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) {
1860f439271150e4548f116919e0254d57655421581cMartijn Coenen                    /* TODO undo this after the LLCP stack is fixed.
1861f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * Use a different sequence when turning the screen off to
1862f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * workaround race conditions in pn544 libnfc. The race occurs
1863f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * when we change routing while there is a P2P target connect.
1864f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * The async LLCP callback will crash since the routing code
1865f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * is overwriting globals it relies on.
1866f439271150e4548f116919e0254d57655421581cMartijn Coenen                     */
1867f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (POLLING_MODE > SCREEN_STATE_OFF) {
1868f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfcPollingEnabled) {
1869f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-C OFF, disconnect");
1870f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfcPollingEnabled = false;
1871f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.disableDiscovery();
1872f439271150e4548f116919e0254d57655421581cMartijn Coenen                            maybeDisconnectTarget();
1873f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1874f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1875f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1876f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfceeRouteEnabled) {
1877f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-EE OFF");
1878f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfceeRouteEnabled = false;
1879f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.doDeselectSecureElement();
1880f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1881fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1882f439271150e4548f116919e0254d57655421581cMartijn Coenen                    return;
1883fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1884f439271150e4548f116919e0254d57655421581cMartijn Coenen
18850a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen                if (mIsHceCapable && mScreenState >= SCREEN_STATE_ON_LOCKED &&
1886d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mAidRoutingManager.aidsRoutedToHost()) {
1887d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    if (!mHostRouteEnabled || force) {
1888d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mHostRouteEnabled = true;
1889d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mDeviceHost.enableRoutingToHost();
1890d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    }
1891d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                } else {
1892d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    if (force || mHostRouteEnabled) {
1893d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mHostRouteEnabled = false;
1894d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mDeviceHost.disableRoutingToHost();
18959f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                    }
18969f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                }
18979f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1898f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-EE routing
1899f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
1900f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1901f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfceeRouteEnabled) {
1902f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-EE ON");
1903f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfceeRouteEnabled = true;
1904f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.doSelectSecureElement();
1905f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1906f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1907f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force ||  mNfceeRouteEnabled) {
1908fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        Log.d(TAG, "NFC-EE OFF");
1909fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mNfceeRouteEnabled = false;
1910fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mDeviceHost.doDeselectSecureElement();
1911fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1912fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1913fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1914f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-C polling
1915f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= POLLING_MODE) {
1916f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfcPollingEnabled) {
1917f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C ON");
1918f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = true;
1919f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.enableDiscovery();
1920f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
192131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (mReaderModeParams != null && !mReaderModeEnabled) {
1922c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        mReaderModeEnabled = true;
192331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mDeviceHost.enableReaderMode(mReaderModeParams.flags);
1924c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
192531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (mReaderModeParams == null && mReaderModeEnabled) {
1926c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        mReaderModeEnabled = false;
1927c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        mDeviceHost.disableReaderMode();
1928c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
19297d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                } else if (mInProvisionMode && mScreenState >= SCREEN_STATE_ON_LOCKED) {
19307d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Special case for setup provisioning
19317d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    if (!mNfcPollingEnabled) {
19327d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Log.d(TAG, "NFC-C ON");
19337d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mNfcPollingEnabled = true;
19347d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mDeviceHost.enableDiscovery();
19357d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    }
1936f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1937f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || mNfcPollingEnabled) {
1938f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C OFF");
1939c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        if (mReaderModeEnabled) {
1940c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                            mReaderModeEnabled = false;
1941c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                            mDeviceHost.disableReaderMode();
1942c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        }
1943f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = false;
1944f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.disableDiscovery();
1945f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1946fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1947f439271150e4548f116919e0254d57655421581cMartijn Coenen            } finally {
1948f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.cancel();
1949221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
195065945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
195165945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
195265945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
19532436ffe91853535fad87b7a8e03d8883bae20f20Arnaud Ferir    /** Disconnect any target if present */
195431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
19559a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        if (!isNfcEnabledOrShuttingDown()) {
1956a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1957a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
195831949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
195931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
196031949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
196131949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
196231949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
196331949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
196431949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
196531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
196631949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
196731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
196831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
196931949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
197031949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
197131949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
197231949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
197331949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
197431949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
197531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
197631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
197731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
197831949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
197931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
198031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1981bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1982bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1983bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1984bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1985bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
198631949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
198731949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
198831949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
198931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
199031949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
19912f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
199231949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
19930e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1994f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1995f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
199631949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
199731949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
199831949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1999f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
2000b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
2001b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
200231949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
200331949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
200431949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
200531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
2006f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
2007f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2008d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
20094a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
2010c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            throws LlcpException {
20114a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
2012d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
2013d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
2014d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
20153b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
2016e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen            throws LlcpException {
20173b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
2018e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    }
2019e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen
2020e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    /** For use by code in this process */
20214a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
2022c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            int linearBufferLength) throws LlcpException {
20234a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
2024d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
2025d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
202657d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
2027b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
202857d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
202957d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
2030d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void routeAids(String aid, int route) {
2031d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        Message msg = mHandler.obtainMessage();
2032d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.what = MSG_ROUTE_AID;
2033d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.arg1 = route;
2034d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.obj = aid;
2035d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendMessage(msg);
2036d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
2037d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
2038d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void unrouteAids(String aid) {
2039d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        sendMessage(MSG_UNROUTE_AID, aid);
2040d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
2041d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
2042d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void commitRouting() {
2043d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
2044d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
2045d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
20469f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen	public boolean sendData(byte[] data) {
20479f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen	    return mDeviceHost.sendRawFrame(data);
20489f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
20499f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
2050b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
2051b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
2052b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
2053b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
2054b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
2055b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
2056b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
20573fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
2058b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
2059b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
206031949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
2061d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_ROUTE_AID: {
2062d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    int route = msg.arg1;
2063d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
2064d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.routeAid(hexStringToBytes(aid), route);
2065d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    // Restart polling config
2066d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
2067d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
2068d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_UNROUTE_AID: {
2069d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
2070d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.unrouteAid(hexStringToBytes(aid));
2071d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
2072d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
2073d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_COMMIT_ROUTING: {
2074d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    applyRouting(true);
2075d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
2076d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
207731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
207831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
207931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
208031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
208131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
208231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
208331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
208431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
208531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new int[] { TagTechnology.NDEF },
208631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new Bundle[] { extras });
208731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
208831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
2089ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                    boolean delivered = mNfcDispatcher.dispatchTag(tag);
209031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (delivered) {
2091d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
209277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    } else {
2093d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
209431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
209531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
209631949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
209757d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
209831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
209931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
210031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
210131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    ReaderModeParams readerParams = null;
210231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    int presenceCheckDelay = DEFAULT_PRESENCE_CHECK_DELAY;
2103c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    synchronized (NfcService.this) {
210431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        readerParams = mReaderModeParams;
2105c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
210631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (readerParams != null) {
210731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        presenceCheckDelay = readerParams.presenceCheckDelay;
210831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
210931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
211031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            tag.startPresenceChecking(presenceCheckDelay);
211131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            dispatchTagEndpoint(tag, readerParams);
211231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            break;
211331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        }
211431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    }
211531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (readerParams == null ||
211631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            (readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
211731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        playSound(SOUND_START);
2118c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
211989baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
212089baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // When these tags start containing NDEF, they will require
212189baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // the stack to deal with them in a different way, since
212289baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // they are activated only really shortly.
212389baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // For now, don't consider NDEF on these.
212489baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
212531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        tag.startPresenceChecking(presenceCheckDelay);
212631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        dispatchTagEndpoint(tag, readerParams);
212789baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        break;
212889baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    }
2129391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    NdefMessage ndefMsg = tag.findAndReadNdef();
2130c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
2131391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    if (ndefMsg != null) {
213231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        tag.startPresenceChecking(presenceCheckDelay);
213331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        dispatchTagEndpoint(tag, readerParams);
213431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
213531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
213631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            tag.startPresenceChecking(presenceCheckDelay);
213731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            dispatchTagEndpoint(tag, readerParams);
213831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
213931949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
2140d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
214131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
214231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
214331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
214431949217328bf2357ff044f0d18677fe588c790cNick Pelly
214531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_CARD_EMULATION:
214631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Emulation message");
2147f9366de7b3ad1ce90859d4194dacf13c0066926bMartijn Coenen                    /* Tell the host-emu manager an AID has been selected on
2148f9366de7b3ad1ce90859d4194dacf13c0066926bMartijn Coenen                     * a secure element.
2149f9366de7b3ad1ce90859d4194dacf13c0066926bMartijn Coenen                     */
2150f9366de7b3ad1ce90859d4194dacf13c0066926bMartijn Coenen                    if (mHostEmulationManager != null) {
2151f9366de7b3ad1ce90859d4194dacf13c0066926bMartijn Coenen                        mHostEmulationManager.notifyOffHostAidSelected();
2152f9366de7b3ad1ce90859d4194dacf13c0066926bMartijn Coenen                    }
215331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] aid = (byte[]) msg.obj;
215431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
215531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent aidIntent = new Intent();
215631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.setAction(ACTION_AID_SELECTED);
215731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.putExtra(EXTRA_AID, aid);
215831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
215914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(aidIntent);
216031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
216131949217328bf2357ff044f0d18677fe588c790cNick Pelly
216231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_EMV_CARD_REMOVAL:
216331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Removal message");
216431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
216531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent cardRemovalIntent = new Intent();
216631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
216731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
216814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(cardRemovalIntent);
216931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
217031949217328bf2357ff044f0d18677fe588c790cNick Pelly
217131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_APDU_RECEIVED:
217231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "APDU Received message");
217331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] apduBytes = (byte[]) msg.obj;
217431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
217531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent apduReceivedIntent = new Intent();
217631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
217731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (apduBytes != null && apduBytes.length > 0) {
217831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
217931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
218031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
218114a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(apduReceivedIntent);
218231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
218331949217328bf2357ff044f0d18677fe588c790cNick Pelly
218431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_MIFARE_ACCESS:
218531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "MIFARE access message");
218631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
218731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] mifareCmd = (byte[]) msg.obj;
218831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent mifareAccessIntent = new Intent();
218931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
219031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mifareCmd != null && mifareCmd.length > 1) {
219131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        int mifareBlock = mifareCmd[1] & 0xff;
219231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
219331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
219431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
219531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
219614a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(mifareAccessIntent);
219731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
2198c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
219931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
220096e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
220196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent actIntent = new Intent(ACTION_LLCP_UP);
220296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(actIntent);
220396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
220431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
220531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
220631949217328bf2357ff044f0d18677fe588c790cNick Pelly
220731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
220896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
220996e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
221096e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(deactIntent);
221196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
221231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
221331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
221431949217328bf2357ff044f0d18677fe588c790cNick Pelly
221531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
221631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
221731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
221831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
221931949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
222031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
222131949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
222231949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
222331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
222431949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
222531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
222631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
222731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
222831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
222931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
223031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
223131949217328bf2357ff044f0d18677fe588c790cNick Pelly
223277d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
223331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
223457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                case MSG_LLCP_LINK_FIRST_PACKET:
223557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    mP2pLinkManager.onLlcpFirstPacketReceived();
223657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    break;
223731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_TARGET_DESELECTED:
223831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Broadcast Intent Target Deselected */
223931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Target Deselected");
224031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent intent = new Intent();
224131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
224231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting Intent");
224331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
224431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
224531949217328bf2357ff044f0d18677fe588c790cNick Pelly
224631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_ACTIVATED: {
224731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
224831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOnIntent = new Intent();
224931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
225014a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOnIntent);
225131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
225231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
225331949217328bf2357ff044f0d18677fe588c790cNick Pelly
225431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_DEACTIVATED: {
225531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
225631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOffIntent = new Intent();
225731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
225814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOffIntent);
225931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
226031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
226131949217328bf2357ff044f0d18677fe588c790cNick Pelly
2262525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_ACTIVATED: {
2263525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE ACTIVATED");
2264525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeActivated = new Intent();
2265525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeActivated.setAction(ACTION_SE_LISTEN_ACTIVATED);
2266525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeActivated);
2267525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
2268525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2269525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
2270525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_DEACTIVATED: {
2271525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE DEACTIVATED");
2272525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeDeactivated = new Intent();
2273525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeDeactivated.setAction(ACTION_SE_LISTEN_DEACTIVATED);
2274525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeDeactivated);
2275525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
2276525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
227731949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
227831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
227931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
228031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
2281b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
2282d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
228314a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        private void sendSeBroadcast(Intent intent) {
228414a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
2285c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            // Resume app switches so the receivers can start activites without delay
2286c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfcDispatcher.resumeAppSwitches();
2287c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
2288e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            synchronized(this) {
2289e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                for (PackageInfo pkg : mInstalledPackages) {
2290e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (pkg != null && pkg.applicationInfo != null) {
2291e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
2292e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            intent.setPackage(pkg.packageName);
2293e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            mContext.sendBroadcast(intent);
2294e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        }
2295c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
2296c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
2297c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
229814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        }
229914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton
2300d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
2301d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
2302d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2303d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
2304d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
2305d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
2306d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
2307d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
2308d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
2309d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
2310d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
231131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
231231949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
231331949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
2314d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
231577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                            mP2pLinkManager.onLlcpActivated();
2316d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
2317d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
2318d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
2319d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
2320d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
2321d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
2322d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
2323d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
2324d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
2325d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2326d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2327d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
2328d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
2329d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
2330d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
2331d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
2332d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2333d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
2334d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
2335d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
2336d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
2337d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
2338d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
2339d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
234031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
234131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
234231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
2343d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
234477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
2345d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
2346d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2347d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2348d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
2349d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2350d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
2351d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2352d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
2353d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
2354d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
235531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, ReaderModeParams readerParams) {
2356f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
2357f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
2358f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
23593dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen            if (readerParams != null) {
236031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                try {
236131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if ((readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
236231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        playSound(SOUND_END);
236331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    }
23643dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    if (readerParams.callback != null) {
23653dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        readerParams.callback.onTagDiscovered(tag);
23663dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        return;
23673dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    } else {
23683dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        // Follow normal dispatch below
23693dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    }
237031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                } catch (RemoteException e) {
237131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    Log.e(TAG, "Reader mode remote has died, falling back.");
23723dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    // Intentional fall-through
23733dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                } catch (Exception e) {
23743dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    // Catch any other exception
23753dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    Log.e(TAG, "App exception, not dispatching.");
23763dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    return;
237731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                }
237831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen            }
2379ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            if (!mNfcDispatcher.dispatchTag(tag)) {
2380f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
2381d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
2382d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else {
2383d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
23843fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
23853fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
2386b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
2387b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
2388b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
238949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
2390fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
2391fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
2392fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        protected Void doInBackground(Integer... params) {
2393fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            synchronized (NfcService.this) {
2394fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (params == null || params.length != 1) {
2395fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    // force apply current routing
2396fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    applyRouting(true);
2397fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    return null;
2398161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2399fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                mScreenState = params[0].intValue();
2400fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
2401525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
2402525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2403525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    applyRouting(false);
2404525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
2405525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
2406161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2407fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return null;
24087c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
24097c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
24107c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
24117c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
2412525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
24130e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        @Override
24140e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public void onReceive(Context context, Intent intent) {
241531949217328bf2357ff044f0d18677fe588c790cNick Pelly            String action = intent.getAction();
2416525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
2417e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
2418e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
2419e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
2420e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                updatePackageCache();
2421e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2422e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
2423e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    // Clear the NFCEE access cache in case a UID gets recycled
2424e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    mNfceeAccessControl.invalidateCache();
2425e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2426e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
2427e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (dataRemoved) {
2428e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        Uri data = intent.getData();
2429e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (data == null) return;
2430e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        String packageName = data.getSchemeSpecificPart();
24317a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton
2432e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        synchronized (NfcService.this) {
2433e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            if (mSePackages.contains(packageName)) {
2434e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                new EnableDisableTask().execute(TASK_EE_WIPE);
2435e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                mSePackages.remove(packageName);
2436e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            }
24377a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                        }
2438bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                    }
2439bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
2440525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
2441525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                EnableDisableTask eeWipeTask = new EnableDisableTask();
2442525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                eeWipeTask.execute(TASK_EE_WIPE);
2443525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2444525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    eeWipeTask.get();  // blocks until EE wipe is complete
2445525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (ExecutionException e) {
2446525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2447525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (InterruptedException e) {
2448525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2449525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2450525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
2451525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
2452525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    };
2453525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
2454525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2455525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
2456525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2457525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            String action = intent.getAction();
2458525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(
2459525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
2460525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2461525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute();
2462525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(Intent.ACTION_SCREEN_ON)
2463525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_SCREEN_OFF)
2464525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_USER_PRESENT)) {
2465525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2466525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int screenState = SCREEN_STATE_OFF;
2467525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
2468525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_OFF;
2469525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
2470525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = mKeyguard.isKeyguardLocked() ?
2471525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
2472525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
2473525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_ON_UNLOCKED;
2474525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2475525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
247631949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
247731949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
247831949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
247931949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
248031949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
248131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
248231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
248331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
248431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
248531949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
24861668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
24871668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
248831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
248931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
249031949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
249131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
249231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
24933859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
24943859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                mP2pLinkManager.onUserSwitched();
2495341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen                if (mIsHceCapable) {
249678976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen                    mAidCache.invalidateCache(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
24974358172f18871d58d5bc2050e4d9d0bf9bc2d5e5Martijn Coenen                }
2498f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
2499f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
2500f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
250131949217328bf2357ff044f0d18677fe588c790cNick Pelly
250231949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** Returns true if airplane mode is currently on */
250331949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
25047d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        return Settings.System.getInt(mContentResolver,
25057d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
250631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
250731949217328bf2357ff044f0d18677fe588c790cNick Pelly
2508fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** for debugging only - no i18n */
250931949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
251031949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
251131949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
251231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
251331949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
251431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
251531949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
251631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
251731949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
251831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
251931949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
252031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
252131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
252231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
252331949217328bf2357ff044f0d18677fe588c790cNick Pelly
2524fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** For debugging only - no i18n */
2525fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static String screenStateToString(int screenState) {
2526fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        switch (screenState) {
2527fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_OFF:
2528fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "OFF";
2529fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_LOCKED:
2530fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_LOCKED";
2531fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_UNLOCKED:
2532fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_UNLOCKED";
2533fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            default:
2534fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "UNKNOWN";
2535fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
2536fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
2537fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
253831949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
253950effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
254050effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
254150effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
254250effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
254350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
254450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
254550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
254650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
254731949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
254831949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
25490b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
2550fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mScreenState=" + screenStateToString(mScreenState));
2551fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfcPollingEnabled=" + mNfcPollingEnabled);
2552fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfceeRouteEnabled=" + mNfceeRouteEnabled);
255331949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
255431949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
255592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            pw.println("mOpenEe=" + mOpenEe);
255677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
2557341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen            if (mIsHceCapable) {
2558341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen                mAidCache.dump(fd, pw, args);
2559341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen            }
2560c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfceeAccessControl.dump(fd, pw, args);
2561391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            mNfcDispatcher.dump(fd, pw, args);
256256f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
2563c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
256431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
256531949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
256674180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
2567