NfcService.java revision 75f63db568f953e935e62cb3046d167b881979c8
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;
286493859b424f65af79e3e13835f7dfed38495c00Martijn Coenenimport com.android.nfc.cardemulation.RegisteredServicesCache;
294bbd47e5507d4c47a4d722216606307e45195a0aMartijn Coenenimport com.android.nfc.dhimpl.NativeNfcManager;
304bbd47e5507d4c47a4d722216606307e45195a0aMartijn Coenenimport com.android.nfc.dhimpl.NativeNfcSecureElement;
31d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenenimport android.app.ActivityManager;
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;
502094515fca0cfa0ac87e9cc260d3953d416afe3eJason parksimport android.nfc.INdefPushCallback;
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;
8531949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.concurrent.ExecutionException;
863ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
87525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectpublic class NfcService implements DeviceHostListener {
88bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
89bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
90c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = false;
9176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
92fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
93d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
94fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
95c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** Regular NFC permission */
96bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM = android.Manifest.permission.NFC;
97bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String NFC_PERM_ERROR = "NFC permission required";
98c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
99c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    /** NFC ADMIN permission - only for system apps */
100bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
101bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
102bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
10377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
104f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
105416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
106416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
107416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
108416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
109416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
110416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
1111668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
112a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen    static final boolean SE_BROADCASTS_WITH_HCE = true;
113a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
114b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
115b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_CARD_EMULATION = 1;
116b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_ACTIVATION = 2;
117b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
118b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_TARGET_DESELECTED = 4;
119b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    static final int MSG_MOCK_NDEF = 7;
120c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_ACTIVATED = 8;
121c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas    static final int MSG_SE_FIELD_DEACTIVATED = 9;
1222c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_APDU_RECEIVED = 10;
1232c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
1242c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    static final int MSG_SE_MIFARE_ACCESS = 12;
125525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_ACTIVATED = 13;
126525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int MSG_SE_LISTEN_DEACTIVATED = 14;
12757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    static final int MSG_LLCP_LINK_FIRST_PACKET = 15;
128d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_ROUTE_AID = 16;
129d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_UNROUTE_AID = 17;
130d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    static final int MSG_COMMIT_ROUTING = 18;
131b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
13231949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
13331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
13431949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
13531949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_EE_WIPE = 4;
13631949217328bf2357ff044f0d18677fe588c790cNick Pelly
137fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    // Screen state, used by mScreenState
138fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_UNKNOWN = 0;
139fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_OFF = 1;
140fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_LOCKED = 2;
141fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int SCREEN_STATE_ON_UNLOCKED = 3;
142fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
14349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Copied from com.android.nfc_extras to avoid library dependency
14449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // Must keep in sync with com.android.nfc_extras
14549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_OFF = 1;
14649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
1477efbf69a37134ccbd86a1f6b4121f16b4a80eaaeNick Pelly
148c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // Return values from NfcEe.open() - these are 1:1 mapped
149c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    // to the thrown EE_EXCEPTION_ exceptions in nfc-extras.
150c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_IO = -1;
151c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_ALREADY_OPEN = -2;
152c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_INIT = -3;
153c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_LISTEN_MODE = -4;
154c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_EXT_FIELD = -5;
155c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen    static final int EE_ERROR_NFC_DISABLED = -6;
156c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
157fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** minimum screen state that enables NFC polling (discovery) */
158fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
159fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
160525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for NFC controller to initialize before watchdog
161525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off. This time is chosen large, because firmware download
162525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // may be a part of initialization.
163525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int INIT_WATCHDOG_MS = 90000;
164525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
165525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for routing to be applied before watchdog
166525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off
167525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int ROUTING_WATCHDOG_MS = 10000;
168525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1693e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Amount of time to wait before closing the NFCEE connection
1703e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // in a disable/shutdown scenario.
1713e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_OPERATIONS_MS = 5000;
1723e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    // Polling interval for waiting on NFCEE operations
1733e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen    static final int WAIT_FOR_NFCEE_POLL_MS = 100;
1743e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
175d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
176d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
177d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
178d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
179d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
18049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_ON_DETECTED =
18149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
18249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_RF_FIELD_OFF_DETECTED =
18349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
18449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String ACTION_AID_SELECTED =
18549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        "com.android.nfc_extras.action.AID_SELECTED";
18649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
18749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
18896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_UP =
18996e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_UP";
19096e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
19196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_DOWN =
19296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_DOWN";
19396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
1942c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_APDU_RECEIVED =
1952c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.APDU_RECEIVED";
1962c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_APDU_BYTES =
1972c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.APDU_BYTES";
1982c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
1992c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_EMV_CARD_REMOVAL =
2002c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
2012c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
2022c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String ACTION_MIFARE_ACCESS_DETECTED =
2032c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
2042c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas    public static final String EXTRA_MIFARE_BLOCK =
2052c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas        "com.android.nfc_extras.extra.MIFARE_BLOCK";
2062c37e6a839cecf5638911af357a2ea7aec6093a5Daniel Tomas
207525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_ACTIVATED =
208525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_ACTIVATED";
209525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public static final String ACTION_SE_LISTEN_DEACTIVATED =
210525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            "com.android.nfc_extras.action.SE_LISTEN_DEACTIVATED";
21149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
21249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
21349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
2140bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    private NativeNfcSecureElement mSecureElement;
21549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private OpenSecureElement mOpenEe;  // null when EE closed
21649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private int mEeRoutingState;  // contactless interface routing
2170bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
218d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    // fields below must be used only on the UI thread and therefore aren't synchronized
219d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton    boolean mP2pStarted = false;
220d2d5dddf17ac2008547172cd72faa034a89d569bJeff Hamilton
2212f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
222fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
223525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // mSePackages holds packages that accessed the SE, but only for the owner user,
224525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // as SE access is not granted for non-owner users.
225fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    HashSet<String> mSePackages = new HashSet<String>();
226fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int mScreenState;
2277d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
228fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mIsNdefPushEnabled;
229fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfceeRouteEnabled;  // current Device Host state of NFC-EE routing
230fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mNfcPollingEnabled;  // current Device Host state of NFC-C polling
2319f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    boolean mHostRouteEnabled;   // current Device Host state of host-based routing
232e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    List<PackageInfo> mInstalledPackages; // cached version of installed packages
23331949217328bf2357ff044f0d18677fe588c790cNick Pelly
23431949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
23531949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
23631949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
23731949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
2382f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
2392f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
24005973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
2414a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
2420e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
2430e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
244525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mRoutingWakeLock;
245525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mEeWakeLock;
246525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
247d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
248d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
249d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
250d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
25177d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
2524a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
2534a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
2544a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterExtrasService mExtrasService;
255a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    CardEmulationService mCardEmulationService;
25631949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
25731949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
25896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    boolean mIsDebugBuild;
2590a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen    boolean mIsHceCapable;
260c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    NfceeAccessControl mNfceeAccessControl;
2612ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
26276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
263fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    private PowerManager mPowerManager;
264275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
2657d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private HandoverManager mHandoverManager;
2667d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private ContentResolver mContentResolver;
267a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    private RegisteredServicesCache mServiceCache;
2689f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    private HostEmulationManager mHostEmulationManager;
269d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    private AidRoutingManager mAidRoutingManager;
270d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
271d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    private static NfcService sService;
272d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
27393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    public static void enforceAdminPerm(Context context) {
274c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
27593d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
27693d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
277c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    public void enforceNfceeAdminPerm(String pkg) {
278c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (pkg == null) {
279c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException("caller must pass a package name");
280c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
281c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
282c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        if (!mNfceeAccessControl.check(Binder.getCallingUid(), pkg)) {
283c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
284c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    " denies NFCEE access to " + pkg);
285c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        }
286525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
287525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            throw new SecurityException("only the owner is allowed to call SE APIs");
288525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
28993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton    }
29093d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton
291d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
292d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
293d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
294f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2950e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
296f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
297f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
298f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
299f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
300f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
301f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
302f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
303d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
304f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationDeselected() {
305a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3060a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
3070a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
308f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
309f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
310f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
311f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
312f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
313d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
314f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onCardEmulationAidSelected(byte[] aid) {
315a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3160a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_CARD_EMULATION, aid);
3170a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
318f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
319f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
320f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
3219f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen     * Notifies transaction
3229f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen     */
3239f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3249f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationActivated() {
3250a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3260a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyHostEmulationActivated();
3270a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3289f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3299f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3309f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3319f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationData(byte[] data) {
3320a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3330a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyHostEmulationData(data);
3340a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3359f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3369f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3379f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
3389f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationDeactivated() {
3390a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mHostEmulationManager != null) {
3400a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mHostEmulationManager.notifyNostEmulationDeactivated();
3410a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
3429f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
3439f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
3449f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    /**
345f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
346f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
347f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
348f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
349f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
350f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
351f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
352f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
353f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
354f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
355d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
356f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
357f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
358f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
359f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
36057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    /**
36157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     * Notifies P2P Device detected, first packet received over LLCP link
36257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     */
36357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    @Override
36457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
36557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
36657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    }
36757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
368d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
369f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldActivated() {
370a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3710a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
3720a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
373f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
374f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
375d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
376f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteFieldDeactivated() {
377a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3780a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
3790a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
380f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
381f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
382f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
383525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenActivated() {
384a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3850a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_LISTEN_ACTIVATED, null);
3860a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
387525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
388525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
389525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
390525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public void onSeListenDeactivated() {
391a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
3920a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_LISTEN_DEACTIVATED, null);
3930a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
394525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
395525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
396525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
397525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    @Override
398442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeApduReceived(byte[] apdu) {
399a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4000a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
4010a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
402442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
403442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
404442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
405442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeEmvCardRemoval() {
406a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4070a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
4080a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
409442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
410442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
411442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    @Override
412442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    public void onSeMifareAccess(byte[] block) {
413a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4140a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
4150a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
416442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly    }
417442cad40a205a63ea8797fbccaee99b2e8ab89abNick Pelly
418525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public NfcService(Application nfcApplication) {
4194a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
4204a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
421ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly        mExtrasService = new NfcAdapterExtrasService();
422a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        mCardEmulationService = new CardEmulationService();
4234a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton
4242f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
4252f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
426d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
427d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
428525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext = nfcApplication;
4297d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mContentResolver = mContext.getContentResolver();
430525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDeviceHost = new NativeNfcManager(mContext, this);
43174180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
4327d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager = new HandoverManager(mContext);
4337d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        boolean isNfcProvisioningEnabled = false;
4347d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        try {
4357d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
4367d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    R.bool.enable_nfc_provisioning);
4377d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } catch (NotFoundException e) {
4387d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
4397d8987f233985a5ff29226890e11012275d325f5Martijn Coenen
4407d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        if (isNfcProvisioningEnabled) {
4417d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
4427d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
4437d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } else {
4447d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = false;
4457d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
446525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
4477d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mHandoverManager.setEnabled(!mInProvisionMode);
4487d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
4497d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
450525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
45124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
45237058bf7b59def2f9a565ae5b16aae54e80e9e95Sunil Jogi        mSecureElement = new NativeNfcSecureElement(mContext);
453eab09ad7204fe1f0feaca33efccf75c1bb388708Robert Tsai        mEeRoutingState = ROUTE_OFF;
4540bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
455525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mNfceeAccessControl = new NfceeAccessControl(mContext);
456c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
457525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
4580e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
459f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
46031949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
4610b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
462f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
46396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
46496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
465525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
466525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
467525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mRoutingWakeLock = mPowerManager.newWakeLock(
468525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
469525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock = mPowerManager.newWakeLock(
470525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mEeWakeLock");
471275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
472525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
473fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        mScreenState = checkScreenState();
474533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
475d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
476f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
477525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents for all users
478eead88c5e2bdd34eb33fdf2c76717f9edb9e0396Jeff Hamilton        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
47965945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_OFF);
48065945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
481275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
4823859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        filter.addAction(Intent.ACTION_USER_SWITCHED);
48331949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
484525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
4850e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
4860a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        PackageManager pm = mContext.getPackageManager();
4870a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HCE);
4880a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mIsHceCapable) {
4890a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mAidRoutingManager = new AidRoutingManager();
490a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            mServiceCache = new RegisteredServicesCache(mContext, mAidRoutingManager);
491a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            mHostEmulationManager = new HostEmulationManager(mContext, mServiceCache);
492a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        }
493a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        if (!mIsHceCapable || SE_BROADCASTS_WITH_HCE) {
4940a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            IntentFilter ownerFilter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
4950a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
4960a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
4970a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
4980a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
4990a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mContext.registerReceiver(mOwnerReceiver, ownerFilter);
5000a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5010a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter = new IntentFilter();
5020a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
5030a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
5040a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            ownerFilter.addDataScheme("package");
5050a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5060a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            mContext.registerReceiver(mOwnerReceiver, ownerFilter);
5070a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen
5080a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            updatePackageCache();
5090a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
510e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
51131949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
51231949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
51331949217328bf2357ff044f0d18677fe588c790cNick Pelly
514d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
515d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
516d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
517d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
518525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
519525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
520525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
521d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
522d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
523d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
524d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
525d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
526d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        synchronized(this) {
527d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
528d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
529d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
530d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
531d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
532d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
533d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
53431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
5357d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
5367d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_RADIOS);
5377d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String toggleableRadios = Settings.System.getString(mContentResolver,
5387d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
53931949217328bf2357ff044f0d18677fe588c790cNick Pelly
54031949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
5417d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
54231949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
5437d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            toggleableRadios.contains(Settings.Global.RADIO_NFC);
54431949217328bf2357ff044f0d18677fe588c790cNick Pelly
54531949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
54631949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
54731949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
54831949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
54931949217328bf2357ff044f0d18677fe588c790cNick Pelly
550e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    void updatePackageCache() {
551525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        PackageManager pm = mContext.getPackageManager();
552525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
553e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        synchronized (this) {
554e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            mInstalledPackages = packages;
555e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen        }
556e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen    }
557e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
558fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int checkScreenState() {
559fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        if (!mPowerManager.isScreenOn()) {
560fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_OFF;
561fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else if (mKeyguard.isKeyguardLocked()) {
562fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_LOCKED;
563fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        } else {
564fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            return SCREEN_STATE_ON_UNLOCKED;
565fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
566fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
567fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
568525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    int doOpenSecureElementConnection() {
569525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
570525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
571525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mSecureElement.doOpenSecureElementConnection();
572525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
573525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
574525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
575525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
576525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
577525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceive(int handle, byte[] cmd) {
578525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
579525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
580525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceiveNoLock(handle, cmd);
581525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
582525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
583525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
584525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
585525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
586525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    byte[] doTransceiveNoLock(int handle, byte[] cmd) {
587525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        return mSecureElement.doTransceive(handle, cmd);
588525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
589525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
590525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    void doDisconnect(int handle) {
591525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mEeWakeLock.acquire();
592525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        try {
593525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mSecureElement.doDisconnect(handle);
594525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        } finally {
595525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.release();
596525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
597525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    }
598525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
59931949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
60031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
60131949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
60231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
60331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
60431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
60531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
60631949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
60731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
60831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
60931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
61031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
61131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
61231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
61331949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
61431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
61531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
61631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
61731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
61831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
61931949217328bf2357ff044f0d18677fe588c790cNick Pelly     *
62031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
62131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
62231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
62331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
62431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
62531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
62631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * process may temporarily enable the NFC adapter
62731949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
62831949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
62931949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
63031949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
63131949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
63231949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
63331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
63431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
63531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
63631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
63731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
63831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
63931949217328bf2357ff044f0d18677fe588c790cNick Pelly
6404467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
6414467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
6424467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
6434467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
6444467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
6454467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
6464467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
6474467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
6484467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
64931949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
65031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
65131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
65231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
65331949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
65431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
65531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
65631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
6570fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    Log.d(TAG,"checking on firmware download");
6581668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
65931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
6601668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
6610fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is on. Doing normal stuff");
66231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
6630fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
6640fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        Log.d(TAG,"NFC is off.  Checking firmware version");
6650fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
66631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
66731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
66831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
66931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
67031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
67131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        executeEeWipe();
67231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
67331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
67431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_EE_WIPE:
67531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    executeEeWipe();
67631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
67731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
678d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
679d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
680d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
68131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
68231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
68331949217328bf2357ff044f0d18677fe588c790cNick Pelly
68431949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
68531949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
68631949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
68731949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
68831949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
68931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
69031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
69131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
69231949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
69331949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
69431949217328bf2357ff044f0d18677fe588c790cNick Pelly
695525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
696525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            watchDog.start();
697525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
698525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
699525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
700525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (!mDeviceHost.initialize()) {
701525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.w(TAG, "Error enabling NFC");
702525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        updateState(NfcAdapter.STATE_OFF);
703525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        return false;
704525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
705525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
706525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
707525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
708525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
709525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                watchDog.cancel();
71031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
71131949217328bf2357ff044f0d18677fe588c790cNick Pelly
7120a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            if (mIsHceCapable) {
7130a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen                // Generate the initial card emulation routing table
714a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                mServiceCache.invalidateCache(ActivityManager.getCurrentUser(), true);
7150a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            }
716d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
71731949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized(NfcService.this) {
71831949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
7190b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
72031949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
72131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
72231949217328bf2357ff044f0d18677fe588c790cNick Pelly
723d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
724d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
72531949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
7260c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
727fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
72831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
72931949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
73031949217328bf2357ff044f0d18677fe588c790cNick Pelly
73131949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
73231949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
73331949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
73431949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
73531949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
73631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
73731949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
73831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
73931949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
74031949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
74131949217328bf2357ff044f0d18677fe588c790cNick Pelly
74231949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
74331949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
74431949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
74531949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
746525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
74731949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
74831949217328bf2357ff044f0d18677fe588c790cNick Pelly
749953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            if (mIsHceCapable) {
750953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen                mAidRoutingManager.onNfccRoutingTableCleared();
751953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            }
752d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
75377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
75431949217328bf2357ff044f0d18677fe588c790cNick Pelly
7553e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            /* The NFC-EE may still be opened by another process,
7563e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * and a transceive() could still be in progress on
7573e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * another Binder thread.
7583e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * Give it a while to finish existing operations
7593e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             * before we close it.
7603e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen             */
7613e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            Long startTime = SystemClock.elapsedRealtime();
7623e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            do {
7633e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                synchronized (NfcService.this) {
7643e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    if (mOpenEe == null)
7653e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                        break;
7663e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
7673e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                try {
7683e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    Thread.sleep(WAIT_FOR_NFCEE_POLL_MS);
7693e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                } catch (InterruptedException e) {
7703e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                    // Ignore
7713e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen                }
7723e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen            } while (SystemClock.elapsedRealtime() - startTime < WAIT_FOR_NFCEE_OPERATIONS_MS);
7733e38dca2bc7c7629d7159663d597a1e886d85527Martijn Coenen
7744ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            synchronized (NfcService.this) {
7754ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                if (mOpenEe != null) {
7764ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    try {
7774ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                        _nfcEeClose(-1, mOpenEe.binder);
7784ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                    } catch (IOException e) { }
7794ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen                }
7804ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            }
7814ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen
78231949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
78331949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
78431949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
78531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
78631949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
78731949217328bf2357ff044f0d18677fe588c790cNick Pelly
7880b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
78931949217328bf2357ff044f0d18677fe588c790cNick Pelly
79031949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
79131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
79231949217328bf2357ff044f0d18677fe588c790cNick Pelly
79331949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
79431949217328bf2357ff044f0d18677fe588c790cNick Pelly
79531949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_OFF);
79631949217328bf2357ff044f0d18677fe588c790cNick Pelly
797d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
798d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
79931949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
80031949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
80131949217328bf2357ff044f0d18677fe588c790cNick Pelly
80231949217328bf2357ff044f0d18677fe588c790cNick Pelly        void executeEeWipe() {
80331949217328bf2357ff044f0d18677fe588c790cNick Pelly            // TODO: read SE reset list from /system/etc
804525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            byte[][]apdus = mDeviceHost.getWipeApdus();
805525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
806525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (apdus == null) {
807525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.d(TAG, "No wipe APDUs found");
808525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                return;
809525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
81031949217328bf2357ff044f0d18677fe588c790cNick Pelly
81131949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
812525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            // Hold a wake-lock over the entire wipe procedure
813525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mEeWakeLock.acquire();
814525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
815525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (tempEnable && !enableInternal()) {
816ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
81731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
818f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
819525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
820525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    // NFC enabled
821525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    int handle = 0;
822525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    try {
823525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.i(TAG, "Executing SE wipe");
824525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        handle = doOpenSecureElementConnection();
8252b4dc11f4508cdb662a8069cccf9f2273004a4c8Martijn Coenen                        if (handle < 0) {
826525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Log.w(TAG, "Could not open the secure element");
827525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            return;
828525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
829525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        // TODO: remove this hack
830525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
831525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            Thread.sleep(1000);
832525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } catch (InterruptedException e) {
833525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            // Ignore
834525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
83531949217328bf2357ff044f0d18677fe588c790cNick Pelly
836525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
837525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        try {
838525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            for (byte[] cmd : apdus) {
839525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                byte[] resp = doTransceiveNoLock(handle, cmd);
840525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                if (resp == null) {
841525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
842525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                    break;
843525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                                }
844525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            }
845525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        } finally {
846525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            mDeviceHost.resetTimeouts();
847525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
848525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    } finally {
8492b4dc11f4508cdb662a8069cccf9f2273004a4c8Martijn Coenen                        if (handle >= 0) {
850525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            doDisconnect(handle);
851525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        }
852525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
853525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
854525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (tempEnable) {
855525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        disableInternal();
856525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
857ca7e72aaac66ce856c32aaffb8fd2163d7bb486aNick Pelly                }
858525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
859525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEeWakeLock.release();
86031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
861525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            Log.i(TAG, "SE wipe done");
86231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
86331949217328bf2357ff044f0d18677fe588c790cNick Pelly
86431949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
8652a3f6f141fdaf746a81ce850a8ab0ef251041966mike wakerly            synchronized (NfcService.this) {
86631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
86731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
86831949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
86931949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
87031949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
87131949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
87231949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
873525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
87431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
87531949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
87631949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
87731949217328bf2357ff044f0d18677fe588c790cNick Pelly
87831949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
87931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
88031949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
88131949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
88231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
8830e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
8840e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
885d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
886d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
887d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
888d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
889d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
890d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
891d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
892d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
893d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
894d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
895d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
896d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
897d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
898d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
899d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
900d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
901d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
902d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
903d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
904d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
9050e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
9064a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
907fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9080e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
90993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
9100e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
91131949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
9121668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen
9131668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
9141668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                if (!mIsAirplaneToggleable) {
9151668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    Log.i(TAG, "denying enable() request (airplane mode)");
9161668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    return false;
9171668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                }
9181668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                // Make sure the override survives a reboot
9191668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
9201668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
921f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
92231949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
92331949217328bf2357ff044f0d18677fe588c790cNick Pelly
92431949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
925f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
926f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
927fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
928290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi        public boolean disable(boolean saveState) throws RemoteException {
92993d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamilton            NfcService.enforceAdminPerm(mContext);
9300e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
931290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            if (saveState) {
932290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi                saveNfcOnSetting(false);
933290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            }
934290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi
93531949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
93631949217328bf2357ff044f0d18677fe588c790cNick Pelly
93731949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
938f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
939f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
940fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
9410b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
94231949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
9439993a5a96a862cea4512509b413d0de6cacb7c14Nick Pelly                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
94431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
945d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
946d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
947d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9480b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
949d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
950d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
9510b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
95231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
95331949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
9540b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
9550b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
95631949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
9570b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
95831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
95977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
960d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
961d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
962d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
963d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
964d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
965d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9660b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
967d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            NfcService.enforceAdminPerm(mContext);
968d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            synchronized(NfcService.this) {
9690b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
97031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
97131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
9720b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
9730b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
97431949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
9750b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
97631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
97777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
978d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
979d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
980d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
981d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
982d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
983d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
9840b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
98524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
98605973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
987a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
9880b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
9890b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
9900b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
9910b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
992ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
993a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
994a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
995a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
996a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
997a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
998a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
999a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
1000a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
1001a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
1002a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
1003a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
1004a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
1005a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
1006a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
100724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
100824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
100924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
101024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
101124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
101249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
10130b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
10142094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
10152094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
10162094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
1017c96f982f8c0fa061701143a27395acf3b24dfb54Nick Pelly        public void setNdefPushCallback(INdefPushCallback callback) {
1018ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
10193859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
1020ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
1021ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
1022ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
10230e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
10240e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
10250e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
10260e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
1027fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1028c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) {
1029c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
103049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mExtrasService;
10310bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
10320bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1033fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1034a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public INfcCardEmulation getNfcCardEmulationInterface() {
1035a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            return mCardEmulationService;
1036a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1037a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
1038a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
103931949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
104031949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
104131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
104231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
104331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
104431949217328bf2357ff044f0d18677fe588c790cNick Pelly
104531949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
104631949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
104731949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
10480e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1049391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly
1050391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        @Override
1051ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        public void dispatch(Tag tag) throws RemoteException {
1052391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            enforceAdminPerm(mContext);
1053ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            mNfcDispatcher.dispatchTag(tag);
1054391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        }
10550c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
10560c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        @Override
10570c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
10580c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            enforceAdminPerm(mContext);
10590c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
10600c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pInitiatorModes(initiatorModes);
10610c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pTargetModes(targetModes);
10620c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.disableDiscovery();
10630c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.enableDiscovery();
10640c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        }
1065c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
10660e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
1067a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    final class CardEmulationService extends INfcCardEmulation.Stub {
1068a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
1069a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public boolean isDefaultServiceForCategory(int userId, ComponentName service,
1070a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                String category) throws RemoteException {
1071a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1072a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return false;
1073a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
1074a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            // TODO perm
1075a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            ApduServiceInfo defaultService = mServiceCache.getDefaultServiceForCategory(userId,
1076a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                    category);
1077a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            return (defaultService != null && defaultService.getComponent().equals(service));
1078a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1079a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
1080a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
1081a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public boolean setDefaultServiceForCategory(int userId, ComponentName service,
1082a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                String category) throws RemoteException {
1083a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
1084a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1085a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return false;
1086a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
1087a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            // TODO perm
1088a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            return mServiceCache.setDefaultServiceForCategory(userId, service, category);
1089a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
109075f63db568f953e935e62cb3046d167b881979c8Martijn Coenen
109175f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        @Override
109275f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        public boolean setDefaultForNextTap(int userId, ComponentName service)
109375f63db568f953e935e62cb3046d167b881979c8Martijn Coenen                throws RemoteException {
109475f63db568f953e935e62cb3046d167b881979c8Martijn Coenen            if (!mIsHceCapable) {
109575f63db568f953e935e62cb3046d167b881979c8Martijn Coenen                return false;
109675f63db568f953e935e62cb3046d167b881979c8Martijn Coenen            }
109775f63db568f953e935e62cb3046d167b881979c8Martijn Coenen            // TODO perm
109875f63db568f953e935e62cb3046d167b881979c8Martijn Coenen            return mServiceCache.setDefaultForNextTap(userId, service);
109975f63db568f953e935e62cb3046d167b881979c8Martijn Coenen        }
110075f63db568f953e935e62cb3046d167b881979c8Martijn Coenen
1101a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
1102a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public List<ApduServiceInfo> getServices(int userId, String category)
1103a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                throws RemoteException {
1104a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1105a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return null;
1106a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
1107a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            // TODO perm
1108a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            return mServiceCache.getServicesForCategory(userId, category);
1109a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1110a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
1111a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
1112a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public boolean isDefaultServiceForAid(int userHandle, ComponentName service, String aid)
1113a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                throws RemoteException {
1114a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            if (!mIsHceCapable) {
1115a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen                return false;
1116a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            }
1117a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            // TODO perm
1118a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen            return false;
1119a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
1120a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen    };
1121a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
11224a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
1123fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1124f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
1125d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1126bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1127f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1128f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
112931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1130f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1131f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1132f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1133f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1134f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1135f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1136b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
1137b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
113821545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
1139b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
1140f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1141f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
1142fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1143f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
1144f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1145f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1146fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1147ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
1148d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1149bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1150f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1151f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
115231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1153f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1154f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1155f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1156f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1157f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1158b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1159b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
1160f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1161ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
1162cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            if (!tag.isPresent()) {
1163cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1164cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            }
1165cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen
1166ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
1167ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
1168ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
1169ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
1170ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
1171ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
1172ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1173ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
1174f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1175f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1176fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1177aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
1178aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1179aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1180f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1181aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1182aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
118331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1184aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
1185aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1186aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1187aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
1188f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1189aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
1190aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
1191aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
1192aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
1193aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
1194aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
1195aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1196aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
1197aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
1198aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1199aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
1200b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
1201d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1202bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1203f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
120431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1205f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1206f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1207f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1208f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1209f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1210f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1211b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
1212f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1213f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1214f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1215f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1216fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1217b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
1218f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1219b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1220b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
122131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1222b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1223b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1224b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1225b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
1226f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1227b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1228b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1229b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1230b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1231ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
1232b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1233b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1234fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1235f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
1236182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1237182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen
1238f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1239f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1240f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
124131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
12422c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1243f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1244f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1245f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1246f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
12473ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
12482c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
12492c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1250f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
125170bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
1252f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1253f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1254fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12559d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
125697c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
1257d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1258bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1259f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1260f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
1261f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1262f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
126331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1264f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1265f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1266f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1267f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1268f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1269f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1270bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
1271bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1272bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1273bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
12749d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
12759d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
1276bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
1277bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
1278bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
1279bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
1280bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
1281bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
1282bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
1283bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
1284bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
1285f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1286f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1287f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1288f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1289fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12903fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1291d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1292bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1293f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1294f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1295f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
129631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1297f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1298f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1299f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1300f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1301f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1302f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1303f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
1304f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
1305f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1306f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
1307f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1308f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
1309f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
1310f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
1311f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
1312f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1313f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1314f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1315f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1316f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1317f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1318fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13193fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1320d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1321bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1322f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1323f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1324f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
132531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1326f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1327f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1328f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1329f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1330f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1331f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1332f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1333f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1334f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1335791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1336791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen
1337f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1338f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1339f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1340f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1341f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1342f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1343f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1344f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1345fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13463fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
13473fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1348f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1349f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1350fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
13513fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
135203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
135303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1354f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
135503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
135603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
135731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
135803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
135903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
136003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
136103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1362f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
136303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
136403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
136503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
136603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1367f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
136803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1369f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
137003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
137103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1372f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1373f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
13740aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
13750aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
13760aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
13770aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1378f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
13790aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
13800aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
138131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
13820aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
13830aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
13840aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
13850aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1386f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
13870aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
13880aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
13890aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
13900aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
13910aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
13920aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1393f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
13940aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
13950aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
13960aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
13970aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
13981b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
13993fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
14003fb14d0868594c78a777e805545209636814e223Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
14013fb14d0868594c78a777e805545209636814e223Martijn Coenen
1402f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
14033fb14d0868594c78a777e805545209636814e223Martijn Coenen
14043fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
140531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
14063fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
14073fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
14083fb14d0868594c78a777e805545209636814e223Martijn Coenen
14093fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1410f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
14113fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
14123fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
14133fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
14143fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
14153fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
14163fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
14173fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
14183fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
14193fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
14203fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
14213fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1422391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                tag.findAndReadNdef();
14233fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
14243fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
14254a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
14263fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
14273fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
14283fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
14293fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
14303fb14d0868594c78a777e805545209636814e223Martijn Coenen
14311b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1432fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
14331b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1434f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1435fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1436fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1437fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1438fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1439fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1440dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1441dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1442dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1443358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
1444358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1445358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1446358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1447358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1448358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1449358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1450dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
1451dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1452dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1453f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
14541b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1455bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1456bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1457bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1458bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1459bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1460bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1461bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1462bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1463bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1464bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1465ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen
1466ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        @Override
1467ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1468ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen            return mDeviceHost.getExtendedLengthApdusSupported();
1469ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        }
1470c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
1471f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
147292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly    void _nfcEeClose(int callingPid, IBinder binder) throws IOException {
1473dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // Blocks until a pending open() or transceive() times out.
1474dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        //TODO: This is incorrect behavior - the close should interrupt pending
1475dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        // operations. However this is not supported by current hardware.
1476dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
14770571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly        synchronized (NfcService.this) {
14784ac28aa73f8bc7b501912fb8e96877a7b9a1f4f2Martijn Coenen            if (!isNfcEnabledOrShuttingDown()) {
1479dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC adapter is disabled");
1480dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
1481dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            if (mOpenEe == null) {
1482dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new IOException("NFC EE closed");
1483dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
148492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (callingPid != -1 && callingPid != mOpenEe.pid) {
1485dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                throw new SecurityException("Wrong PID");
1486dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            }
148792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            if (mOpenEe.binder != binder) {
148892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                throw new SecurityException("Wrong binder handle");
148992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            }
1490dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
149192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            binder.unlinkToDeath(mOpenEe, 0);
1492f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
1493525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            doDisconnect(mOpenEe.handle);
1494dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly            mOpenEe = null;
1495dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
1496fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1497dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly        }
1498dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly    }
1499dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly
15004a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
150149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        private Bundle writeNoException() {
150249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
150349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            p.putInt("e", 0);
150449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
150549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1506c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1507c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private Bundle writeEeException(int exceptionType, String message) {
150849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle p = new Bundle();
1509c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putInt("e", exceptionType);
1510c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            p.putString("m", message);
151149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return p;
151249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
15130bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1514bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1515c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle open(String pkg, IBinder b) throws RemoteException {
1516c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1517bd555ee64250126b60b24814120a2049943920caNick Pelly
151849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
1519c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            int handle = _open(b);
1520c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            if (handle < 0) {
1521c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(handle, "NFCEE open exception.");
1522c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen            } else {
152349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
15240bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
152549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
152649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
15270bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1528c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        /**
1529c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * Opens a connection to the secure element.
1530c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *
1531c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         * @return A handle with a value >= 0 in case of success, or a
1532c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         *         negative value in case of failure.
1533c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen         */
1534c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen        private int _open(IBinder b) {
153549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
153631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
1537c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_NFC_DISABLED;
153849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
15397a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                if (mInProvisionMode) {
15407a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // Deny access to the NFCEE as long as the device is being setup
15417a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    return EE_ERROR_IO;
15427a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                }
15437a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                if (mDeviceHost.enablePN544Quirks() && mP2pLinkManager.isLlcpActive()) {
15447a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // Don't allow PN544-based devices to open the SE while the LLCP
15457a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // link is still up or in a debounce state. This avoids race
15467a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    // conditions in the NXP stack around P2P/SMX switching.
15477a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                    return EE_ERROR_EXT_FIELD;
15487a499e775021bafefbe890d079e2a43f4a54482cMartijn Coenen                }
154949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (mOpenEe != null) {
1550c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return EE_ERROR_ALREADY_OPEN;
155149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
15520bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1553476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                boolean restorePolling = false;
1554476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                if (mDeviceHost.enablePN544Quirks() && mNfcPollingEnabled) {
1555476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // Disable polling for tags/P2P when connecting to the SMX
1556476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // on PN544-based devices. Whenever nfceeClose is called,
1557476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    // the polling configuration will be restored.
1558476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    mDeviceHost.disableDiscovery();
1559476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    mNfcPollingEnabled = false;
1560476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    restorePolling = true;
1561476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                }
1562476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen
1563525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int handle = doOpenSecureElementConnection();
1564c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                if (handle < 0) {
1565476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen
1566476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    if (restorePolling) {
1567476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                        mDeviceHost.enableDiscovery();
1568476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                        mNfcPollingEnabled = true;
1569476ee8a64404b7ee042ba1a70400bcb1dd5ace10Martijn Coenen                    }
1570c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                    return handle;
157149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
1572525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 30000);
1573ba6401757f8017faeb77423f2d08fd51be1d1051Nick Pelly
157492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
157549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                try {
157649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    b.linkToDeath(mOpenEe, 0);
157749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                } catch (RemoteException e) {
157849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    mOpenEe.binderDied();
157949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
158084e1e0adc2516afd35ebab029a52e764e0490559Jason parks
158184e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // Add the calling package to the list of packages that have accessed
158284e1e0adc2516afd35ebab029a52e764e0490559Jason parks                // the secure element.
1583525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                for (String packageName : mContext.getPackageManager().getPackagesForUid(getCallingUid())) {
158484e1e0adc2516afd35ebab029a52e764e0490559Jason parks                    mSePackages.add(packageName);
158584e1e0adc2516afd35ebab029a52e764e0490559Jason parks                }
1586c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
1587c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                return handle;
158849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly           }
15890bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
15900bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1591bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
159292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public Bundle close(String pkg, IBinder binder) throws RemoteException {
1593c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1594c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
159549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
159649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
159792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                _nfcEeClose(getCallingPid(), binder);
159849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
159949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1600c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
16010bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
160249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
160349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
16040bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1605bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1606c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public Bundle transceive(String pkg, byte[] in) throws RemoteException {
1607c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1608bd555ee64250126b60b24814120a2049943920caNick Pelly
160949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            Bundle result;
161049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            byte[] out;
161149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            try {
161249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                out = _transceive(in);
161349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result = writeNoException();
161449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                result.putByteArray("out", out);
161549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            } catch (IOException e) {
1616c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen                result = writeEeException(EE_ERROR_IO, e.getMessage());
16170bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
161849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return result;
161949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
16200bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1621c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly        private byte[] _transceive(byte[] data) throws IOException {
162249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized(NfcService.this) {
162331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!isNfcEnabled()) {
162449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC is not enabled");
162549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16260571ce53451baf7d363703b6e3ac10bc885fc5bcNick Pelly                if (mOpenEe == null) {
162749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new IOException("NFC EE is not open");
162849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
162949d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                if (getCallingPid() != mOpenEe.pid) {
163049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                    throw new SecurityException("Wrong PID");
163149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                }
16320bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
16330bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1634525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return doTransceive(mOpenEe.handle, data);
16350bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
16360bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1637bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1638c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public int getCardEmulationRoute(String pkg) throws RemoteException {
1639c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
164049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            return mEeRoutingState;
16410bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
16420bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
1643bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1644c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
1645c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
164649d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            mEeRoutingState = route;
1647525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            ApplyRoutingTask applyRoutingTask = new ApplyRoutingTask();
1648525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            applyRoutingTask.execute();
1649525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
1650525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Block until route is set
1651525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                applyRoutingTask.get();
1652525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (ExecutionException e) {
1653525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1654525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } catch (InterruptedException e) {
1655525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                Log.e(TAG, "failed to set card emulation mode");
1656525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
16570bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
1658bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
1659bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
1660c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton        public void authenticate(String pkg, byte[] token) throws RemoteException {
1661c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            NfcService.this.enforceNfceeAdminPerm(pkg);
1662bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1663525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1664525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
1665525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public String getDriverName(String pkg) throws RemoteException {
1666525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            NfcService.this.enforceNfceeAdminPerm(pkg);
1667525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            return mDeviceHost.getName();
1668525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1669c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
16700bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
167149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    /** resources kept while secure element is open */
167249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    private class OpenSecureElement implements IBinder.DeathRecipient {
167349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int pid;  // pid that opened SE
167492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // binder handle used for DeathReceipient. Must keep
167592250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // a reference to this, otherwise it can get GC'd and
167692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // the binder stub code might create a different BinderProxy
167792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // for the same remote IBinder, causing mismatched
167892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        // link()/unlink()
167992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public IBinder binder;
168049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public int handle; // low-level handle
168192250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public OpenSecureElement(int pid, int handle, IBinder binder) {
168249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.pid = pid;
168349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            this.handle = handle;
168492250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            this.binder = binder;
168549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        }
1686bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        @Override
168749d53329a0c720a7e430220d77805bc1763545b1Nick Pelly        public void binderDied() {
168849d53329a0c720a7e430220d77805bc1763545b1Nick Pelly            synchronized (NfcService.this) {
168992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                Log.i(TAG, "Tracked app " + pid + " died");
169049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly                pid = -1;
16910bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas                try {
169292250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    _nfcEeClose(-1, binder);
1693dfac80d25dd2816ad5af74cc4131b74134cc81b7Nick Pelly                } catch (IOException e) { /* already closed */ }
16940bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas            }
16950bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas        }
169692250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        @Override
169792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        public String toString() {
169892250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            return new StringBuilder('@').append(Integer.toHexString(hashCode())).append("[pid=")
169992250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly                    .append(pid).append(" handle=").append(handle).append("]").toString();
170092250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly        }
17010bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas    }
17020bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
17039a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    boolean isNfcEnabledOrShuttingDown() {
17049a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        synchronized (this) {
17059a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
17069a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        }
17079a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    }
17089a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen
170931949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
171031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
171131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1712e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1713aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1714aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
171531949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
1716a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        final Object mCancelWaiter = new Object();
1717525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        final int mTimeout;
1718a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        boolean mCanceled = false;
1719525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1720525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public WatchDogThread(String threadName, int timeout) {
1721525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            super(threadName);
1722525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mTimeout = timeout;
1723525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1724525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
17252edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
17262edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
1727a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            try {
1728a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                synchronized (mCancelWaiter) {
1729a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    mCancelWaiter.wait(mTimeout);
1730a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    if (mCanceled) {
1731a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                        return;
1732a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    }
17332edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
1734a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            } catch (InterruptedException e) {
1735a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                // Should not happen; fall-through to abort.
1736a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                Log.w(TAG, "Watchdog thread interruped.");
1737a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                interrupt();
17382edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
1739a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            Log.e(TAG, "Watchdog triggered, aborting.");
1740a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            mDeviceHost.doAbort();
17412edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
1742a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project
17432edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
1744a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            synchronized (mCancelWaiter) {
1745a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCanceled = true;
1746a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCancelWaiter.notify();
1747a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            }
17482edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
17492edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
17502edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
17519f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    static byte[] hexStringToBytes(String s) {
17529f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (s == null || s.length() == 0) return null;
17539f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        int len = s.length();
17549f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (len % 2 != 0) {
17559f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            s = '0' + s;
17569f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            len++;
17579f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
17589f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        byte[] data = new byte[len / 2];
17599f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        for (int i = 0; i < len; i += 2) {
17609f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
17619f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                                 + Character.digit(s.charAt(i+1), 16));
17629f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
17639f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        return data;
17649f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
17659f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1766fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /**
1767fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1768fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     */
1769fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    void applyRouting(boolean force) {
1770e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
17719a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            if (!isNfcEnabledOrShuttingDown() || mOpenEe != null) {
1772fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                // PN544 cannot be reconfigured while EE is open
1773e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1774e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1775525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
17767d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            if (mInProvisionMode) {
17777d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
17787d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
17797d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                if (!mInProvisionMode) {
17807d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Notify dispatcher it's fine to dispatch to any package now
17817d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // and allow handover transfers.
17827d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mNfcDispatcher.disableProvisioningMode();
17837d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mHandoverManager.setEnabled(true);
17847d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                }
17857d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            }
1786f439271150e4548f116919e0254d57655421581cMartijn Coenen            try {
1787f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.start();
1788f439271150e4548f116919e0254d57655421581cMartijn Coenen
1789525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (mDeviceHost.enablePN544Quirks() && mScreenState == SCREEN_STATE_OFF) {
1790f439271150e4548f116919e0254d57655421581cMartijn Coenen                    /* TODO undo this after the LLCP stack is fixed.
1791f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * Use a different sequence when turning the screen off to
1792f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * workaround race conditions in pn544 libnfc. The race occurs
1793f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * when we change routing while there is a P2P target connect.
1794f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * The async LLCP callback will crash since the routing code
1795f439271150e4548f116919e0254d57655421581cMartijn Coenen                     * is overwriting globals it relies on.
1796f439271150e4548f116919e0254d57655421581cMartijn Coenen                     */
1797f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (POLLING_MODE > SCREEN_STATE_OFF) {
1798f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfcPollingEnabled) {
1799f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-C OFF, disconnect");
1800f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfcPollingEnabled = false;
1801f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.disableDiscovery();
1802f439271150e4548f116919e0254d57655421581cMartijn Coenen                            maybeDisconnectTarget();
1803f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1804f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1805f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1806f439271150e4548f116919e0254d57655421581cMartijn Coenen                        if (force || mNfceeRouteEnabled) {
1807f439271150e4548f116919e0254d57655421581cMartijn Coenen                            Log.d(TAG, "NFC-EE OFF");
1808f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mNfceeRouteEnabled = false;
1809f439271150e4548f116919e0254d57655421581cMartijn Coenen                            mDeviceHost.doDeselectSecureElement();
1810f439271150e4548f116919e0254d57655421581cMartijn Coenen                        }
1811fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1812f439271150e4548f116919e0254d57655421581cMartijn Coenen                    return;
1813fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1814f439271150e4548f116919e0254d57655421581cMartijn Coenen
18150a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen                if (mIsHceCapable && mScreenState >= SCREEN_STATE_ON_LOCKED &&
1816d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mAidRoutingManager.aidsRoutedToHost()) {
1817d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    if (!mHostRouteEnabled || force) {
1818d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mHostRouteEnabled = true;
1819d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mDeviceHost.enableRoutingToHost();
1820d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    }
1821d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                } else {
1822d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    if (force || mHostRouteEnabled) {
1823d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mHostRouteEnabled = false;
1824d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                        mDeviceHost.disableRoutingToHost();
18259f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                    }
18269f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen                }
18279f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1828f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-EE routing
1829f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
1830f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1831f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfceeRouteEnabled) {
1832f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-EE ON");
1833f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfceeRouteEnabled = true;
1834f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.doSelectSecureElement();
1835f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1836f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1837f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force ||  mNfceeRouteEnabled) {
1838fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        Log.d(TAG, "NFC-EE OFF");
1839fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mNfceeRouteEnabled = false;
1840fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                        mDeviceHost.doDeselectSecureElement();
1841fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    }
1842fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1843fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1844f439271150e4548f116919e0254d57655421581cMartijn Coenen                // configure NFC-C polling
1845f439271150e4548f116919e0254d57655421581cMartijn Coenen                if (mScreenState >= POLLING_MODE) {
1846f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || !mNfcPollingEnabled) {
1847f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C ON");
1848f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = true;
1849f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.enableDiscovery();
1850f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
18517d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                } else if (mInProvisionMode && mScreenState >= SCREEN_STATE_ON_LOCKED) {
18527d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Special case for setup provisioning
18537d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    if (!mNfcPollingEnabled) {
18547d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Log.d(TAG, "NFC-C ON");
18557d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mNfcPollingEnabled = true;
18567d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        mDeviceHost.enableDiscovery();
18577d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    }
1858f439271150e4548f116919e0254d57655421581cMartijn Coenen                } else {
1859f439271150e4548f116919e0254d57655421581cMartijn Coenen                    if (force || mNfcPollingEnabled) {
1860f439271150e4548f116919e0254d57655421581cMartijn Coenen                        Log.d(TAG, "NFC-C OFF");
1861f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mNfcPollingEnabled = false;
1862f439271150e4548f116919e0254d57655421581cMartijn Coenen                        mDeviceHost.disableDiscovery();
1863f439271150e4548f116919e0254d57655421581cMartijn Coenen                    }
1864fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1865f439271150e4548f116919e0254d57655421581cMartijn Coenen            } finally {
1866f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.cancel();
1867221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
186865945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
186965945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
187065945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
18712436ffe91853535fad87b7a8e03d8883bae20f20Arnaud Ferir    /** Disconnect any target if present */
187231949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
18739a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        if (!isNfcEnabledOrShuttingDown()) {
1874a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1875a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
187631949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
187731949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
187831949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
187931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
188031949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
188131949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
188231949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
188331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
188431949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
188531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
188631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
188731949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
188831949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
188931949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
189031949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
189131949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
189231949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
189331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
189431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
189531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
189631949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
189731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
189831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1899bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1900bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1901bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1902bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1903bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
190431949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
190531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
190631949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
190731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
190831949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
19092f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
191031949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
19110e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1912f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1913f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
191431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
191531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
191631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1917f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1918b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1919b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
192031949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
192131949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
192231949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
192331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
1924f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1925f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1926d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
19274a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1928c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            throws LlcpException {
19294a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1930d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1931d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1932d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    /** For use by code in this process */
19333b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
1934e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen            throws LlcpException {
19353b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
1936e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    }
1937e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen
1938e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    /** For use by code in this process */
19394a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1940c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            int linearBufferLength) throws LlcpException {
19414a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1942d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1943d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
194457d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
1945b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
194657d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
194757d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
1948d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void routeAids(String aid, int route) {
1949d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        Message msg = mHandler.obtainMessage();
1950d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.what = MSG_ROUTE_AID;
1951d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.arg1 = route;
1952d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.obj = aid;
1953d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendMessage(msg);
1954d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1955d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
1956d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void unrouteAids(String aid) {
1957d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        sendMessage(MSG_UNROUTE_AID, aid);
1958d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1959d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
1960d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void commitRouting() {
1961d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
1962d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1963d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
19649f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen	public boolean sendData(byte[] data) {
19659f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen	    return mDeviceHost.sendRawFrame(data);
19669f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
19679f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1968b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
1969b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
1970b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
1971b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
1972b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
1973b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1974b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
19753fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
1976b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
1977b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
197831949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
1979d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_ROUTE_AID: {
1980d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    int route = msg.arg1;
1981d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
1982d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.routeAid(hexStringToBytes(aid), route);
1983d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    // Restart polling config
1984d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1985d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
1986d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_UNROUTE_AID: {
1987d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
1988d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.unrouteAid(hexStringToBytes(aid));
1989d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1990d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
1991d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_COMMIT_ROUTING: {
1992d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    applyRouting(true);
1993d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1994d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
199531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
199631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
199731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
199831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
199931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
200031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
200131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
200231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
200331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new int[] { TagTechnology.NDEF },
200431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            new Bundle[] { extras });
200531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
200631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
2007ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                    boolean delivered = mNfcDispatcher.dispatchTag(tag);
200831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (delivered) {
2009d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
201077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    } else {
2011d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
201231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
201331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
201431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
201557d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
201631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
201731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
201831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
2019d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    playSound(SOUND_START);
202089baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
202189baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // When these tags start containing NDEF, they will require
202289baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // the stack to deal with them in a different way, since
202389baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // they are activated only really shortly.
202489baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // For now, don't consider NDEF on these.
202589baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
202689baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        tag.startPresenceChecking();
202789baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        dispatchTagEndpoint(tag);
202889baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        break;
202989baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    }
2030391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    NdefMessage ndefMsg = tag.findAndReadNdef();
2031c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
2032391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    if (ndefMsg != null) {
203331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        tag.startPresenceChecking();
2034ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                        dispatchTagEndpoint(tag);
203531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
203631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
203731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.startPresenceChecking();
2038ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly                            dispatchTagEndpoint(tag);
203931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
204031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
2041d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
204231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
204331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
204431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
204531949217328bf2357ff044f0d18677fe588c790cNick Pelly
204631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_CARD_EMULATION:
204731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Emulation message");
204831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] aid = (byte[]) msg.obj;
204931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
205031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent aidIntent = new Intent();
205131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.setAction(ACTION_AID_SELECTED);
205231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    aidIntent.putExtra(EXTRA_AID, aid);
205331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
205414a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(aidIntent);
205531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
205631949217328bf2357ff044f0d18677fe588c790cNick Pelly
205731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_EMV_CARD_REMOVAL:
205831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Card Removal message");
205931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
206031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent cardRemovalIntent = new Intent();
206131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
206231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
206314a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(cardRemovalIntent);
206431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
206531949217328bf2357ff044f0d18677fe588c790cNick Pelly
206631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_APDU_RECEIVED:
206731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "APDU Received message");
206831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] apduBytes = (byte[]) msg.obj;
206931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
207031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent apduReceivedIntent = new Intent();
207131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
207231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (apduBytes != null && apduBytes.length > 0) {
207331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
207431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
207531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
207614a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(apduReceivedIntent);
207731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
207831949217328bf2357ff044f0d18677fe588c790cNick Pelly
207931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_MIFARE_ACCESS:
208031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "MIFARE access message");
208131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Send broadcast */
208231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    byte[] mifareCmd = (byte[]) msg.obj;
208331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent mifareAccessIntent = new Intent();
208431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
208531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mifareCmd != null && mifareCmd.length > 1) {
208631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        int mifareBlock = mifareCmd[1] & 0xff;
208731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
208831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
208931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
209031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
209114a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(mifareAccessIntent);
209231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
2093c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
209431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
209596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
209696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent actIntent = new Intent(ACTION_LLCP_UP);
209796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(actIntent);
209896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
209931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
210031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
210131949217328bf2357ff044f0d18677fe588c790cNick Pelly
210231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
210396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
210496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
210596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(deactIntent);
210696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
210731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
210831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
210931949217328bf2357ff044f0d18677fe588c790cNick Pelly
211031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
211131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
211231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
211331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
211431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
211531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
211631949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
211731949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
211831949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
211931949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
212031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
212131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
212231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
212331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
212431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
212531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
212631949217328bf2357ff044f0d18677fe588c790cNick Pelly
212777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
212831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
212957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                case MSG_LLCP_LINK_FIRST_PACKET:
213057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    mP2pLinkManager.onLlcpFirstPacketReceived();
213157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    break;
213231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_TARGET_DESELECTED:
213331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    /* Broadcast Intent Target Deselected */
213431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Target Deselected");
213531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent intent = new Intent();
213631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
213731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Broadcasting Intent");
213831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
213931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
214031949217328bf2357ff044f0d18677fe588c790cNick Pelly
214131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_ACTIVATED: {
214231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
214331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOnIntent = new Intent();
214431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
214514a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOnIntent);
214631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
214731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
214831949217328bf2357ff044f0d18677fe588c790cNick Pelly
214931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_SE_FIELD_DEACTIVATED: {
215031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
215131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Intent eventFieldOffIntent = new Intent();
215231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
215314a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton                    sendSeBroadcast(eventFieldOffIntent);
215431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
215531949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
215631949217328bf2357ff044f0d18677fe588c790cNick Pelly
2157525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_ACTIVATED: {
2158525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE ACTIVATED");
2159525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeActivated = new Intent();
2160525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeActivated.setAction(ACTION_SE_LISTEN_ACTIVATED);
2161525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeActivated);
2162525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
2163525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2164525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
2165525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                case MSG_SE_LISTEN_DEACTIVATED: {
2166525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    if (DBG) Log.d(TAG, "SE LISTEN MODE DEACTIVATED");
2167525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Intent listenModeDeactivated = new Intent();
2168525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    listenModeDeactivated.setAction(ACTION_SE_LISTEN_DEACTIVATED);
2169525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    sendSeBroadcast(listenModeDeactivated);
2170525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    break;
2171525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
217231949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
217331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
217431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
217531949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
2176b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
2177d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
217814a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        private void sendSeBroadcast(Intent intent) {
217914a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
2180c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            // Resume app switches so the receivers can start activites without delay
2181c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfcDispatcher.resumeAppSwitches();
2182c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
2183e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen            synchronized(this) {
2184e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                for (PackageInfo pkg : mInstalledPackages) {
2185e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (pkg != null && pkg.applicationInfo != null) {
2186e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
2187e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            intent.setPackage(pkg.packageName);
2188e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            mContext.sendBroadcast(intent);
2189e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        }
2190c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                    }
2191c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton                }
2192c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            }
219314a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton        }
219414a4b124592b50dcec47d9b07232fff0188a4e02Jeff Hamilton
2195d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
2196d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
2197d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2198d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
2199d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
2200d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
2201d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
2202d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
2203d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
2204d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
2205d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
220631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
220731949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
220831949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
2209d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
221077d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                            mP2pLinkManager.onLlcpActivated();
2211d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
2212d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
2213d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
2214d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
2215d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
2216d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
2217d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
2218d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
2219d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
2220d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2221d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2222d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
2223d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
2224d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
2225d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
2226d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
2227d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2228d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
2229d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
2230d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
2231d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
2232d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
2233d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
2234d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
223531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
223631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
223731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
2238d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
223977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
2240d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
2241d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
2242d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
2243d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
2244d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
2245d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
2246d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2247d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
2248d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
2249d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
2250ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        private void dispatchTagEndpoint(TagEndpoint tagEndpoint) {
2251f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
2252f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
2253f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
2254ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            if (!mNfcDispatcher.dispatchTag(tag)) {
2255f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
2256d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
2257d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else {
2258d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
22593fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
22603fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
2261b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
2262b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
2263b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
226449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
2265fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
2266fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
2267fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        protected Void doInBackground(Integer... params) {
2268fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            synchronized (NfcService.this) {
2269fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (params == null || params.length != 1) {
2270fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    // force apply current routing
2271fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    applyRouting(true);
2272fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    return null;
2273161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2274fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                mScreenState = params[0].intValue();
2275fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
2276525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
2277525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2278525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    applyRouting(false);
2279525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
2280525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
2281161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
2282fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return null;
22837c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
22847c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
22857c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
22867c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
2287525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
22880e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        @Override
22890e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public void onReceive(Context context, Intent intent) {
229031949217328bf2357ff044f0d18677fe588c790cNick Pelly            String action = intent.getAction();
2291525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
2292e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
2293e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
2294e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
2295e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                updatePackageCache();
2296e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2297e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
2298e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    // Clear the NFCEE access cache in case a UID gets recycled
2299e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    mNfceeAccessControl.invalidateCache();
2300e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen
2301e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
2302e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                    if (dataRemoved) {
2303e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        Uri data = intent.getData();
2304e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        if (data == null) return;
2305e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        String packageName = data.getSchemeSpecificPart();
23067a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton
2307e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                        synchronized (NfcService.this) {
2308e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            if (mSePackages.contains(packageName)) {
2309e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                new EnableDisableTask().execute(TASK_EE_WIPE);
2310e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                                mSePackages.remove(packageName);
2311e288a8c852ad826efcb2ef5a318394974918209dMartijn Coenen                            }
23127a7f8f8fd82936f0ee005ccfa7ac5c36760ed902Jeff Hamilton                        }
2313bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                    }
2314bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
2315525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
2316525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                EnableDisableTask eeWipeTask = new EnableDisableTask();
2317525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                eeWipeTask.execute(TASK_EE_WIPE);
2318525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
2319525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    eeWipeTask.get();  // blocks until EE wipe is complete
2320525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (ExecutionException e) {
2321525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2322525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } catch (InterruptedException e) {
2323525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    Log.w(TAG, "failed to wipe NFC-EE");
2324525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2325525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            }
2326525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
2327525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    };
2328525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
2329525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2330525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
2331525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public void onReceive(Context context, Intent intent) {
2332525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            String action = intent.getAction();
2333525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            if (action.equals(
2334525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
2335525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2336525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute();
2337525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } else if (action.equals(Intent.ACTION_SCREEN_ON)
2338525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_SCREEN_OFF)
2339525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_USER_PRESENT)) {
2340525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
2341525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                int screenState = SCREEN_STATE_OFF;
2342525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
2343525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_OFF;
2344525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
2345525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = mKeyguard.isKeyguardLocked() ?
2346525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                            SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
2347525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
2348525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    screenState = SCREEN_STATE_ON_UNLOCKED;
2349525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
2350525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
235131949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
235231949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
235331949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
235431949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
235531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
235631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
235731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
235831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
235931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
236031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
23611668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
23621668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
236331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
236431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
236531949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
236631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
236731949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
23683859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
23693859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen                mP2pLinkManager.onUserSwitched();
2370f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
2371f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
2372f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
237331949217328bf2357ff044f0d18677fe588c790cNick Pelly
237431949217328bf2357ff044f0d18677fe588c790cNick Pelly    /** Returns true if airplane mode is currently on */
237531949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
23767d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        return Settings.System.getInt(mContentResolver,
23777d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
237831949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
237931949217328bf2357ff044f0d18677fe588c790cNick Pelly
2380fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** for debugging only - no i18n */
238131949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
238231949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
238331949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
238431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
238531949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
238631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
238731949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
238831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
238931949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
239031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
239131949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
239231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
239331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
239431949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
239531949217328bf2357ff044f0d18677fe588c790cNick Pelly
2396fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /** For debugging only - no i18n */
2397fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    static String screenStateToString(int screenState) {
2398fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        switch (screenState) {
2399fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_OFF:
2400fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "OFF";
2401fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_LOCKED:
2402fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_LOCKED";
2403fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            case SCREEN_STATE_ON_UNLOCKED:
2404fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "ON_UNLOCKED";
2405fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            default:
2406fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return "UNKNOWN";
2407fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        }
2408fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    }
2409fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
241031949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
241150effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
241250effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
241350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
241450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
241550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
241650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
241750effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
241850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
241931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
242031949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
24210b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
2422fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mScreenState=" + screenStateToString(mScreenState));
2423fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfcPollingEnabled=" + mNfcPollingEnabled);
2424fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            pw.println("mNfceeRouteEnabled=" + mNfceeRouteEnabled);
242531949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
242631949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
242792250f5cc5e34549985c31a053feff85b21c60c0Nick Pelly            pw.println("mOpenEe=" + mOpenEe);
242877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
2429c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton            mNfceeAccessControl.dump(fd, pw, args);
2430391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            mNfcDispatcher.dump(fd, pw, args);
243156f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
2432c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton
243331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
243431949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
243574180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
2436