NfcService.java revision 31f39aee25964dad1038b7a9cc335d5a386113c8
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
322f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pellyimport android.app.Application;
33275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parksimport android.app.KeyguardManager;
3405973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamiltonimport android.app.PendingIntent;
3513d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.BroadcastReceiver;
36a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenenimport android.content.ComponentName;
3731949217328bf2357ff044f0d18677fe588c790cNick Pellyimport android.content.ContentResolver;
3813d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Context;
3913d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Intent;
4013d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.IntentFilter;
410e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.content.SharedPreferences;
42483f3065021c878468ab0921140aa9a2c89b4246Martijn Coenenimport android.content.pm.PackageInfo;
4393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamiltonimport android.content.pm.PackageManager;
447d8987f233985a5ff29226890e11012275d325f5Martijn Coenenimport android.content.res.Resources.NotFoundException;
45d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.AudioManager;
46d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.SoundPool;
473fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamiltonimport android.net.Uri;
48f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.ErrorCodes;
49f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.FormatException;
5031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenenimport android.nfc.IAppCallback;
510e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.INfcAdapter;
5249d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.nfc.INfcAdapterExtras;
53a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenenimport android.nfc.INfcCardEmulation;
54f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.INfcTag;
55f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NdefMessage;
56f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NfcAdapter;
570e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.Tag;
5824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.nfc.TechListParcel;
599d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenenimport android.nfc.TransceiveResult;
60a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenenimport android.nfc.cardemulation.ApduServiceInfo;
61aca0d055a82da850c27f6872405602ad5f3fee7bJeff Hamiltonimport android.nfc.tech.Ndef;
6281c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport android.nfc.tech.TagTechnology;
637c034a7fe7d36b1ab039af2c44717812ea02657eNick Pellyimport android.os.AsyncTask;
6450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Rootimport android.os.Binder;
6596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenenimport android.os.Build;
66b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamiltonimport android.os.Bundle;
67b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Handler;
6849d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.os.IBinder;
69b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Message;
70533043d1003de2f6a20a29201100d94c3c7bc9caNick Pellyimport android.os.PowerManager;
714467dca5650a170af5020c10a8ccb25f86f1007fNick Pellyimport android.os.Process;
72f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.os.RemoteException;
7313d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.os.ServiceManager;
743e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenenimport android.os.SystemClock;
75525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.os.UserHandle;
76d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.provider.Settings;
77f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.util.Log;
7831949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.FileDescriptor;
7957d376f1ee1a3939977b95759525585abb9601fbJeff Hamiltonimport java.io.IOException;
8031949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.PrintWriter;
8131949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.Arrays;
823ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamiltonimport java.util.HashMap;
8384e1e0adc2516afd35ebab029a52e764e0490559Jason parksimport java.util.HashSet;
84c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamiltonimport java.util.List;
85c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenenimport java.util.NoSuchElementException;
8631949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.concurrent.ExecutionException;
873ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
88525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectpublic class NfcService implements DeviceHostListener {
89bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
90bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
91c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = false;
9276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
93fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
94d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
95fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
96c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** Regular NFC permission */
97bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM = android.Manifest.permission.NFC;
98bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM_ERROR = "NFC permission required";
99c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
100c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** NFC ADMIN permission - only for system apps */
101bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
102bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
103bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
10477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
105f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
106416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
107416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
108416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
109416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
110416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
111416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
1121668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
113a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen    static final boolean SE_BROADCASTS_WITH_HCE = true;
114a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
115b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
116b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_CARD_EMULATION = 1;
117b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_ACTIVATION = 2;
118b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
119b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_TARGET_DESELECTED = 4;
120b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    static final int MSG_MOCK_NDEF = 7;
121c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_ACTIVATED = 8;
122c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_DEACTIVATED = 9;
1232c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_APDU_RECEIVED = 10;
1242c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
1252c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_MIFARE_ACCESS = 12;
126525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_ACTIVATED = 13;
127525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_DEACTIVATED = 14;
12857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    static final int MSG_LLCP_LINK_FIRST_PACKET = 15;
129d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_ROUTE_AID = 16;
130d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_UNROUTE_AID = 17;
131d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_COMMIT_ROUTING = 18;
132b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
13331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
13431949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
13531949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
13631949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_EE_WIPE = 4;
13731949217328bf2357ff044f0d18677fe588c790cNick Pelly
138fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    // Screen state, used by mScreenState
139fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_UNKNOWN = 0;
140fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_OFF = 1;
141fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_LOCKED = 2;
142fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_UNLOCKED = 3;
143fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
14449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Copied from com.android.nfc_extras to avoid library dependency
14549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Must keep in sync with com.android.nfc_extras
14649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_OFF = 1;
14749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
1487efbf69a37134ccbd86a1f6b4121f16b4a80eaaeNick Pelly
149c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // Return values from NfcEe.open() - these are 1:1 mapped
150c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // to the thrown EE_EXCEPTION_ exceptions in nfc-extras.
151c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_IO = -1;
152c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_ALREADY_OPEN = -2;
153c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_INIT = -3;
154c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_LISTEN_MODE = -4;
155c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_EXT_FIELD = -5;
156c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_NFC_DISABLED = -6;
157c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
158fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** minimum screen state that enables NFC polling (discovery) */
159fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
160fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
161525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for NFC controller to initialize before watchdog
162525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off. This time is chosen large, because firmware download
163525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // may be a part of initialization.
164525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int INIT_WATCHDOG_MS = 90000;
165525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
166525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for routing to be applied before watchdog
167525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off
168525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int ROUTING_WATCHDOG_MS = 10000;
169525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1703e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Amount of time to wait before closing the NFCEE connection
1713e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // in a disable/shutdown scenario.
1723e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_OPERATIONS_MS = 5000;
1733e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Polling interval for waiting on NFCEE operations
1743e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_POLL_MS = 100;
1753e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
17631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    // Default delay used for presence checks
17731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    static final int DEFAULT_PRESENCE_CHECK_DELAY = 125;
17831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
179d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
180d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
181d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
182d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
183d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
18449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_ON_DETECTED =
18549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
18649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_OFF_DETECTED =
18749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
18849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_AID_SELECTED =
18949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.AID_SELECTED";
19049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
19149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
19296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_UP =
19396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_UP";
19496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
19596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_DOWN =
19696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_DOWN";
19796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
1982c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_APDU_RECEIVED =
1992c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.APDU_RECEIVED";
2002c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_APDU_BYTES =
2012c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.APDU_BYTES";
2022c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
2032c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_EMV_CARD_REMOVAL =
2042c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
2052c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
2062c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_MIFARE_ACCESS_DETECTED =
2072c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
2082c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_MIFARE_BLOCK =
2092c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.MIFARE_BLOCK";
2102c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
211525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_ACTIVATED =
212525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_ACTIVATED";
213525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_DEACTIVATED =
214525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_DEACTIVATED";
21549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
21649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
21749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
2180bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    private NativeNfcSecureElement mSecureElement;
21949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private OpenSecureElement mOpenEe;  // null when EE closed
220c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    private final ReaderModeDeathRecipient mReaderModeDeathRecipient =
221c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            new ReaderModeDeathRecipient();
22249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private int mEeRoutingState;  // contactless interface routing
2230bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
224d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    // fields below must be used only on the UI thread and therefore aren't synchronized
225d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    boolean mP2pStarted = false;
226d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
2272f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
228fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
229525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // mSePackages holds packages that accessed the SE, but only for the owner user,
230525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // as SE access is not granted for non-owner users.
231fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    HashSet<String> mSePackages = new HashSet<String>();
232fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int mScreenState;
2337d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
234fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mIsNdefPushEnabled;
235fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfceeRouteEnabled;  // current Device Host state of NFC-EE routing
236fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfcPollingEnabled;  // current Device Host state of NFC-C polling
2379f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    boolean mHostRouteEnabled;   // current Device Host state of host-based routing
238c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    boolean mReaderModeEnabled;  // current Device Host state of reader mode
23931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    ReaderModeParams mReaderModeParams;
24031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
241e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    List<PackageInfo> mInstalledPackages; // cached version of installed packages
24231949217328bf2357ff044f0d18677fe588c790cNick Pelly
24331949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
24431949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
24531949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
24631949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
2472f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
2482f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
24905973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
2504a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
2510e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
2520e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
253525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mRoutingWakeLock;
254525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mEeWakeLock;
255525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
256d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
257d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
258d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
259d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
26077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
2614a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
2624a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
2634a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterExtrasService mExtrasService;
264a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    CardEmulationService mCardEmulationService;
26531949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
26631949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
26796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    boolean mIsDebugBuild;
2680a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen    boolean mIsHceCapable;
269c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    NfceeAccessControl mNfceeAccessControl;
2702ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
27176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
272fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    private PowerManager mPowerManager;
273275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
2747d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private HandoverManager mHandoverManager;
2757d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private ContentResolver mContentResolver;
27678976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen    private RegisteredAidCache mAidCache;
2779f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    private HostEmulationManager mHostEmulationManager;
278d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    private AidRoutingManager mAidRoutingManager;
279d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
280d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    private static NfcService sService;
281d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
28293d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceAdminPerm(Context context) {
283c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
28493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
28593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
28689c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen    public static void validateUserId(int userId) {
28789c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        if (userId != UserHandle.getCallingUserId()) {
28889c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            throw new SecurityException("userId passed in it not the calling user.");
28989c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        }
29089c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen    }
29189c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen
292c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public void enforceNfceeAdminPerm(String pkg) {
293c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (pkg == null) {
294c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException("caller must pass a package name");
295c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
296c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
297c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (!mNfceeAccessControl.check(Binder.getCallingUid(), pkg)) {
298c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
299c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    " denies NFCEE access to " + pkg);
300c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
301525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
302525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            throw new SecurityException("only the owner is allowed to call SE APIs");
303525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
30493d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
30593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
306d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
307d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
308d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
309f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
3100e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
311f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
312f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
313f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
314f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
315f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
316f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
317f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
318d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
319f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationDeselected() {
320a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3210a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
3220a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
323f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
324f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
325f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
326f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
327f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
328d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
329f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationAidSelected(byte[] aid) {
330a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3310a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_CARD_EMULATION, aid);
3320a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
333f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
334f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
335f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
3369f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen     * Notifies transaction
3379f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen     */
3389f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3399f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationActivated() {
3400a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3410a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyHostEmulationActivated();
3420a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3439f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3449f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3459f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3469f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationData(byte[] data) {
3470a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3480a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyHostEmulationData(data);
3490a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3509f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3519f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3529f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3539f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationDeactivated() {
3540a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3550a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyNostEmulationDeactivated();
3560a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3579f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3589f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3599f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    /**
360f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
361f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
362f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
363f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
364f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
365f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
366f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
367f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
368f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
369f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
370d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
371f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
372f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
373f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
374f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
37557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    /**
37657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     * Notifies P2P Device detected, first packet received over LLCP link
37757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     */
37857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    @Override
37957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
38057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
38157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    }
38257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
383d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
384f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldActivated() {
385a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3860a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
3870a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
388f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
389f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
390d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
391f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldDeactivated() {
392a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3930a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
3940a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
395f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
396f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
397f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
398525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenActivated() {
399a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4000a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_LISTEN_ACTIVATED, null);
4010a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
402525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
403525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
404525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
405525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenDeactivated() {
406a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4070a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_LISTEN_DEACTIVATED, null);
4080a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
409525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
410525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
411525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
412525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
413442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeApduReceived(byte[] apdu) {
414a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4150a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
4160a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
417442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
418442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
419442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
420442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeEmvCardRemoval() {
421a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4220a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
4230a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
424442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
425442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
426442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
427442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeMifareAccess(byte[] block) {
428a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4290a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
4300a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
431442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
432442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
43331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    final class ReaderModeParams {
43431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public int flags;
43531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public IAppCallback callback;
43631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public int presenceCheckDelay;
43731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    }
43831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
439525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public NfcService(Application nfcApplication) {
4404a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
4414a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
442ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly        mExtrasService = new NfcAdapterExtrasService();
443a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        mCardEmulationService = new CardEmulationService();
4444a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton
4452f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
4462f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
447d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
448d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
449525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext = nfcApplication;
4507d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mContentResolver = mContext.getContentResolver();
451525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDeviceHost = new NativeNfcManager(mContext, this);
45274180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
4537d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager = new HandoverManager(mContext);
4547d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        boolean isNfcProvisioningEnabled = false;
4557d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        try {
4567d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
4577d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    R.bool.enable_nfc_provisioning);
4587d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } catch (NotFoundException e) {
4597d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
4607d8987f233985a5ff29226890e11012275d325f5Martijn Coenen
4617d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        if (isNfcProvisioningEnabled) {
4627d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
4637d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
4647d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } else {
4657d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = false;
4667d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
467525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
4687d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager.setEnabled(!mInProvisionMode);
4697d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
4707d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
471525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
47224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
47337058bf7b59def2f9a565ae5b16aae54e80e9e95Sunil Jogi        mSecureElement = new NativeNfcSecureElement(mContext);
474eab09ad7204fe1f0feaca33efccf75c1bb388708Robert Tsai        mEeRoutingState = ROUTE_OFF;
4750bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
476525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mNfceeAccessControl = new NfceeAccessControl(mContext);
477c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
478525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
4790e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
480f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
48131949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
4820b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
483f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
48496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
48596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
486525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
487525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
488525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mRoutingWakeLock = mPowerManager.newWakeLock(
489525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
490525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock = mPowerManager.newWakeLock(
491525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock");
492275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
493525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
494fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        mScreenState = checkScreenState();
495533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
496d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
497f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
498525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents for all users
499eead88c5e2bdd34eb33fdf2c76717f9edb9e0396Jeff Hamilton        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
50065945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_OFF);
50165945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
502275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
5033859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        filter.addAction(Intent.ACTION_USER_SWITCHED);
50431949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
505525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
5060e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
5070a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        PackageManager pm = mContext.getPackageManager();
5080a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HCE);
5090a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mIsHceCapable) {
5100a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mAidRoutingManager = new AidRoutingManager();
511451ba48faa87d78bfbec0597ff06af1747cf6acbMartijn Coenen            mAidCache = new RegisteredAidCache(mContext, mAidRoutingManager);
51278976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            mHostEmulationManager = new HostEmulationManager(mContext, mAidCache);
513a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        }
514a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
5150a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            IntentFilter ownerFilter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
5160a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
5170a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
5180a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
5190a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5200a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mContext.registerReceiver(mOwnerReceiver, ownerFilter);
5210a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5220a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter = new IntentFilter();
5230a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
5240a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
5250a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addDataScheme("package");
5260a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5270a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mContext.registerReceiver(mOwnerReceiver, ownerFilter);
5280a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5290a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            updatePackageCache();
5300a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
531e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
53231949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
53331949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
53431949217328bf2357ff044f0d18677fe588c790cNick Pelly
535d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
536d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
537d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
538d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
539525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
540525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
541525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
542d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
543d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
544d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
545d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
546d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
547d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
548d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
549d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
550d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
551d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
552d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
553d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
554d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
55531949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
5567d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
5577d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_RADIOS);
5587d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String toggleableRadios = Settings.System.getString(mContentResolver,
5597d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
56031949217328bf2357ff044f0d18677fe588c790cNick Pelly
56131949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
5627d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
56331949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
5647d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            toggleableRadios.contains(Settings.Global.RADIO_NFC);
56531949217328bf2357ff044f0d18677fe588c790cNick Pelly
56631949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
56731949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
56831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
56931949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
57031949217328bf2357ff044f0d18677fe588c790cNick Pelly
571e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    void updatePackageCache() {
572525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        PackageManager pm = mContext.getPackageManager();
573525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
574e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        synchronized (this) {
575e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            mInstalledPackages = packages;
576e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        }
577e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    }
578e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
579fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int checkScreenState() {
580fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        if (!mPowerManager.isScreenOn()) {
581fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_OFF;
582fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else if (mKeyguard.isKeyguardLocked()) {
583fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_LOCKED;
584fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else {
585fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_UNLOCKED;
586fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
587fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
588fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
589525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    int doOpenSecureElementConnection() {
590525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
591525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
592525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mSecureElement.doOpenSecureElementConnection();
593525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
594525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
595525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
596525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
597525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
598525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceive(int handle, byte[] cmd) {
599525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
600525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
601525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceiveNoLock(handle, cmd);
602525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
603525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
604525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
605525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
606525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
607525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceiveNoLock(int handle, byte[] cmd) {
608525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        return mSecureElement.doTransceive(handle, cmd);
609525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
610525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
611525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    void doDisconnect(int handle) {
612525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
613525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
614525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mSecureElement.doDisconnect(handle);
615525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
616525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
617525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
618525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
619525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
62031949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
62131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
62231949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
62331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
62431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
62531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
62631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
62731949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
62831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
62931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
63031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
63131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
63231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
63331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
63431949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
63531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
63631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
63731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
63831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
63931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
64031949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
64131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
64231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
64331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
64431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
64531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
64631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
64731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * process may temporarily enable the NFC adapter
64831949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
64931949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
65031949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
65131949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
65231949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
65331949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
65431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
65531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
65631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
65731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
65831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
65931949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
66031949217328bf2357ff044f0d18677fe588c790cNick Pelly
6614467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
6624467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
6634467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
6644467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
6654467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
6664467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
6674467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
6684467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
6694467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
67031949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
67131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
67231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
67331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
67431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
67531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
67631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
67731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
6780fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    Log.d(TAG,"checking on firmware download");
6791668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
68031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
6811668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
6820fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is on. Doing normal stuff");
68331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
6840fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
6850fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is off.  Checking firmware version");
6860fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
68731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
68831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
68931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
69031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
69131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
69231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        executeEeWipe();
69331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
69431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
69531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_EE_WIPE:
69631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    executeEeWipe();
69731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
69831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
699d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
700d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
701d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
70231949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
70331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
70431949217328bf2357ff044f0d18677fe588c790cNick Pelly
70531949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
70631949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
70731949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
70831949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
70931949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
71031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
71131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
71231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
71331949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
71431949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
71531949217328bf2357ff044f0d18677fe588c790cNick Pelly
716525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
717525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            watchDog.start();
718525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
719525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
720525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
721525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (!mDeviceHost.initialize()) {
722525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.w(TAG, "Error enabling NFC");
723525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        updateState(NfcAdapter.STATE_OFF);
724525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        return false;
725525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
726525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
727525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
728525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
729525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
730525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                watchDog.cancel();
73131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
73231949217328bf2357ff044f0d18677fe588c790cNick Pelly
7330a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            if (mIsHceCapable) {
7340a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen                // Generate the initial card emulation routing table
735f5cd84c3a7ffb66196ab3c0745569da937d7533bMartijn Coenen                mAidCache.onNfcEnabled();
7360a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            }
737d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
73831949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized(NfcService.this) {
73931949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
7400b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
74131949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
74231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
74331949217328bf2357ff044f0d18677fe588c790cNick Pelly
744d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
745d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
74631949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
7470c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
748fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
74931949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
75031949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
75131949217328bf2357ff044f0d18677fe588c790cNick Pelly
75231949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
75331949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
75431949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
75531949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
75631949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
75731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
75831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
75931949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
76031949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
76131949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
76231949217328bf2357ff044f0d18677fe588c790cNick Pelly
76331949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
76431949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
76531949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
76631949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
767525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
76831949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
76931949217328bf2357ff044f0d18677fe588c790cNick Pelly
770953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            if (mIsHceCapable) {
771f5cd84c3a7ffb66196ab3c0745569da937d7533bMartijn Coenen                mAidCache.onNfcDisabled();
772953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            }
773d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
77477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
77531949217328bf2357ff044f0d18677fe588c790cNick Pelly
7763e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            /* The NFC-EE may still be opened by another process,
7773e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * and a transceive() could still be in progress on
7783e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * another Binder thread.
7793e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * Give it a while to finish existing operations
7803e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * before we close it.
7813e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             */
7823e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            Long startTime = SystemClock.elapsedRealtime();
7833e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            do {
7843e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                synchronized (NfcService.this) {
7853e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    if (mOpenEe == null)
7863e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                        break;
7873e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
7883e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                try {
7893e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    Thread.sleep(WAIT_FOR_NFCEE_POLL_MS);
7903e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                } catch (InterruptedException e) {
7913e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    // Ignore
7923e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
7933e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            } while (SystemClock.elapsedRealtime() - startTime < WAIT_FOR_NFCEE_OPERATIONS_MS);
7943e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
7954ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            synchronized (NfcService.this) {
7964ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                if (mOpenEe != null) {
7974ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    try {
7984ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                        _nfcEeClose(-1, mOpenEe.binder);
7994ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    } catch (IOException e) { }
8004ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                }
8014ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            }
8024ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen
80331949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
80431949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
80531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
80631949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
80731949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
80831949217328bf2357ff044f0d18677fe588c790cNick Pelly
8090b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
81031949217328bf2357ff044f0d18677fe588c790cNick Pelly
81131949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
81231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
81331949217328bf2357ff044f0d18677fe588c790cNick Pelly
81431949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
81531949217328bf2357ff044f0d18677fe588c790cNick Pelly
81631949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_OFF);
81731949217328bf2357ff044f0d18677fe588c790cNick Pelly
818d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
819d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
82031949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
82131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
82231949217328bf2357ff044f0d18677fe588c790cNick Pelly
82331949217328bf2357ff044f0d18677fe588c790cNick Pelly        void executeEeWipe() {
82431949217328bf2357ff044f0d18677fe588c790cNick Pelly            // TODO: read SE reset list from /system/etc
825525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            byte[][]apdus = mDeviceHost.getWipeApdus();
826525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
827525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (apdus == null) {
828525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.d(TAG, "No wipe APDUs found");
829525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                return;
830525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
83131949217328bf2357ff044f0d18677fe588c790cNick Pelly
83231949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
833525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Hold a wake-lock over the entire wipe procedure
834525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.acquire();
835525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
836525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (tempEnable && !enableInternal()) {
837ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
83831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
839f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
840525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
841525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    // NFC enabled
842525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    int handle = 0;
843525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    try {
844525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.i(TAG, "Executing SE wipe");
845525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        handle = doOpenSecureElementConnection();
8462b4dc11f4508cdb662a8069cccf9f2273004a4c8Martijn Coenen                        if (handle < 0) {
847525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Log.w(TAG, "Could not open the secure element");
848525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            return;
849525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
850525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        // TODO: remove this hack
851525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
852525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Thread.sleep(1000);
853525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } catch (InterruptedException e) {
854525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            // Ignore
855525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
85631949217328bf2357ff044f0d18677fe588c790cNick Pelly
857525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
858525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
859525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            for (byte[] cmd : apdus) {
860525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                byte[] resp = doTransceiveNoLock(handle, cmd);
861525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                if (resp == null) {
862525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
863525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    break;
864525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                }
865525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            }
866525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } finally {
867525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            mDeviceHost.resetTimeouts();
868525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
869525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    } finally {
8702b4dc11f4508cdb662a8069cccf9f2273004a4c8Martijn Coenen                        if (handle >= 0) {
871525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            doDisconnect(handle);
872525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
873525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
874525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
875525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (tempEnable) {
876525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        disableInternal();
877525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
878ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                }
879525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
880525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEeWakeLock.release();
88131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
882525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            Log.i(TAG, "SE wipe done");
88331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
88431949217328bf2357ff044f0d18677fe588c790cNick Pelly
88531949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
8862a3f6f141fdaf746a81ce850a8ab0ef251041966mike wakerly            synchronized (NfcService.this) {
88731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
88831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
88931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
89031949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
89131949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
89231949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
89331949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
894525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
89531949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
89631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
89731949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
89831949217328bf2357ff044f0d18677fe588c790cNick Pelly
89931949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
90031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
90131949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
90231949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
90331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
9040e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
9050e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
906d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
907d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
908d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
909d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
910d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
911d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
912d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
913d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
914d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
915d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
916d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
917d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
918d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
919d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
920d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
921d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
922d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
923d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
924d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
925d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
9260e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
9274a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
928fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9290e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
93093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
9310e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
93231949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
9331668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen
9341668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
9351668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                if (!mIsAirplaneToggleable) {
9361668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    Log.i(TAG, "denying enable() request (airplane mode)");
9371668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    return false;
9381668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                }
9391668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                // Make sure the override survives a reboot
9401668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
9411668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
942f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
94331949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
94431949217328bf2357ff044f0d18677fe588c790cNick Pelly
94531949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
946f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
947f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
948fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
949290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi        public boolean disable(boolean saveState) throws RemoteException {
95093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
9510e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
952290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            if (saveState) {
953290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi                saveNfcOnSetting(false);
954290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            }
955290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi
95631949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
95731949217328bf2357ff044f0d18677fe588c790cNick Pelly
95831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
959f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
960f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
961fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9620b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
96331949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
9649993a5a96a862cea4512509b413d0de6cacb7c14Nick Pelly                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
96531949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
966d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
967d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
968d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9690b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
970d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
971d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
9720b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
97331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
97431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
9750b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
9760b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
97731949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
9780b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
97931949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
98077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
981d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
982d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
983d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
984d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
985d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
986d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9870b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
988d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
989d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
9900b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
99131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
99231949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
9930b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
9940b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
99531949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
9960b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
99731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
99877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
999d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
1000d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
1001d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
1002d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
1003d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
1004d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
10050b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
100624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
100705973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1008a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
10090b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
10100b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
10110b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
10120b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
1013ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
1014a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
1015a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
1016a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
1017a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
1018a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
1019a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
1020a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
1021a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
1022a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
1023a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
1024a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
1025a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
1026a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
1027a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
102824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
102924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
103024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
103124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
103224dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
103349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
10340b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
10352094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
10362094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
10372094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
103831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public void setAppCallback(IAppCallback callback) {
1039ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
10403859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
1041ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
1042ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
1043ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
10440e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
10450e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
10460e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
10470e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
1048fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1049c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) {
1050c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
105149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mExtrasService;
10520bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
10530bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1054fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1055a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public INfcCardEmulation getNfcCardEmulationInterface() {
1056a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            return mCardEmulationService;
1057a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1058a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
1059a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
106031949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
106131949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
106231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
106331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
106431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
106531949217328bf2357ff044f0d18677fe588c790cNick Pelly
106631949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
106731949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
106831949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
10690e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1070391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly
1071391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        @Override
1072ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        public void dispatch(Tag tag) throws RemoteException {
1073391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            enforceAdminPerm(mContext);
1074ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            mNfcDispatcher.dispatchTag(tag);
1075391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        }
10760c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
10770c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        @Override
10780c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
10790c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            enforceAdminPerm(mContext);
10800c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
10810c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pInitiatorModes(initiatorModes);
10820c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pTargetModes(targetModes);
10830c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.disableDiscovery();
10840c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.enableDiscovery();
10850c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        }
1086c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
1087c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        @Override
108831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public void setReaderMode(IBinder binder, IAppCallback callback, int flags, Bundle extras)
108931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                throws RemoteException {
1090c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            synchronized (NfcService.this) {
1091c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                if (flags != 0) {
1092c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    try {
109331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams = new ReaderModeParams();
109431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.callback = callback;
109531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.flags = flags;
109631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.presenceCheckDelay = extras != null ?
109731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                                (extras.getInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY,
109831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                                DEFAULT_PRESENCE_CHECK_DELAY)) : DEFAULT_PRESENCE_CHECK_DELAY;
1099c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        binder.linkToDeath(mReaderModeDeathRecipient, 0);
1100c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    } catch (RemoteException e) {
1101c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        Log.e(TAG, "Remote binder has already died.");
1102c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        return;
1103c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
1104c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                } else {
1105c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    try {
110631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams = null;
1107c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        binder.unlinkToDeath(mReaderModeDeathRecipient, 0);
1108c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    } catch (NoSuchElementException e) {
1109c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        Log.e(TAG, "Reader mode Binder was never registered.");
1110c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
1111c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                }
1112c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                applyRouting(false);
1113c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            }
1114c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        }
1115c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    }
1116c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
1117c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    final class ReaderModeDeathRecipient implements IBinder.DeathRecipient {
1118c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        @Override
1119c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        public void binderDied() {
1120c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            synchronized (NfcService.this) {
112131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                if (mReaderModeParams != null) {
112231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    mReaderModeParams = null;
1123c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    applyRouting(false);
1124c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                }
1125c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            }
1126c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        }
1127c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
11280e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
1129a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    final class CardEmulationService extends INfcCardEmulation.Stub {
1130a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
1131a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public boolean isDefaultServiceForCategory(int userId, ComponentName service,
1132a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                String category) throws RemoteException {
1133a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1134a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return false;
1135a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
113689c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
113789c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
113878976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            ComponentName defaultService = mAidCache.getDefaultServiceForCategory(userId,
1139451ba48faa87d78bfbec0597ff06af1747cf6acbMartijn Coenen                    category, true);
114078976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return (defaultService != null && defaultService.equals(service));
1141a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1142a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
1143a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
114489c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        public boolean isDefaultServiceForAid(int userId, ComponentName service, String aid)
114589c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen                throws RemoteException {
114689c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            if (!mIsHceCapable) {
114789c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen                return false;
114889c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            }
114989c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
115089c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
115178976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return mAidCache.isDefaultServiceForAid(userId, service, aid);
115289c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        }
115389c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen
115489c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen        @Override
1155a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public boolean setDefaultServiceForCategory(int userId, ComponentName service,
1156a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                String category) throws RemoteException {
1157a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1158a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return false;
1159a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
116089c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
116189c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            enforceAdminPerm(mContext);
116278976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return mAidCache.setDefaultServiceForCategory(userId, service, category);
1163a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
116475f63db568f953e935e62cb3046d167b881979c8Martijn Coenen
116575f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        @Override
116675f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        public boolean setDefaultForNextTap(int userId, ComponentName service)
116775f63db568f953e935e62cb3046d167b881979c8Martijn Coenen                throws RemoteException {
116875f63db568f953e935e62cb3046d167b881979c8Martijn Coenen            if (!mIsHceCapable) {
116975f63db568f953e935e62cb3046d167b881979c8Martijn Coenen                return false;
117075f63db568f953e935e62cb3046d167b881979c8Martijn Coenen            }
117189c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
117289c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            enforceAdminPerm(mContext);
117389c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            mHostEmulationManager.setDefaultForNextTap(service);
117478976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return mAidCache.setDefaultForNextTap(userId, service);
117575f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        }
117675f63db568f953e935e62cb3046d167b881979c8Martijn Coenen
1177a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
1178a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public List<ApduServiceInfo> getServices(int userId, String category)
1179a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                throws RemoteException {
1180a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1181a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return null;
1182a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
118389c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            validateUserId(userId);
118489c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen            enforceAdminPerm(mContext);
118578976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen            return mAidCache.getServicesForCategory(userId, category);
1186a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1187a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    };
1188a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
11894a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
1190fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1191f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
1192d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1193bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1194f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1195f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
119631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1197f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1198f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1199f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1200f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1201f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1202f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1203b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
1204b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
120521545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
1206b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
1207f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1208f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
1209fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1210f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
1211f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1212f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1213fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1214ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
1215d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1216bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1217f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1218f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
121931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1220f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1221f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1222f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1223f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1224f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1225b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1226b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
1227f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1228ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
1229cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            if (!tag.isPresent()) {
1230cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1231cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            }
1232cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen
1233ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
1234ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
1235ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
1236ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
1237ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
1238ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
1239ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1240ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
1241f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1242f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1243fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1244aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
1245aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1246aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1247f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1248aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1249aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
125031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1251aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
1252aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1253aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1254aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
1255f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1256aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
1257aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
1258aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
1259aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
1260aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
1261aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
1262aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1263aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
1264aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
1265aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1266aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
1267b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
1268d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1269bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1270f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
127131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1272f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1273f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1274f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1275f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1276f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1277f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1278b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
1279f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1280f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1281f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1282f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1283fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1284b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
1285f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1286b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1287b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
128831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1289b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1290b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1291b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1292b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
1293f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1294b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1295b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1296b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1297b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1298ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
1299b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1300b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1301fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1302f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
1303182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1304182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen
1305f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1306f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1307f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
130831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
13092c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1310f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1311f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1312f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1313f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
13143ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
13152c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
13162c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1317f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
131870bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
1319f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1320f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1321fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13229d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
132397c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
1324d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1325bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1326f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1327f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
1328f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1329f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
133031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1331f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1332f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1333f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1334f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1335f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1336f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1337bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
1338bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1339bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1340bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
13419d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
13429d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
1343bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
1344bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
1345bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
1346bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
1347bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
1348bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
1349bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
1350bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
1351bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
1352f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1353f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1354f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1355f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1356fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13573fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1358d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1359bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1360f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1361f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1362f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
136331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1364f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1365f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1366f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1367f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1368f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1369f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1370f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
1371f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
1372f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1373f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
1374f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1375f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
1376f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
1377f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
1378f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
1379f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1380f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1381f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1382f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1383f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1384f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1385fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13863fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1387d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1388bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1389f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1390f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1391f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
139231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1393f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1394f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1395f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1396f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1397f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1398f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1399f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1400f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1401f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1402791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1403791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen
1404f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1405f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1406f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1407f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1408f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1409f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1410f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1411f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1412fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
14133fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
14143fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1415f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1416f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1417fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
14183fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
141903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
142003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1421f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
142203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
142303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
142431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
142503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
142603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
142703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
142803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1429f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
143003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
143103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
143203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
143303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1434f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
143503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1436f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
143703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
143803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1439f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1440f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
14410aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
14420aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
14430aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
14440aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1445f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
14460aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
14470aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
144831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
14490aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
14500aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
14510aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
14520aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1453f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
14540aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
14550aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
14560aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
14570aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
14580aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
14590aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1460f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
14610aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
14620aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
14630aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
14640aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
14651b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
14663fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
14673fb14d0868594c78a777e805545209636814e223Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
14683fb14d0868594c78a777e805545209636814e223Martijn Coenen
1469f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
14703fb14d0868594c78a777e805545209636814e223Martijn Coenen
14713fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
147231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
14733fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
14743fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
14753fb14d0868594c78a777e805545209636814e223Martijn Coenen
14763fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1477f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
14783fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
14793fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
14803fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
14813fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
14823fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
14833fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
14843fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
14853fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
14863fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
14873fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
14883fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1489391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                tag.findAndReadNdef();
14903fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
14913fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
14924a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
14933fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
14943fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
14953fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
14963fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
14973fb14d0868594c78a777e805545209636814e223Martijn Coenen
14981b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1499fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
15001b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1501f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1502fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1503fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1504fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1505fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1506fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1507dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1508dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1509dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1510358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
1511358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1512358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1513358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1514358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1515358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1516358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1517dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
1518dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1519dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1520f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
15211b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1522bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1523bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1524bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1525bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1526bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1527bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1528bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1529bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1530bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1531bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1532ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen
1533ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        @Override
1534ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1535ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen            return mDeviceHost.getExtendedLengthApdusSupported();
1536ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        }
1537c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
1538f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
153992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly    void _nfcEeClose(int callingPid, IBinder binder) throws IOException {
1540dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // Blocks until a pending open() or transceive() times out.
1541dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        //TODO: This is incorrect behavior - the close should interrupt pending
1542dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // operations. However this is not supported by current hardware.
1543dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
15440571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly        synchronized (NfcService.this) {
15454ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            if (!isNfcEnabledOrShuttingDown()) {
1546dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC adapter is disabled");
1547dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1548dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (mOpenEe == null) {
1549dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC EE closed");
1550dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
155192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (callingPid != -1 && callingPid != mOpenEe.pid) {
1552dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new SecurityException("Wrong PID");
1553dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
155492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (mOpenEe.binder != binder) {
155592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                throw new SecurityException("Wrong binder handle");
155692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            }
1557dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
155892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            binder.unlinkToDeath(mOpenEe, 0);
1559f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
1560525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            doDisconnect(mOpenEe.handle);
1561dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mOpenEe = null;
1562dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1563fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1564dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        }
1565dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    }
1566dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
15674a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
156849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeNoException() {
156949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
157049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", 0);
157149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
157249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1573c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1574c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private Bundle writeEeException(int exceptionType, String message) {
157549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
1576c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putInt("e", exceptionType);
1577c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putString("m", message);
157849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
157949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
15800bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1581bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1582c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle open(String pkg, IBinder b) throws RemoteException {
1583c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1584bd555ee64250126b60b24814120a2049943920caNick Pelly
158549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
1586c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            int handle = _open(b);
1587c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            if (handle < 0) {
1588c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(handle, "NFCEE open exception.");
1589c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            } else {
159049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
15910bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
159249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
159349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
15940bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1595c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        /**
1596c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * Opens a connection to the secure element.
1597c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *
1598c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * @return A handle with a value >= 0 in case of success, or a
1599c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *         negative value in case of failure.
1600c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         */
1601c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private int _open(IBinder b) {
160249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
160331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
1604c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_NFC_DISABLED;
160549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16067a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                if (mInProvisionMode) {
16077a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // Deny access to the NFCEE as long as the device is being setup
16087a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    return EE_ERROR_IO;
16097a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                }
16107a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                if (mDeviceHost.enablePN544Quirks() && mP2pLinkManager.isLlcpActive()) {
16117a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // Don't allow PN544-based devices to open the SE while the LLCP
16127a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // link is still up or in a debounce state. This avoids race
16137a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // conditions in the NXP stack around P2P/SMX switching.
16147a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    return EE_ERROR_EXT_FIELD;
16157a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                }
161649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe != null) {
1617c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_ALREADY_OPEN;
161849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16190bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1620476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                boolean restorePolling = false;
1621476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                if (mDeviceHost.enablePN544Quirks() && mNfcPollingEnabled) {
1622476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // Disable polling for tags/P2P when connecting to the SMX
1623476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // on PN544-based devices. Whenever nfceeClose is called,
1624476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // the polling configuration will be restored.
1625476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    mDeviceHost.disableDiscovery();
1626476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    mNfcPollingEnabled = false;
1627476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    restorePolling = true;
1628476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                }
1629476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen
1630525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int handle = doOpenSecureElementConnection();
1631c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                if (handle < 0) {
1632476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen
1633476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    if (restorePolling) {
1634476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                        mDeviceHost.enableDiscovery();
1635476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                        mNfcPollingEnabled = true;
1636476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    }
1637c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return handle;
163849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
1639525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000);
1640ba6401757f8017faeb77423f2d08fd51be1d1051Nick Pelly
164192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
164249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                try {
164349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    b.linkToDeath(mOpenEe, 0);
164449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                } catch (RemoteException e) {
164549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    mOpenEe.binderDied();
164649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
164784e1e0adc2516afd35ebab029a52e764e0490559Jason parks
164884e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // Add the calling package to the list of packages that have accessed
164984e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // the secure element.
1650525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) {
165184e1e0adc2516afd35ebab029a52e764e0490559Jason parks                    mSePackages.add(packageName);
165284e1e0adc2516afd35ebab029a52e764e0490559Jason parks                }
1653c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1654c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                return handle;
165549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly           }
16560bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
16570bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1658bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
165992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public Bundle close(String pkg, IBinder binder) throws RemoteException {
1660c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1661c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
166249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
166349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
166492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                _nfcEeClose(getCallingPid(), binder);
166549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
166649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1667c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
16680bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
166949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
167049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
16710bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1672bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1673c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle transceive(String pkg, byte[] in) throws RemoteException {
1674c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1675bd555ee64250126b60b24814120a2049943920caNick Pelly
167649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
167749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            byte[] out;
167849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
167949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                out = _transceive(in);
168049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
168149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result.putByteArray("out", out);
168249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1683c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
16840bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
168549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
168649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
16870bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1688c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly        private byte[] _transceive(byte[] data) throws IOException {
168949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
169031949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
169149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC is not enabled");
169249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16930571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly                if (mOpenEe == null) {
169449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE is not open");
169549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
169649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (getCallingPid() != mOpenEe.pid) {
169749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new SecurityException("Wrong PID");
169849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16990bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
17000bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1701525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceive(mOpenEe.handle, data);
17020bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
17030bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1704bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1705c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public int getCardEmulationRoute(String pkg) throws RemoteException {
1706c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
170749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mEeRoutingState;
17080bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
17090bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1710bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1711c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
1712c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
171349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            mEeRoutingState = route;
1714525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            ApplyRoutingTask applyRoutingTask = new ApplyRoutingTask();
1715525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            applyRoutingTask.execute();
1716525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
1717525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Block until route is set
1718525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                applyRoutingTask.get();
1719525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (ExecutionException e) {
1720525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1721525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (InterruptedException e) {
1722525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1723525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
17240bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
1725bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
1726bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1727c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void authenticate(String pkg, byte[] token) throws RemoteException {
1728c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1729bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1730525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1731525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
1732525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public String getDriverName(String pkg) throws RemoteException {
1733525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            NfcService.this.enforceNfceeAdminPerm(pkg);
1734525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mDeviceHost.getName();
1735525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1736c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
17370bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
173849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** resources kept while secure element is open */
173949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private class OpenSecureElement implements IBinder.DeathRecipient {
174049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int pid;  // pid that opened SE
174192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // binder handle used for DeathReceipient. Must keep
174292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // a reference to this, otherwise it can get GC'd and
174392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // the binder stub code might create a different BinderProxy
174492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // for the same remote IBinder, causing mismatched
174592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // link()/unlink()
174692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public IBinder binder;
174749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int handle; // low-level handle
174892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public OpenSecureElement(int pid, int handle, IBinder binder) {
174949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.pid = pid;
175049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.handle = handle;
175192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            this.binder = binder;
175249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1753bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
175449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void binderDied() {
175549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized (NfcService.this) {
175692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                Log.i(TAG, "Tracked app " + pid + " died");
175749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                pid = -1;
17580bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas                try {
175992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    _nfcEeClose(-1, binder);
1760dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                } catch (IOException e) { /* already closed */ }
17610bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
17620bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
176392250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        @Override
176492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public String toString() {
176592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            return new StringBuilder('@').append(Integer.toHexString(hashCode())).append("[pid=")
176692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    .append(pid).append(" handle=").append(handle).append("]").toString();
176792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        }
17680bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    }
17690bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
17709a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    boolean isNfcEnabledOrShuttingDown() {
17719a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        synchronized (this) {
17729a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
17739a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        }
17749a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    }
17759a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen
177631949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
177731949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
177831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1779e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1780aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1781aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
178231949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
1783a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        final Object mCancelWaiter = new Object();
1784525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        final int mTimeout;
1785a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        boolean mCanceled = false;
1786525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1787525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public WatchDogThread(String threadName, int timeout) {
1788525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            super(threadName);
1789525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mTimeout = timeout;
1790525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1791525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
17922edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
17932edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
1794a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            try {
1795a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                synchronized (mCancelWaiter) {
1796a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    mCancelWaiter.wait(mTimeout);
1797a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    if (mCanceled) {
1798a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                        return;
1799a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    }
18002edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
1801a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            } catch (InterruptedException e) {
1802a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                // Should not happen; fall-through to abort.
1803a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                Log.w(TAG, "Watchdog thread interruped.");
1804a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                interrupt();
18052edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
1806a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            Log.e(TAG, "Watchdog triggered, aborting.");
1807a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            mDeviceHost.doAbort();
18082edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
1809a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project
18102edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
1811a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            synchronized (mCancelWaiter) {
1812a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCanceled = true;
1813a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCancelWaiter.notify();
1814a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            }
18152edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
18162edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
18172edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
18189f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    static byte[] hexStringToBytes(String s) {
18199f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (s == null || s.length() == 0) return null;
18209f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        int len = s.length();
18219f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (len % 2 != 0) {
18229f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            s = '0' + s;
18239f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            len++;
18249f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
18259f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        byte[] data = new byte[len / 2];
18269f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        for (int i = 0; i < len; i += 2) {
18279f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
18289f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                                 + Character.digit(s.charAt(i+1), 16));
18299f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
18309f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        return data;
18319f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
18329f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1833fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /**
1834fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1835fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     */
1836fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    void applyRouting(boolean force) {
1837e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
18389a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            if (!isNfcEnabledOrShuttingDown() || mOpenEe != null) {
1839fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                // PN544 cannot be reconfigured while EE is open
1840e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1841e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1842525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
18437d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            if (mInProvisionMode) {
18447d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
18457d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
18467d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                if (!mInProvisionMode) {
18477d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Notify dispatcher it's fine to dispatch to any package now
18487d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // and allow handover transfers.
18497d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mNfcDispatcher.disableProvisioningMode();
18507d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mHandoverManager.setEnabled(true);
18517d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                }
18527d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            }
1853f439271150e4548f116919e0254d57655421581cMartijn Coenen            try {
1854f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.start();
1855f439271150e4548f116919e0254d57655421581cMartijn Coenen
1856525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) {
1857f439271150e4548f116919e0254d57655421581cMartijn Coenen                    /* TODO undo this after the LLCP stack is fixed.
1858f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * Use a different sequence when turning the screen off to
1859f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * workaround race conditions in pn544 libnfc. The race occurs
1860f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * when we change routing while there is a P2P target connect.
1861f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * The async LLCP callback will crash since the routing code
1862f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * is overwriting globals it relies on.
1863f439271150e4548f116919e0254d57655421581cMartijn Coenen                     */
1864f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (POLLING_MODE > SCREEN_STATE_OFF) {
1865f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfcPollingEnabled) {
1866f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-C OFF, disconnect");
1867f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfcPollingEnabled = false;
1868f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.disableDiscovery();
1869f439271150e4548f116919e0254d57655421581cMartijn Coenen                            maybeDisconnectTarget();
1870f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1871f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1872f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1873f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfceeRouteEnabled) {
1874f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-EE OFF");
1875f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfceeRouteEnabled = false;
1876f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.doDeselectSecureElement();
1877f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1878fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1879f439271150e4548f116919e0254d57655421581cMartijn Coenen                    return;
1880fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1881f439271150e4548f116919e0254d57655421581cMartijn Coenen
18820a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen                if (mIsHceCapable && mScreenState >= SCREEN_STATE_ON_LOCKED &&
1883d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mAidRoutingManager.aidsRoutedToHost()) {
1884d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    if (!mHostRouteEnabled || force) {
1885d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mHostRouteEnabled = true;
1886d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mDeviceHost.enableRoutingToHost();
1887d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    }
1888d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                } else {
1889d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    if (force || mHostRouteEnabled) {
1890d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mHostRouteEnabled = false;
1891d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mDeviceHost.disableRoutingToHost();
18929f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                    }
18939f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                }
18949f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1895f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-EE routing
1896f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
1897f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1898f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfceeRouteEnabled) {
1899f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-EE ON");
1900f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfceeRouteEnabled = true;
1901f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.doSelectSecureElement();
1902f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1903f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1904f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force ||  mNfceeRouteEnabled) {
1905fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        Log.d(TAG, "NFC-EE OFF");
1906fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mNfceeRouteEnabled = false;
1907fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mDeviceHost.doDeselectSecureElement();
1908fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1909fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1910fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1911f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-C polling
1912f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= POLLING_MODE) {
1913f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfcPollingEnabled) {
1914f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C ON");
1915f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = true;
1916f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.enableDiscovery();
1917f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
191831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (mReaderModeParams != null && !mReaderModeEnabled) {
1919c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        mReaderModeEnabled = true;
192031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mDeviceHost.enableReaderMode(mReaderModeParams.flags);
1921c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
192231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (mReaderModeParams == null && mReaderModeEnabled) {
1923c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        mReaderModeEnabled = false;
1924c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        mDeviceHost.disableReaderMode();
1925c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
19267d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                } else if (mInProvisionMode && mScreenState >= SCREEN_STATE_ON_LOCKED) {
19277d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Special case for setup provisioning
19287d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    if (!mNfcPollingEnabled) {
19297d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Log.d(TAG, "NFC-C ON");
19307d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mNfcPollingEnabled = true;
19317d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mDeviceHost.enableDiscovery();
19327d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    }
1933f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1934f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || mNfcPollingEnabled) {
1935f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C OFF");
1936c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        if (mReaderModeEnabled) {
1937c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                            mReaderModeEnabled = false;
1938c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                            mDeviceHost.disableReaderMode();
1939c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        }
1940f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = false;
1941f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.disableDiscovery();
1942f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1943fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1944f439271150e4548f116919e0254d57655421581cMartijn Coenen            } finally {
1945f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.cancel();
1946221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
194765945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
194865945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
194965945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
19502436ffe91853535fad87b7a8e03d8883bae20f20Arnaud Ferir    /** Disconnect any target if present */
195131949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
19529a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        if (!isNfcEnabledOrShuttingDown()) {
1953a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1954a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
195531949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
195631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
195731949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
195831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
195931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
196031949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
196131949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
196231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
196331949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
196431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
196531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
196631949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
196731949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
196831949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
196931949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
197031949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
197131949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
197231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
197331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
197431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
197531949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
197631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
197731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1978bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1979bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1980bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1981bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1982bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
198331949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
198431949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
198531949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
198631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
198731949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
19882f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
198931949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
19900e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1991f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1992f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
199331949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
199431949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
199531949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1996f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1997b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1998b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
199931949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
200031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
200131949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
200231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
2003f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
2004f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2005d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
20064a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
2007c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            throws LlcpException {
20084a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
2009d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
2010d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
2011d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
20123b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
2013e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen            throws LlcpException {
20143b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
2015e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    }
2016e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen
2017e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    /** For use by code in this process */
20184a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
2019c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            int linearBufferLength) throws LlcpException {
20204a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
2021d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
2022d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
202357d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
2024b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
202557d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
202657d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
2027d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void routeAids(String aid, int route) {
2028d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        Message msg = mHandler.obtainMessage();
2029d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.what = MSG_ROUTE_AID;
2030d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.arg1 = route;
2031d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.obj = aid;
2032d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendMessage(msg);
2033d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
2034d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
2035d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void unrouteAids(String aid) {
2036d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        sendMessage(MSG_UNROUTE_AID, aid);
2037d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
2038d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
2039d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void commitRouting() {
2040d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
2041d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
2042d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
20439f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen	public boolean sendData(byte[] data) {
20449f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen	    return mDeviceHost.sendRawFrame(data);
20459f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
20469f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
2047b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
2048b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
2049b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
2050b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
2051b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
2052b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
2053b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
20543fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
2055b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
2056b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
205731949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
2058d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_ROUTE_AID: {
2059d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    int route = msg.arg1;
2060d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
2061d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.routeAid(hexStringToBytes(aid), route);
2062d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    // Restart polling config
2063d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
2064d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
2065d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_UNROUTE_AID: {
2066d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
2067d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.unrouteAid(hexStringToBytes(aid));
2068d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
2069d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
2070d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_COMMIT_ROUTING: {
2071d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    applyRouting(true);
2072d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
2073d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
207431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
207531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
207631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
207731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
207831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
207931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
208031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
208131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
208231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new int[] { TagTechnology.NDEF },
208331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new Bundle[] { extras });
208431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
208531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
2086ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                    boolean delivered = mNfcDispatcher.dispatchTag(tag);
208731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (delivered) {
2088d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
208977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    } else {
2090d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
209131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
209231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
209331949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
209457d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
209531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
209631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
209731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
209831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    ReaderModeParams readerParams = null;
209931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    int presenceCheckDelay = DEFAULT_PRESENCE_CHECK_DELAY;
2100c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    synchronized (NfcService.this) {
210131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        readerParams = mReaderModeParams;
2102c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
210331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (readerParams != null) {
210431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        presenceCheckDelay = readerParams.presenceCheckDelay;
210531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
210631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
210731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            tag.startPresenceChecking(presenceCheckDelay);
210831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            dispatchTagEndpoint(tag, readerParams);
210931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            break;
211031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        }
211131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    }
211231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (readerParams == null ||
211331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            (readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
211431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        playSound(SOUND_START);
2115c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
211689baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
211789baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // When these tags start containing NDEF, they will require
211889baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // the stack to deal with them in a different way, since
211989baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // they are activated only really shortly.
212089baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // For now, don't consider NDEF on these.
212189baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
212231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        tag.startPresenceChecking(presenceCheckDelay);
212331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        dispatchTagEndpoint(tag, readerParams);
212489baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        break;
212589baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    }
2126391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    NdefMessage ndefMsg = tag.findAndReadNdef();
2127c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
2128391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    if (ndefMsg != null) {
212931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        tag.startPresenceChecking(presenceCheckDelay);
213031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        dispatchTagEndpoint(tag, readerParams);
213131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
213231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
213331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            tag.startPresenceChecking(presenceCheckDelay);
213431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            dispatchTagEndpoint(tag, readerParams);
213531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
213631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
2137d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
213831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
213931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
214031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
214131949217328bf2357ff044f0d18677fe588c790cNick Pelly
214231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_CARD_EMULATION:
214331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Emulation message");
214431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] aid = (byte[]) msg.obj;
214531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
214631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent aidIntent = new Intent();
214731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.setAction(ACTION_AID_SELECTED);
214831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.putExtra(EXTRA_AID, aid);
214931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
215014a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(aidIntent);
215131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
215231949217328bf2357ff044f0d18677fe588c790cNick Pelly
215331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_EMV_CARD_REMOVAL:
215431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Removal message");
215531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
215631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent cardRemovalIntent = new Intent();
215731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
215831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
215914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(cardRemovalIntent);
216031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
216131949217328bf2357ff044f0d18677fe588c790cNick Pelly
216231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_APDU_RECEIVED:
216331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "APDU Received message");
216431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] apduBytes = (byte[]) msg.obj;
216531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
216631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent apduReceivedIntent = new Intent();
216731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
216831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (apduBytes != null && apduBytes.length > 0) {
216931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
217031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
217131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
217214a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(apduReceivedIntent);
217331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
217431949217328bf2357ff044f0d18677fe588c790cNick Pelly
217531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_MIFARE_ACCESS:
217631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "MIFARE access message");
217731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
217831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] mifareCmd = (byte[]) msg.obj;
217931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent mifareAccessIntent = new Intent();
218031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
218131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mifareCmd != null && mifareCmd.length > 1) {
218231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        int mifareBlock = mifareCmd[1] & 0xff;
218331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
218431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
218531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
218631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
218714a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(mifareAccessIntent);
218831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
2189c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
219031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
219196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
219296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent actIntent = new Intent(ACTION_LLCP_UP);
219396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(actIntent);
219496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
219531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
219631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
219731949217328bf2357ff044f0d18677fe588c790cNick Pelly
219831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
219996e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
220096e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
220196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(deactIntent);
220296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
220331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
220431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
220531949217328bf2357ff044f0d18677fe588c790cNick Pelly
220631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
220731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
220831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
220931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
221031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
221131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
221231949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
221331949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
221431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
221531949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
221631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
221731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
221831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
221931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
222031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
222131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
222231949217328bf2357ff044f0d18677fe588c790cNick Pelly
222377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
222431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
222557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                case MSG_LLCP_LINK_FIRST_PACKET:
222657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    mP2pLinkManager.onLlcpFirstPacketReceived();
222757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    break;
222831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_TARGET_DESELECTED:
222931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Broadcast Intent Target Deselected */
223031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Target Deselected");
223131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent intent = new Intent();
223231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
223331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting Intent");
223431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
223531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
223631949217328bf2357ff044f0d18677fe588c790cNick Pelly
223731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_ACTIVATED: {
223831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
223931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOnIntent = new Intent();
224031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
224114a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOnIntent);
224231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
224331949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
224431949217328bf2357ff044f0d18677fe588c790cNick Pelly
224531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_DEACTIVATED: {
224631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
224731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOffIntent = new Intent();
224831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
224914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOffIntent);
225031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
225131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
225231949217328bf2357ff044f0d18677fe588c790cNick Pelly
2253525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_ACTIVATED: {
2254525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE ACTIVATED");
2255525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeActivated = new Intent();
2256525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeActivated.setAction(ACTION_SE_LISTEN_ACTIVATED);
2257525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeActivated);
2258525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
2259525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2260525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
2261525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_DEACTIVATED: {
2262525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE DEACTIVATED");
2263525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeDeactivated = new Intent();
2264525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeDeactivated.setAction(ACTION_SE_LISTEN_DEACTIVATED);
2265525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeDeactivated);
2266525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
2267525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
226831949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
226931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
227031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
227131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
2272b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
2273d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
227414a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        private void sendSeBroadcast(Intent intent) {
227514a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
2276c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            // Resume app switches so the receivers can start activites without delay
2277c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfcDispatcher.resumeAppSwitches();
2278c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
2279e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            synchronized(this) {
2280e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                for (PackageInfo pkg : mInstalledPackages) {
2281e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (pkg != null && pkg.applicationInfo != null) {
2282e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
2283e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            intent.setPackage(pkg.packageName);
2284e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            mContext.sendBroadcast(intent);
2285e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        }
2286c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
2287c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
2288c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
228914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        }
229014a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton
2291d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
2292d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
2293d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2294d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
2295d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
2296d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
2297d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
2298d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
2299d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
2300d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
2301d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
230231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
230331949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
230431949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
2305d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
230677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                            mP2pLinkManager.onLlcpActivated();
2307d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
2308d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
2309d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
2310d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
2311d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
2312d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
2313d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
2314d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
2315d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
2316d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2317d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2318d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
2319d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
2320d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
2321d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
2322d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
2323d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2324d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
2325d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
2326d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
2327d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
2328d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
2329d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
2330d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
233131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
233231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
233331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
2334d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
233577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
2336d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
2337d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2338d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2339d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
2340d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2341d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
2342d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2343d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
2344d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
2345d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
234631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, ReaderModeParams readerParams) {
2347f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
2348f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
2349f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
235031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen            if (readerParams != null && readerParams.callback != null) {
235131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                try {
235231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    readerParams.callback.onTagDiscovered(tag);
235331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if ((readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
235431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        playSound(SOUND_END);
235531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    }
235631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    return;
235731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                } catch (RemoteException e) {
235831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    Log.e(TAG, "Reader mode remote has died, falling back.");
235931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                }
236031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen            }
2361ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            if (!mNfcDispatcher.dispatchTag(tag)) {
2362f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
2363d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
2364d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else {
2365d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
23663fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
23673fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
2368b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
2369b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
2370b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
237149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
2372fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
2373fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
2374fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        protected Void doInBackground(Integer... params) {
2375fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            synchronized (NfcService.this) {
2376fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (params == null || params.length != 1) {
2377fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    // force apply current routing
2378fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    applyRouting(true);
2379fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    return null;
2380161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2381fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                mScreenState = params[0].intValue();
2382fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
2383525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
2384525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2385525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    applyRouting(false);
2386525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
2387525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
2388161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2389fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return null;
23907c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
23917c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
23927c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
23937c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
2394525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
23950e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        @Override
23960e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public void onReceive(Context context, Intent intent) {
239731949217328bf2357ff044f0d18677fe588c790cNick Pelly            String action = intent.getAction();
2398525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
2399e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
2400e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
2401e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
2402e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                updatePackageCache();
2403e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2404e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
2405e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    // Clear the NFCEE access cache in case a UID gets recycled
2406e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    mNfceeAccessControl.invalidateCache();
2407e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2408e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
2409e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (dataRemoved) {
2410e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        Uri data = intent.getData();
2411e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (data == null) return;
2412e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        String packageName = data.getSchemeSpecificPart();
24137a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton
2414e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        synchronized (NfcService.this) {
2415e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            if (mSePackages.contains(packageName)) {
2416e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                new EnableDisableTask().execute(TASK_EE_WIPE);
2417e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                mSePackages.remove(packageName);
2418e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            }
24197a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                        }
2420bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                    }
2421bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
2422525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
2423525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                EnableDisableTask eeWipeTask = new EnableDisableTask();
2424525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                eeWipeTask.execute(TASK_EE_WIPE);
2425525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2426525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    eeWipeTask.get();  // blocks until EE wipe is complete
2427525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (ExecutionException e) {
2428525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2429525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (InterruptedException e) {
2430525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2431525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2432525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
2433525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
2434525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    };
2435525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
2436525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2437525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
2438525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2439525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            String action = intent.getAction();
2440525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(
2441525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
2442525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2443525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute();
2444525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(Intent.ACTION_SCREEN_ON)
2445525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_SCREEN_OFF)
2446525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_USER_PRESENT)) {
2447525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2448525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int screenState = SCREEN_STATE_OFF;
2449525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
2450525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_OFF;
2451525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
2452525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = mKeyguard.isKeyguardLocked() ?
2453525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
2454525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
2455525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_ON_UNLOCKED;
2456525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2457525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
245831949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
245931949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
246031949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
246131949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
246231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
246331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
246431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
246531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
246631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
246731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
24681668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
24691668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
247031949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
247131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
247231949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
247331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
247431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
24753859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
24763859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                mP2pLinkManager.onUserSwitched();
247778976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen                if (mAidCache != null) {
247878976de08ad5d5f9d5fcba28f3ea82350907a782Martijn Coenen                    mAidCache.invalidateCache(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
24794358172f18871d58d5bc2050e4d9d0bf9bc2d5e5Martijn Coenen                }
2480f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
2481f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
2482f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
248331949217328bf2357ff044f0d18677fe588c790cNick Pelly
248431949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** Returns true if airplane mode is currently on */
248531949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
24867d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        return Settings.System.getInt(mContentResolver,
24877d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
248831949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
248931949217328bf2357ff044f0d18677fe588c790cNick Pelly
2490fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** for debugging only - no i18n */
249131949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
249231949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
249331949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
249431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
249531949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
249631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
249731949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
249831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
249931949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
250031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
250131949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
250231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
250331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
250431949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
250531949217328bf2357ff044f0d18677fe588c790cNick Pelly
2506fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** For debugging only - no i18n */
2507fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static String screenStateToString(int screenState) {
2508fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        switch (screenState) {
2509fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_OFF:
2510fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "OFF";
2511fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_LOCKED:
2512fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_LOCKED";
2513fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_UNLOCKED:
2514fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_UNLOCKED";
2515fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            default:
2516fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "UNKNOWN";
2517fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
2518fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
2519fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
252031949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
252150effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
252250effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
252350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
252450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
252550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
252650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
252750effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
252850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
252931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
253031949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
25310b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
2532fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mScreenState=" + screenStateToString(mScreenState));
2533fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfcPollingEnabled=" + mNfcPollingEnabled);
2534fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfceeRouteEnabled=" + mNfceeRouteEnabled);
253531949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
253631949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
253792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            pw.println("mOpenEe=" + mOpenEe);
253877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
2539c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfceeAccessControl.dump(fd, pw, args);
2540391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            mNfcDispatcher.dump(fd, pw, args);
254156f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
2542c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
254331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
254431949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
254574180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
2546