NfcService.java revision b82d80d891077ccd74729e4143925a66eb89eef2
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
19efb7a3df560585994cebd40fcf5ffbc864f8c358Martijn Coenenimport android.app.ActivityManager;
202f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pellyimport android.app.Application;
21275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parksimport android.app.KeyguardManager;
2205973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamiltonimport android.app.PendingIntent;
23b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franzimport android.app.admin.DevicePolicyManager;
2413d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.BroadcastReceiver;
25a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenenimport android.content.ComponentName;
2631949217328bf2357ff044f0d18677fe588c790cNick Pellyimport android.content.ContentResolver;
2713d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Context;
2813d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.Intent;
2913d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.content.IntentFilter;
300e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.content.SharedPreferences;
31b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franzimport android.content.pm.IPackageManager;
32c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenenimport android.content.pm.PackageInfo;
3393d8a69ccadfa01b0a5ec3d7edeb921a1da4bce8Jeff Hamiltonimport android.content.pm.PackageManager;
34b42756d47f39774a07654f68af27bf3cc2c41511Andres Moralesimport android.content.pm.UserInfo;
357d8987f233985a5ff29226890e11012275d325f5Martijn Coenenimport android.content.res.Resources.NotFoundException;
36d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.AudioManager;
37d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport android.media.SoundPool;
389340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenenimport android.nfc.BeamShareData;
39f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.ErrorCodes;
40f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.FormatException;
4131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenenimport android.nfc.IAppCallback;
420e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.INfcAdapter;
4349d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.nfc.INfcAdapterExtras;
44a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenenimport android.nfc.INfcCardEmulation;
45f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.INfcTag;
4616ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Moralesimport android.nfc.INfcUnlockHandler;
47f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NdefMessage;
48f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.nfc.NfcAdapter;
490e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pellyimport android.nfc.Tag;
5024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamiltonimport android.nfc.TechListParcel;
519d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenenimport android.nfc.TransceiveResult;
52aca0d055a82da850c27f6872405602ad5f3fee7bJeff Hamiltonimport android.nfc.tech.Ndef;
5381c476dd93f059d4082c15369894d5d16fbea05dJeff Hamiltonimport android.nfc.tech.TagTechnology;
547c034a7fe7d36b1ab039af2c44717812ea02657eNick Pellyimport android.os.AsyncTask;
5550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Rootimport android.os.Binder;
5696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenenimport android.os.Build;
57b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamiltonimport android.os.Bundle;
58b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Handler;
5949d53329a0c720a7e430220d77805bc1763545b1Nick Pellyimport android.os.IBinder;
60b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneauimport android.os.Message;
61533043d1003de2f6a20a29201100d94c3c7bc9caNick Pellyimport android.os.PowerManager;
624467dca5650a170af5020c10a8ccb25f86f1007fNick Pellyimport android.os.Process;
63f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.os.RemoteException;
6413d8819d9d716c8f0ba03288d058f0bd462d70a7Nick Pellyimport android.os.ServiceManager;
65525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.os.UserHandle;
665c452dad7b24f28223414ce5e953bfcab782570eAndres Moralesimport android.os.UserManager;
67d11251b2d1fed7b7325c4fcb0616b2d1c654320fMartijn Coenenimport android.provider.Settings;
68f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pellyimport android.util.Log;
699340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
704309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesimport com.android.nfc.DeviceHost.DeviceHostListener;
714309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesimport com.android.nfc.DeviceHost.LlcpConnectionlessSocket;
724309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesimport com.android.nfc.DeviceHost.LlcpServerSocket;
734309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesimport com.android.nfc.DeviceHost.LlcpSocket;
744309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesimport com.android.nfc.DeviceHost.NfcDepEndpoint;
754309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesimport com.android.nfc.DeviceHost.TagEndpoint;
76af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenenimport com.android.nfc.cardemulation.CardEmulationManager;
774309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesimport com.android.nfc.dhimpl.NativeNfcManager;
78b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.handover.HandoverDataParser;
794309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales
8031949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.FileDescriptor;
8131949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.io.PrintWriter;
8231949217328bf2357ff044f0d18677fe588c790cNick Pellyimport java.util.Arrays;
833ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamiltonimport java.util.HashMap;
84c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenenimport java.util.List;
8528a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Moralesimport java.util.Map;
86c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenenimport java.util.NoSuchElementException;
873ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
88525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectpublic class NfcService implements DeviceHostListener {
89c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = false;
9076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
91fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
92d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
93fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
9477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
95f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
96416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
97416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
98416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
99416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
100416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
101416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
1021668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
103a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
104b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
105c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_LLCP_LINK_ACTIVATION = 1;
106c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_LLCP_LINK_DEACTIVATED = 2;
107c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_MOCK_NDEF = 3;
108c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_LLCP_LINK_FIRST_PACKET = 4;
109c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_ROUTE_AID = 5;
110c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_UNROUTE_AID = 6;
111c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_COMMIT_ROUTING = 7;
112c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_INVOKE_BEAM = 8;
113c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_RF_FIELD_ACTIVATED = 9;
114c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_RF_FIELD_DEACTIVATED = 10;
115e276d3323d755d8bdaccd59a551332c064970215Andres Morales    static final int MSG_RESUME_POLLING = 11;
11642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
11742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales    static final long MAX_POLLING_PAUSE_TIMEOUT = 40000;
118b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
11931949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
12031949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
12131949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
122c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
123a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    // Polling technology masks
124a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_A = 0x01;
125a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_B = 0x02;
126a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_F = 0x04;
127a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_ISO15693 = 0x08;
128a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_B_PRIME = 0x10;
129a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_KOVIO = 0x20;
130fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1310799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales    // minimum screen state that enables NFC polling
1320799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales    static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1330799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales
134525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for NFC controller to initialize before watchdog
135525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off. This time is chosen large, because firmware download
136525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // may be a part of initialization.
137525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int INIT_WATCHDOG_MS = 90000;
138525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
139525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for routing to be applied before watchdog
140525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off
141525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int ROUTING_WATCHDOG_MS = 10000;
142525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
14331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    // Default delay used for presence checks
14431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    static final int DEFAULT_PRESENCE_CHECK_DELAY = 125;
14531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
14634322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    // The amount of time we wait before manually launching
14734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    // the Beam animation when called through the share menu.
14834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    static final int INVOKE_BEAM_DELAY_MS = 1000;
14934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen
150c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    // RF field events as defined in NFC extras
151c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    public static final String ACTION_RF_FIELD_ON_DETECTED =
152c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
153c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    public static final String ACTION_RF_FIELD_OFF_DETECTED =
154c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
155c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
156d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
157d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
158d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
159d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
160d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
16196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_UP =
16296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_UP";
16396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
16496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_DOWN =
16596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_DOWN";
16696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
16742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales    // Timeout to re-apply routing if a tag was present and we postponed it
16842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales    private static final int APPLY_ROUTING_RETRY_TIMEOUT_MS = 5000;
16942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
1705c452dad7b24f28223414ce5e953bfcab782570eAndres Morales    private final UserManager mUserManager;
1715c452dad7b24f28223414ce5e953bfcab782570eAndres Morales
17249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
17349d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
174c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    private final ReaderModeDeathRecipient mReaderModeDeathRecipient =
175c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            new ReaderModeDeathRecipient();
17616ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales    private final NfcUnlockManager mNfcUnlockManager;
1770bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
178c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    private final NfceeAccessControl mNfceeAccessControl;
179c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
180c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    List<PackageInfo> mInstalledPackages; // cached version of installed packages
181c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
1822f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
183fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
184fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int mScreenState;
1857d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
186fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mIsNdefPushEnabled;
187ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen    NfcDiscoveryParameters mCurrentDiscoveryParameters =
188ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen            NfcDiscoveryParameters.getNfcOffParameters();
18928a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
19031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    ReaderModeParams mReaderModeParams;
19131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
19231949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
19331949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
19431949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
19531949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
1962f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
19705973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
1984a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
1990e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
2000e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
201525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mRoutingWakeLock;
202525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
203d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
204d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
205d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
206d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
20777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
2084a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
2094a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
21031949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
21131949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
21296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    boolean mIsDebugBuild;
2130a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen    boolean mIsHceCapable;
21442c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales    boolean mPollingPaused;
2152ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
21676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
217fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    private PowerManager mPowerManager;
218275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
219b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private HandoverDataParser mHandoverDataParser;
2207d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private ContentResolver mContentResolver;
221af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen    private CardEmulationManager mCardEmulationManager;
22228a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
2234309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    private ScreenStateHelper mScreenStateHelper;
22434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    private ForegroundUtils mForegroundUtils;
225d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
22628a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales    private int mUserId;
2274309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    private static NfcService sService;
22889c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen
229d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
230d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
231d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
232f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2330e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
234f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
235f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
236f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
237f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
238f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
239f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
240f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
241d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
2429f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationActivated() {
243af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen        if (mCardEmulationManager != null) {
244af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen            mCardEmulationManager.onHostCardEmulationActivated();
2450a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
2469f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
2479f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
2489f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
2499f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationData(byte[] data) {
250af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen        if (mCardEmulationManager != null) {
251af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen            mCardEmulationManager.onHostCardEmulationData(data);
2520a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
2539f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
2549f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
2559f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
2569f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationDeactivated() {
257af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen        if (mCardEmulationManager != null) {
258af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen            mCardEmulationManager.onHostCardEmulationDeactivated();
2590a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
2609f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
2619f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
2629f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    /**
263f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
264f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
265f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
266f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
267f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
268f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
269f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
270f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
271f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
272f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
273d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
274f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
275f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
276f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
277f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
27857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    /**
27957a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     * Notifies P2P Device detected, first packet received over LLCP link
28057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     */
28157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    @Override
28257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
28357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
28457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    }
28557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
286c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    @Override
287c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    public void onRemoteFieldActivated() {
288c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        sendMessage(NfcService.MSG_RF_FIELD_ACTIVATED, null);
289c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    }
290c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
291c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    public void onRemoteFieldDeactivated() {
292c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        sendMessage(NfcService.MSG_RF_FIELD_DEACTIVATED, null);
293c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    }
294c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
29531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    final class ReaderModeParams {
29631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public int flags;
29731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public IAppCallback callback;
29831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public int presenceCheckDelay;
29931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    }
30031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
301525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public NfcService(Application nfcApplication) {
302d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales        mUserId = ActivityManager.getCurrentUser();
3034309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        mContext = nfcApplication;
3044309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales
3054a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
3064a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
3072f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
3082f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
309d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
310d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
3114309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        mScreenStateHelper = new ScreenStateHelper(mContext);
3127d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mContentResolver = mContext.getContentResolver();
313525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDeviceHost = new NativeNfcManager(mContext, this);
31474180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
31516ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        mNfcUnlockManager = NfcUnlockManager.getInstance();
31616ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
317b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mHandoverDataParser = new HandoverDataParser();
3187d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        boolean isNfcProvisioningEnabled = false;
3197d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        try {
3207d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
3217d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    R.bool.enable_nfc_provisioning);
3227d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } catch (NotFoundException e) {
3237d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
3247d8987f233985a5ff29226890e11012275d325f5Martijn Coenen
3257d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        if (isNfcProvisioningEnabled) {
3267d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
3277d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
3287d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } else {
3297d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = false;
3307d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
331525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
332b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, mInProvisionMode);
333b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverDataParser,
334525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
33524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
336525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
3370e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
338f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
339c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        mNfceeAccessControl = new NfceeAccessControl(mContext);
340c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
34131949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
3420b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
343a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen        setBeamShareActivityState(mIsNdefPushEnabled);
344f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
34596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
34696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
347525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
348525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
349525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mRoutingWakeLock = mPowerManager.newWakeLock(
3504309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
351275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
352525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
3535c452dad7b24f28223414ce5e953bfcab782570eAndres Morales        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
3545c452dad7b24f28223414ce5e953bfcab782570eAndres Morales
3554309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        mScreenState = mScreenStateHelper.checkScreenState();
356533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
357d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
358f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
359525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents for all users
360c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
36165945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
362275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
3633859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        filter.addAction(Intent.ACTION_USER_SWITCHED);
36431949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
365525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
3660e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
367c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        IntentFilter ownerFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
368c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
369c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
370c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
371c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter = new IntentFilter();
372c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
373c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
374c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter.addDataScheme("package");
375c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
376c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
377b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        IntentFilter policyFilter = new IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
378b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        mContext.registerReceiverAsUser(mPolicyReceiver, UserHandle.ALL, policyFilter, null, null);
379b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz
380c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        updatePackageCache();
381c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
3820a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        PackageManager pm = mContext.getPackageManager();
383341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen        mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
3840a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mIsHceCapable) {
385af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen            mCardEmulationManager = new CardEmulationManager(mContext);
386a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        }
38734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        mForegroundUtils = ForegroundUtils.getInstance();
38831949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
38931949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
39031949217328bf2357ff044f0d18677fe588c790cNick Pelly
391d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
3924309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        synchronized (this) {
393d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
394d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
395525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
396525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
397525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
398d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
399d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
400d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
401d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
402d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
4034309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        synchronized (this) {
404d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
405d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
406d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
407d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
408d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
409d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
410d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
41131949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
4127d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
4137d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_RADIOS);
4147d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String toggleableRadios = Settings.System.getString(mContentResolver,
4157d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
41631949217328bf2357ff044f0d18677fe588c790cNick Pelly
41731949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
4187d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
41931949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
4204309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                toggleableRadios.contains(Settings.Global.RADIO_NFC);
42131949217328bf2357ff044f0d18677fe588c790cNick Pelly
42231949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
42331949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
42431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
42531949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
42631949217328bf2357ff044f0d18677fe588c790cNick Pelly
427c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    void updatePackageCache() {
428c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        PackageManager pm = mContext.getPackageManager();
429c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
430c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        synchronized (this) {
431c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            mInstalledPackages = packages;
432c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        }
433c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    }
434c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
43531949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
43631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
4374309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * <p/>
43831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
43931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
44031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
44131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
4424309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * <p/>
44331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
44431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
44531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
44631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
44731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
44831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
4494309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * <p/>
45031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
45131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
45231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
45331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
45431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
4554309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * <p/>
45631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
45731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
45831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
45931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
46031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
46131949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
46231949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
46331949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
46431949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
46531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
46631949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
46731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
46831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
46931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
47031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
47131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
47231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
47331949217328bf2357ff044f0d18677fe588c790cNick Pelly
4744467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
4754467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
4764467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
4774467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
4784467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
4794467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
4804467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
4814467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
4824467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
48331949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
48431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
48531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
48631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
48731949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
48831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
48931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
49031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
4914309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    Log.d(TAG, "checking on firmware download");
4921668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
49331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
4941668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
4954309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                        Log.d(TAG, "NFC is on. Doing normal stuff");
49631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
4970fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
4984309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                        Log.d(TAG, "NFC is off.  Checking firmware version");
4990fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
50031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
50131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
50231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
50331949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
50431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
50531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
50631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
50731949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
508d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
509d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
510d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
51131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
51231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
51331949217328bf2357ff044f0d18677fe588c790cNick Pelly
51431949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
51531949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
51631949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
51731949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
51831949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
51931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
52031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
52131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
52231949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
52331949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
52431949217328bf2357ff044f0d18677fe588c790cNick Pelly
525525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
526525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            watchDog.start();
527525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
528525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
529525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
530304a6342ee7e5620d3b50d988755c035f1686dc2Martijn Coenen                    if (!mDeviceHost.initialize()) {
531525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.w(TAG, "Error enabling NFC");
532525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        updateState(NfcAdapter.STATE_OFF);
533525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        return false;
534525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
535525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
536525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
537525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
538525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
539525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                watchDog.cancel();
54031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
54131949217328bf2357ff044f0d18677fe588c790cNick Pelly
5420a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            if (mIsHceCapable) {
5430a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen                // Generate the initial card emulation routing table
544af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen                mCardEmulationManager.onNfcEnabled();
5450a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            }
546d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
5474309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            synchronized (NfcService.this) {
54831949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
5490b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
55031949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
55131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
55231949217328bf2357ff044f0d18677fe588c790cNick Pelly
553d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
554d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
55531949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
5560c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
557fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
55831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
55931949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
56031949217328bf2357ff044f0d18677fe588c790cNick Pelly
56131949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
56231949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
56331949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
56431949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
56531949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
56631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
56731949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
56831949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
56931949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
57031949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
57131949217328bf2357ff044f0d18677fe588c790cNick Pelly
57231949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
57331949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
57431949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
57531949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
576525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
57731949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
57831949217328bf2357ff044f0d18677fe588c790cNick Pelly
579953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            if (mIsHceCapable) {
580af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen                mCardEmulationManager.onNfcDisabled();
581953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            }
582d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
58377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
58431949217328bf2357ff044f0d18677fe588c790cNick Pelly
58531949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
58631949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
58731949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
58831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
58931949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
59031949217328bf2357ff044f0d18677fe588c790cNick Pelly
5910b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
59231949217328bf2357ff044f0d18677fe588c790cNick Pelly
593ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen
59431949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
59531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
59631949217328bf2357ff044f0d18677fe588c790cNick Pelly
59731949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
59831949217328bf2357ff044f0d18677fe588c790cNick Pelly
599ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen            synchronized (NfcService.this) {
600ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen                mCurrentDiscoveryParameters = NfcDiscoveryParameters.getNfcOffParameters();
601ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen                updateState(NfcAdapter.STATE_OFF);
602ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen            }
60331949217328bf2357ff044f0d18677fe588c790cNick Pelly
604d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
605d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
60631949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
60731949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
60831949217328bf2357ff044f0d18677fe588c790cNick Pelly
60931949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
6102a3f6f141fdaf746a81ce850a8ab0ef251041966mike wakerly            synchronized (NfcService.this) {
61131949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
61231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
61331949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
61431949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
61531949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
61631949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
61731949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
618525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
61931949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
62031949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
62131949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
62231949217328bf2357ff044f0d18677fe588c790cNick Pelly
62331949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
62431949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
62531949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
62631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
62731949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
6280e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
6290e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
630d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
631d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
632d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
633d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
634d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
635d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
636d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
637d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
638d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
639d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
640d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
641d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
642d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
643d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
644d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
645d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
646d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
647d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
648d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
649d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
650d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales    synchronized int getUserId() {
651d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales        return mUserId;
652d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales    }
653d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales
654a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen    void setBeamShareActivityState(boolean enabled) {
655b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
656b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        // Propagate the state change to all user profiles related to the current
657b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        // user. Note that the list returned by getUserProfiles contains the
658b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        // current user.
659b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        List <UserHandle> luh = um.getUserProfiles();
660b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        for (UserHandle uh : luh){
661b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            enforceBeamShareActivityPolicy(mContext, uh, enabled);
662b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        }
663b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz    }
664b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz
665b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz    void enforceBeamShareActivityPolicy(Context context, UserHandle uh,
666b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            boolean isGlobalEnabled){
667b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
668b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        IPackageManager mIpm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
669b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        boolean isActiveForUser =
670b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                (!um.hasUserRestriction(UserManager.DISALLOW_OUTGOING_BEAM, uh)) &&
671b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                isGlobalEnabled;
672b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        if (DBG){
673b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            Log.d(TAG, "Enforcing a policy change on user: " + uh +
674b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    ", isActiveForUser = " + isActiveForUser);
675b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        }
676b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        try {
677b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            mIpm.setComponentEnabledSetting(new ComponentName(
678b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    BeamShareActivity.class.getPackageName$(),
679b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    BeamShareActivity.class.getName()),
680b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    isActiveForUser ?
681b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
682b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
683b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                            PackageManager.DONT_KILL_APP,
684b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    uh.getIdentifier());
685b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        } catch (RemoteException e) {
686b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            Log.w(TAG, "Unable to change Beam status for user " + uh);
687b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        }
688a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen    }
6890e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
6904a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
691fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
6920e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
6934309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
6940e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
69531949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
6961668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen
6971668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
6981668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                if (!mIsAirplaneToggleable) {
6991668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    Log.i(TAG, "denying enable() request (airplane mode)");
7001668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    return false;
7011668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                }
7021668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                // Make sure the override survives a reboot
7031668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
7041668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
705f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
70631949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
70731949217328bf2357ff044f0d18677fe588c790cNick Pelly
70831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
709f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
710f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
711fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
712290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi        public boolean disable(boolean saveState) throws RemoteException {
7134309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
7140e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
715290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            if (saveState) {
716290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi                saveNfcOnSetting(false);
717290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            }
718290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi
71931949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
72031949217328bf2357ff044f0d18677fe588c790cNick Pelly
72131949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
722f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
723f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
724dbcee970ef57927e73c269f573d06e2f133a34c1Martijn Coenen        @Override
72542c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales        public void pausePolling(int timeoutInMs) {
72642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
72742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
72842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            if (timeoutInMs <= 0 || timeoutInMs > MAX_POLLING_PAUSE_TIMEOUT) {
72942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                Log.e(TAG, "Refusing to pause polling for " + timeoutInMs + "ms.");
73042c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                return;
73142c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            }
73242c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
73342c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            synchronized (NfcService.this) {
73442c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mPollingPaused = true;
73542c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mDeviceHost.disableDiscovery();
73642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mHandler.sendMessageDelayed(
73742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                        mHandler.obtainMessage(MSG_RESUME_POLLING), timeoutInMs);
73842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            }
73942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales        }
74042c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
741dbcee970ef57927e73c269f573d06e2f133a34c1Martijn Coenen        @Override
74242c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales        public void resumePolling() {
74342c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
74442c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
74542c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            synchronized (NfcService.this) {
74642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                if (!mPollingPaused) {
74742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                    return;
74842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                }
74942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
75042c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mHandler.removeMessages(MSG_RESUME_POLLING);
75142c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mPollingPaused = false;
75242c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                new ApplyRoutingTask().execute();
75342c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            }
75442c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales        }
75542c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
756fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
7570b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
75831949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
7599993a5a96a862cea4512509b413d0de6cacb7c14Nick Pelly                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
76031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
761d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
762d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
763d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
7640b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
7654309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
7664309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            synchronized (NfcService.this) {
7670b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
76831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
76931949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
7700b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
7710b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
77231949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
7730b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
774a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen                setBeamShareActivityState(true);
77531949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
77677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
777d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
778d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
779d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
780d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
781d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
782d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
7830b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
7844309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
7854309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            synchronized (NfcService.this) {
7860b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
78731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
78831949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
7890b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
7900b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
79131949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
7920b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
793a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen                setBeamShareActivityState(false);
79431949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
79577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
796d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
797d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
798d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
799d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
800d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
801d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
8020b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
80324dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
8044309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
805a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
8060b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
8070b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
8080b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
8090b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
810ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
811a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
812a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
813a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
814a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
815a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
816a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
817a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
818a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
819a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
820a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
821a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
822a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
823a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
824a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
82524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
82624dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
82724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
82824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
82924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
83049d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
8310b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
8322094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
8332094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
8349340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8352094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
83631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public void setAppCallback(IAppCallback callback) {
8374309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
8385c452dad7b24f28223414ce5e953bfcab782570eAndres Morales
839b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales            // don't allow Beam for managed profiles, or devices with a device owner or policy owner
840b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales            UserInfo userInfo = mUserManager.getUserInfo(UserHandle.getCallingUserId());
84165860bb589c5802ffadb14540670408d6c8dfaa9Benjamin Franz            if(!mUserManager.hasUserRestriction(
842b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales                            UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle())) {
8435c452dad7b24f28223414ce5e953bfcab782570eAndres Morales                mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
844b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales            } else if (DBG) {
845b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales                Log.d(TAG, "Disabling default Beam behavior");
8465c452dad7b24f28223414ce5e953bfcab782570eAndres Morales            }
847ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
848ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
849ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
8509340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        public void invokeBeam() {
8519340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            NfcPermissions.enforceUserPermissions(mContext);
8529340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
85334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            if (mForegroundUtils.isInForeground(Binder.getCallingUid())) {
8549340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                mP2pLinkManager.onManualBeamInvoke(null);
8559340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            } else {
8569340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                Log.e(TAG, "Calling activity not in foreground.");
8579340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            }
8589340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        }
8599340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8609340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        @Override
86134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        public void invokeBeamInternal(BeamShareData shareData) {
86234322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            NfcPermissions.enforceAdminPermissions(mContext);
86334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            Message msg = Message.obtain();
86434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            msg.what = MSG_INVOKE_BEAM;
86534322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            msg.obj = shareData;
86634322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            // We have to send this message delayed for two reasons:
86734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            // 1) This is an IPC call from BeamShareActivity, which is
86834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    running when the user has invoked Beam through the
86934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    share menu. As soon as BeamShareActivity closes, the UI
87034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    will need some time to rebuild the original Activity.
87134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    Waiting here for a while gives a better chance of the UI
87234322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    having been rebuilt, which means the screenshot that the
87334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    Beam animation is using will be more accurate.
87434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            // 2) Similarly, because the Activity that launched BeamShareActivity
87534322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    with an ACTION_SEND intent is now in paused state, the NDEF
87634322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    callbacks that it has registered may no longer be valid.
87734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    Allowing the original Activity to resume will make sure we
87834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    it has a chance to re-register the NDEF message / callback,
87934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    so we share the right data.
88034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //
88134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    Note that this is somewhat of a hack because the delay may not actually
88234322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    be long enough for 2) on very slow devices, but there's no better
88334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    way to do this right now without additional framework changes.
88434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            mHandler.sendMessageDelayed(msg, INVOKE_BEAM_DELAY_MS);
88534322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        }
88634322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen
88734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        @Override
8880e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
8890e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
8900e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
8910e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
892fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
893a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public INfcCardEmulation getNfcCardEmulationInterface() {
89435b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen            if (mIsHceCapable) {
89535b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen                return mCardEmulationManager.getNfcCardEmulationInterface();
89635b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen            } else {
89735b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen                return null;
89835b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen            }
899a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
900a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
901a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
90231949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
90331949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
90431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
90531949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
90631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
90731949217328bf2357ff044f0d18677fe588c790cNick Pelly
90831949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
90931949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
91031949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
9110e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
912391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly
913391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        @Override
914ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        public void dispatch(Tag tag) throws RemoteException {
9154309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
916ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            mNfcDispatcher.dispatchTag(tag);
917391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        }
9180c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
9190c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        @Override
9200c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
9214309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
9220c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pInitiatorModes(initiatorModes);
9230c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pTargetModes(targetModes);
9240799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            applyRouting(true);
9250c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        }
926c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
927c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        @Override
92831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public void setReaderMode(IBinder binder, IAppCallback callback, int flags, Bundle extras)
92931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                throws RemoteException {
930c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            synchronized (NfcService.this) {
931c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                if (flags != 0) {
932c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    try {
93331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams = new ReaderModeParams();
93431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.callback = callback;
93531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.flags = flags;
9364309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                        mReaderModeParams.presenceCheckDelay = extras != null
9374309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                                ? (extras.getInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY,
9384309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                                        DEFAULT_PRESENCE_CHECK_DELAY))
9394309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                                : DEFAULT_PRESENCE_CHECK_DELAY;
940c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        binder.linkToDeath(mReaderModeDeathRecipient, 0);
941c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    } catch (RemoteException e) {
942c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        Log.e(TAG, "Remote binder has already died.");
943c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        return;
944c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
945c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                } else {
946c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    try {
94731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams = null;
948c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        binder.unlinkToDeath(mReaderModeDeathRecipient, 0);
949c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    } catch (NoSuchElementException e) {
950c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        Log.e(TAG, "Reader mode Binder was never registered.");
951c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
952c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                }
953c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                applyRouting(false);
954c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            }
955c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        }
956c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen
957c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen        @Override
958c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) throws RemoteException {
959c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen            // nfc-extras implementation is no longer present in AOSP.
960c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen            return null;
961c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen        }
96228a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
96328a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales        @Override
96416ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        public void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, int[] techList) {
96516ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
96616ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
96716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            int lockscreenPollMask = computeLockscreenPollMask(techList);
96816ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            synchronized (NfcService.this) {
96916ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales                mNfcUnlockManager.addUnlockHandler(unlockHandler, lockscreenPollMask);
97016ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            }
97116ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
97216ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            applyRouting(false);
97316ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        }
97416ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
97516ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        @Override
976af05d4f78bca45a13f54444a67c1da09bdd599a3Andres Morales        public void removeNfcUnlockHandler(INfcUnlockHandler token) throws RemoteException {
97716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            synchronized (NfcService.this) {
978af05d4f78bca45a13f54444a67c1da09bdd599a3Andres Morales                mNfcUnlockManager.removeUnlockHandler(token.asBinder());
97916ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            }
98016ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
98116ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            applyRouting(false);
98216ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        }
98316ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
98428a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales        private int computeLockscreenPollMask(int[] techList) {
98528a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
98628a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            Map<Integer, Integer> techCodeToMask = new HashMap<Integer, Integer>();
98728a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
98828a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_A, NfcService.NFC_POLL_A);
98928a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_B,
99028a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales                    NfcService.NFC_POLL_B | NfcService.NFC_POLL_B_PRIME);
99128a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_V, NfcService.NFC_POLL_ISO15693);
99228a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_F, NfcService.NFC_POLL_F);
99328a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_BARCODE, NfcService.NFC_POLL_KOVIO);
99428a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
99528a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            int mask = 0;
99628a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
99728a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            for (int i = 0; i < techList.length; i++) {
99828a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales                if (techCodeToMask.containsKey(techList[i])) {
99928a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales                    mask |= techCodeToMask.get(techList[i]).intValue();
100028a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales                }
100128a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            }
100228a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
100328a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            return mask;
100428a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales        }
1005c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    }
1006c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
1007c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    final class ReaderModeDeathRecipient implements IBinder.DeathRecipient {
1008c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        @Override
1009c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        public void binderDied() {
1010c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            synchronized (NfcService.this) {
101131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                if (mReaderModeParams != null) {
101231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    mReaderModeParams = null;
1013c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    applyRouting(false);
1014c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                }
1015c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            }
1016c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        }
1017c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
10180e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
10194a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
1020fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1021f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
10224309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1023bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1024f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1025f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
102631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1027f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1028f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1029f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1030f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1031f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1032f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1033b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
1034b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
103521545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
1036b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
1037f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1038f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
1039fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1040f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
1041f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1042f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1043fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1044ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
10454309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1046bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1047f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1048f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
104931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1050f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1051f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1052f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1053f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1054f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1055b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1056b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
1057f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1058ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
1059cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            if (!tag.isPresent()) {
1060cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1061cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            }
1062cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen
1063ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
1064ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
1065ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
1066ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
1067ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
1068ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
1069ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1070ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
1071f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1072f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1073fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1074aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
10754309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1076aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1077f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1078aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1079aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
108031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1081aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
1082aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1083aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1084aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
1085f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1086aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
1087aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
1088aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
1089aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
1090aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
1091aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
1092aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1093aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
1094aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
1095aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1096aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
1097b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
10984309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1099bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1100f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
110131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1102f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1103f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1104f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1105f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1106f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1107f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1108b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
1109f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1110f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1111f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1112f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1113fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1114b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
1115f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1116b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1117b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
111831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1119b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1120b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1121b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1122b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
1123f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1124b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1125b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1126b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1127b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1128ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
1129b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1130b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1131fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1132f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
11334309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1134182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen
1135f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1136f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1137f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
113831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
11392c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1140f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1141f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1142f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1143f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
11443ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
11452c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
11462c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1147f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
114870bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
1149f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1150f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1151fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11529d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
115397c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
11544309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1155bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1156f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1157f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
1158f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1159f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
116031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1161f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1162f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1163f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1164f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1165f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1166f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1167bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
1168bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1169bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1170bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
11719d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
11729d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
1173bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
1174bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
1175bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
1176bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
1177bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
1178bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
1179bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
1180bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
1181bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
1182f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1183f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1184f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1185f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1186fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11873fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
11884309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1189bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1190f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1191f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1192f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
119331949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1194f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1195f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1196f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1197f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1198f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1199f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1200f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
1201f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
1202f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1203f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
1204f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1205f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
1206f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
1207f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
1208f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
1209f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1210f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1211f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1212f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1213f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1214f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1215fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12163fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
12174309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1218bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1219f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1220f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1221f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
122231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1223f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1224f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1225f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1226f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1227f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1228f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1229f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1230f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1231f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1232791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1233791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen
1234f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1235f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1236f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1237f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1238f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1239f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1240f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1241f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1242fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12433fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
12443fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1245f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1246f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1247fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12483fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
12494309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
125003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1251f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
125203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
125303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
125431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
125503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
125603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
125703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
125803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1259f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
126003ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
126103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
126203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
126303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1264f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
126503ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1266f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
126703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
126803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1269f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1270f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
12710aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
12720aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
12734309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
12740aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1275f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
12760aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12770aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
127831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
12790aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
12800aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12810aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12820aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1283f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
12840aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
12850aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
12860aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12870aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12880aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
12890aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1290f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
12910aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
12920aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12930aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
12940aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12951b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
12963fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
12974309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
12983fb14d0868594c78a777e805545209636814e223Martijn Coenen
1299f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
13003fb14d0868594c78a777e805545209636814e223Martijn Coenen
13013fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
130231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
13033fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
13043fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
13053fb14d0868594c78a777e805545209636814e223Martijn Coenen
13063fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1307f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
13083fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
13093fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
13103fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
13113fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
13123fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
13133fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
13143fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
13153fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
13163fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
13173fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
13183fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1319391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                tag.findAndReadNdef();
13203fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
13213fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
13224a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
13233fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
13243fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
13253fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
13263fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
13273fb14d0868594c78a777e805545209636814e223Martijn Coenen
13281b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1329fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
13304309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1331f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1332fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1333fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1334fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1335fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1336fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1337dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1338dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1339dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1340358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
13414309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1342358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1343358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1344358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1345358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1346358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1347dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
13484309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1349dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1350f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
13511b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1352bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1353bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1354bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1355bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1356bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1357bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1358bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1359bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1360bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1361bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1362ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen
1363ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        @Override
1364ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1365ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen            return mDeviceHost.getExtendedLengthApdusSupported();
1366ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        }
1367c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
1368f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
13699a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    boolean isNfcEnabledOrShuttingDown() {
13709a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        synchronized (this) {
13719a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
13729a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        }
13739a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    }
13749a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen
137531949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
137631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
137731949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1378e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1379aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1380aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
138131949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
1382a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        final Object mCancelWaiter = new Object();
1383525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        final int mTimeout;
1384a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        boolean mCanceled = false;
1385525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1386525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public WatchDogThread(String threadName, int timeout) {
1387525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            super(threadName);
1388525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mTimeout = timeout;
1389525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1390525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
13912edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
13922edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
1393a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            try {
1394a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                synchronized (mCancelWaiter) {
1395a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    mCancelWaiter.wait(mTimeout);
1396a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    if (mCanceled) {
1397a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                        return;
1398a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    }
13992edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
1400a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            } catch (InterruptedException e) {
1401a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                // Should not happen; fall-through to abort.
1402a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                Log.w(TAG, "Watchdog thread interruped.");
1403a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                interrupt();
14042edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
1405a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            Log.e(TAG, "Watchdog triggered, aborting.");
1406a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            mDeviceHost.doAbort();
14072edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
1408a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project
14092edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
1410a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            synchronized (mCancelWaiter) {
1411a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCanceled = true;
1412a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCancelWaiter.notify();
1413a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            }
14142edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
14152edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
14162edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
14179f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    static byte[] hexStringToBytes(String s) {
14189f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (s == null || s.length() == 0) return null;
14199f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        int len = s.length();
14209f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (len % 2 != 0) {
14219f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            s = '0' + s;
14229f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            len++;
14239f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
14249f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        byte[] data = new byte[len / 2];
14259f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        for (int i = 0; i < len; i += 2) {
14269f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
14274309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    + Character.digit(s.charAt(i + 1), 16));
14289f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
14299f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        return data;
14309f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
14319f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1432fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /**
1433fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1434fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     */
1435fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    void applyRouting(boolean force) {
1436e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
1437c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen            if (!isNfcEnabledOrShuttingDown()) {
1438e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1439e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1440525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
14417d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            if (mInProvisionMode) {
14427d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
14437d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
14447d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                if (!mInProvisionMode) {
14457d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Notify dispatcher it's fine to dispatch to any package now
14467d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // and allow handover transfers.
14477d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mNfcDispatcher.disableProvisioningMode();
14487d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                }
14497d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            }
14500799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // Special case: if we're transitioning to unlocked state while
14510799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // still talking to a tag, postpone re-configuration.
14520799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && isTagPresent()) {
14530799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                Log.d(TAG, "Not updating discovery parameters, tag connected.");
145442c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESUME_POLLING),
145542c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                        APPLY_ROUTING_RETRY_TIMEOUT_MS);
14560799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                return;
14570799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            }
14580799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales
1459f439271150e4548f116919e0254d57655421581cMartijn Coenen            try {
1460f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.start();
14610799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                // Compute new polling parameters
14620799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                NfcDiscoveryParameters newParams = computeDiscoveryParameters(mScreenState);
14630799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if (force || !newParams.equals(mCurrentDiscoveryParameters)) {
14640799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    if (newParams.shouldEnableDiscovery()) {
1465ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen                        boolean shouldRestart = mCurrentDiscoveryParameters.shouldEnableDiscovery();
14660799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                        mDeviceHost.enableDiscovery(newParams, shouldRestart);
14670799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    } else {
1468a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales                        mDeviceHost.disableDiscovery();
1469a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales                    }
14700799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    mCurrentDiscoveryParameters = newParams;
14710799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                } else {
14720799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    Log.d(TAG, "Discovery configuration equal, not updating.");
1473fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1474a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales            } finally {
1475a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales                watchDog.cancel();
1476221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
147765945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
147865945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
147965945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
14800799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales    private NfcDiscoveryParameters computeDiscoveryParameters(int screenState) {
14810799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        // Recompute discovery parameters based on screen state
14820799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        NfcDiscoveryParameters.Builder paramsBuilder = NfcDiscoveryParameters.newBuilder();
14830799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        // Polling
14840799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        if (screenState >= NFC_POLLING_MODE) {
14850799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // Check if reader-mode is enabled
14860799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            if (mReaderModeParams != null) {
14870799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                int techMask = 0;
14880799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_A) != 0)
14890799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_A;
14900799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_B) != 0)
14910799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_B;
14920799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_F) != 0)
14930799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_F;
14940799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_V) != 0)
14950799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_ISO15693;
14960799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_BARCODE) != 0)
14970799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_KOVIO;
14980799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales
14990799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                paramsBuilder.setTechMask(techMask);
15000799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                paramsBuilder.setEnableReaderMode(true);
15010799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            } else {
15020799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
15030799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            }
15040799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mInProvisionMode) {
15050799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
15060799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED &&
1507731fd8a52cec0dbe8d6ec6a4c7aa36ff52812112Andres Morales                mNfcUnlockManager.isLockscreenPollingEnabled()) {
15080799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // For lock-screen tags, no low-power polling
1509731fd8a52cec0dbe8d6ec6a4c7aa36ff52812112Andres Morales            paramsBuilder.setTechMask(mNfcUnlockManager.getLockscreenPollMask());
15100799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            paramsBuilder.setEnableLowPowerDiscovery(false);
1511a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales        }
1512a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales
15130799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        if (mIsHceCapable && mScreenState >= ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
15140799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // Host routing is always enabled at lock screen or later
15150799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            paramsBuilder.setEnableHostRouting(true);
15160799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        }
15170799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        return paramsBuilder.build();
1518a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales    }
1519a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales
1520a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales    private boolean isTagPresent() {
1521a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales        for (Object object : mObjectMap.values()) {
1522a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales            if (object instanceof TagEndpoint) {
1523a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                return ((TagEndpoint) object).isPresent();
1524a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales            }
1525a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales        }
1526a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales        return false;
1527a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales    }
15284309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
15294309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * Disconnect any target if present
15304309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
153131949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
15329a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        if (!isNfcEnabledOrShuttingDown()) {
1533a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1534a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
153531949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
153631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
153731949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
153831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
153931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
154031949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
154131949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
154231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
154331949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
154431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
154531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
154631949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
154731949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
154831949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
154931949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
155031949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
155131949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
155231949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
155331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
155431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
155531949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
155631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
155731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1558bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1559bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1560bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1561bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1562bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
156331949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
156431949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
156531949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
156631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
156731949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
15682f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
156931949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
15700e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1571f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1572f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
157331949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
157431949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
157531949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1576f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1577b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1578b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
157931949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
158031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
158131949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
158231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
1583f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1584f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
15854309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
15864309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * For use by code in this process
15874309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
15884a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1589c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            throws LlcpException {
15904a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1591d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1592d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
15934309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
15944309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * For use by code in this process
15954309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
15963b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
1597e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen            throws LlcpException {
15983b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
1599e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    }
1600e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen
16014309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
16024309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * For use by code in this process
16034309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
16044a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1605c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            int linearBufferLength) throws LlcpException {
16064a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1607d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1608d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
160957d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
1610b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
161157d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
161257d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
1613d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void routeAids(String aid, int route) {
1614d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        Message msg = mHandler.obtainMessage();
1615d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.what = MSG_ROUTE_AID;
1616d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.arg1 = route;
1617d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.obj = aid;
1618d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendMessage(msg);
1619d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1620d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
1621d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void unrouteAids(String aid) {
1622d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        sendMessage(MSG_UNROUTE_AID, aid);
1623d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1624d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
1625d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void commitRouting() {
1626d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
1627d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1628d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
16294309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    public boolean sendData(byte[] data) {
16304309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        return mDeviceHost.sendRawFrame(data);
16319f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
16329f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1633b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
1634b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
1635b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
1636b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
1637b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
1638b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1639b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
16403fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
1641b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
1642b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
164331949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
1644d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_ROUTE_AID: {
1645d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    int route = msg.arg1;
1646d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
1647d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.routeAid(hexStringToBytes(aid), route);
1648d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    // Restart polling config
1649d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1650d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
1651d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_UNROUTE_AID: {
1652d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
1653d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.unrouteAid(hexStringToBytes(aid));
1654d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1655d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
16569340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                case MSG_INVOKE_BEAM: {
16579340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mP2pLinkManager.onManualBeamInvoke((BeamShareData)msg.obj);
16589340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    break;
16599340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                }
1660d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_COMMIT_ROUTING: {
1661f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    boolean commit = false;
1662f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    synchronized (NfcService.this) {
1663f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                        if (mCurrentDiscoveryParameters.shouldEnableDiscovery()) {
1664f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                            commit = true;
1665f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                        } else {
1666f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                            Log.d(TAG, "Not committing routing because discovery is disabled.");
1667f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                        }
1668f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    }
1669f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    if (commit) {
1670f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                        mDeviceHost.commitRouting();
1671f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    }
1672d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1673d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
167431949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
167531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
167631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
167731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
167831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
167931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
168031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
16814309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    Tag tag = Tag.createMockTag(new byte[]{0x00},
16824309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                            new int[]{TagTechnology.NDEF},
16834309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                            new Bundle[]{extras});
168431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
168531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
168632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales                    int dispatchStatus = mNfcDispatcher.dispatchTag(tag);
168732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales                    if (dispatchStatus == NfcDispatcher.DISPATCH_SUCCESS) {
1688d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
168932cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales                    } else if (dispatchStatus == NfcDispatcher.DISPATCH_FAIL) {
1690d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
169131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
169231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
169331949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
169457d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
169531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
169631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
169731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
169831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    ReaderModeParams readerParams = null;
169931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    int presenceCheckDelay = DEFAULT_PRESENCE_CHECK_DELAY;
1700a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                    DeviceHost.TagDisconnectedCallback callback =
1701a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                            new DeviceHost.TagDisconnectedCallback() {
1702a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                                @Override
1703a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                                public void onTagDisconnected(long handle) {
1704a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                                    applyRouting(false);
1705a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                                }
1706a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                            };
1707c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    synchronized (NfcService.this) {
170831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        readerParams = mReaderModeParams;
1709c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
171031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (readerParams != null) {
171131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        presenceCheckDelay = readerParams.presenceCheckDelay;
171231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
171331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
1714a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                            tag.startPresenceChecking(presenceCheckDelay, callback);
171531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            dispatchTagEndpoint(tag, readerParams);
171631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            break;
171731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        }
171831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    }
17193e8b9a06407baa7c17e6f4c6bac20e0a3deaef31Andres Morales
17203e8b9a06407baa7c17e6f4c6bac20e0a3deaef31Andres Morales                    boolean playSound = readerParams == null ||
17213e8b9a06407baa7c17e6f4c6bac20e0a3deaef31Andres Morales                        (readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0;
17223e8b9a06407baa7c17e6f4c6bac20e0a3deaef31Andres Morales                    if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && playSound) {
172331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        playSound(SOUND_START);
1724c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
172589baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
172689baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // When these tags start containing NDEF, they will require
172789baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // the stack to deal with them in a different way, since
172889baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // they are activated only really shortly.
172989baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // For now, don't consider NDEF on these.
173089baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
1731a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                        tag.startPresenceChecking(presenceCheckDelay, callback);
173231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        dispatchTagEndpoint(tag, readerParams);
173389baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        break;
173489baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    }
1735391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    NdefMessage ndefMsg = tag.findAndReadNdef();
1736c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
1737391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    if (ndefMsg != null) {
1738a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                        tag.startPresenceChecking(presenceCheckDelay, callback);
173931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        dispatchTagEndpoint(tag, readerParams);
174031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
174131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
1742a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                            tag.startPresenceChecking(presenceCheckDelay, callback);
174331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            dispatchTagEndpoint(tag, readerParams);
174431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
174531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
1746d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
174731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
174831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
174931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
175031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
175196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
175296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent actIntent = new Intent(ACTION_LLCP_UP);
175396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(actIntent);
175496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
175531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
175631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
175731949217328bf2357ff044f0d18677fe588c790cNick Pelly
175831949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
175996e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
176096e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
176196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(deactIntent);
176296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
176331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
176431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
176531949217328bf2357ff044f0d18677fe588c790cNick Pelly
176631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
176731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
176831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
176931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
177031949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
177131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
177231949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
177331949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
177431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
177531949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
177631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
177731949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
177831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
177931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
178031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
178131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
178231949217328bf2357ff044f0d18677fe588c790cNick Pelly
178377d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
178431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
178557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                case MSG_LLCP_LINK_FIRST_PACKET:
178657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    mP2pLinkManager.onLlcpFirstPacketReceived();
178757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    break;
1788c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                case MSG_RF_FIELD_ACTIVATED:
1789c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    Intent fieldOnIntent = new Intent(ACTION_RF_FIELD_ON_DETECTED);
1790c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    sendNfcEeAccessProtectedBroadcast(fieldOnIntent);
1791c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    break;
1792c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                case MSG_RF_FIELD_DEACTIVATED:
1793c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    Intent fieldOffIntent = new Intent(ACTION_RF_FIELD_OFF_DETECTED);
1794c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    sendNfcEeAccessProtectedBroadcast(fieldOffIntent);
1795dbcee970ef57927e73c269f573d06e2f133a34c1Martijn Coenen                    break;
179642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                case MSG_RESUME_POLLING:
179742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                    mNfcAdapter.resumePolling();
1798c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    break;
179931949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
180031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
180131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
180231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
1803b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1804d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1805c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        private void sendNfcEeAccessProtectedBroadcast(Intent intent) {
1806c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
1807c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            // Resume app switches so the receivers can start activites without delay
1808c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            mNfcDispatcher.resumeAppSwitches();
1809c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
1810c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            synchronized (this) {
1811c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                for (PackageInfo pkg : mInstalledPackages) {
1812c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    if (pkg != null && pkg.applicationInfo != null) {
1813c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
1814c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                            intent.setPackage(pkg.packageName);
1815c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                            mContext.sendBroadcast(intent);
1816c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                        }
1817c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    }
1818c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                }
1819c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            }
1820c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        }
1821c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
1822d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
1823d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
1824d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1825d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1826d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1827d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
1828d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Check LLCP compliancy */
1829d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doCheckLlcp()) {
1830d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        /* Activate LLCP Link */
1831d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (mDeviceHost.doActivateLlcp()) {
1832d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
183331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            synchronized (NfcService.this) {
183431949217328bf2357ff044f0d18677fe588c790cNick Pelly                                // Register P2P device
183531949217328bf2357ff044f0d18677fe588c790cNick Pelly                                mObjectMap.put(device.getHandle(), device);
1836d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                            }
183777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                            mP2pLinkManager.onLlcpActivated();
1838d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            return true;
1839d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        } else {
1840d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
1841d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1842d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
1843d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
1844d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
1845d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1846d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
1847d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1848d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1849d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1850d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
1851d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
1852d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
1853d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
1854d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1855d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1856d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1857d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
1858d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
1859d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
1860d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
1861d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
186231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
186331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
186431949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
1865d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
186677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
1867d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
1868d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1869d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1870d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
1871d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1872d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
1873d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1874d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
1875d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
1876d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
187731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, ReaderModeParams readerParams) {
1878f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
1879f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
1880f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
18813dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen            if (readerParams != null) {
188231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                try {
188331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if ((readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
188431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        playSound(SOUND_END);
188531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    }
18863dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    if (readerParams.callback != null) {
18873dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        readerParams.callback.onTagDiscovered(tag);
18883dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        return;
18893dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    } else {
18903dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        // Follow normal dispatch below
18913dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    }
189231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                } catch (RemoteException e) {
18930799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    Log.e(TAG, "Reader mode remote has died, falling back.", e);
18943dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    // Intentional fall-through
18953dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                } catch (Exception e) {
18963dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    // Catch any other exception
18970799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    Log.e(TAG, "App exception, not dispatching.", e);
18983dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    return;
189931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                }
190031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen            }
190132cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales            int dispatchResult = mNfcDispatcher.dispatchTag(tag);
190232cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales            if (dispatchResult == NfcDispatcher.DISPATCH_FAIL) {
1903f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
1904d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
190532cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales            } else if (dispatchResult == NfcDispatcher.DISPATCH_SUCCESS) {
1906d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
19073fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
19083fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
1909b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
1910b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1911b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
191249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
1913fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
1914fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1915fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        protected Void doInBackground(Integer... params) {
1916fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            synchronized (NfcService.this) {
1917fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (params == null || params.length != 1) {
1918fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    // force apply current routing
1919fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    applyRouting(true);
1920fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    return null;
1921161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
1922fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                mScreenState = params[0].intValue();
1923fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1924525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
1925525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
1926525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    applyRouting(false);
1927525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
1928525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
1929161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
1930fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return null;
19317c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
19327c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
19337c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
19347c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
1935525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1936525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
1937525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1938525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            String action = intent.getAction();
1939c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen            if (action.equals(Intent.ACTION_SCREEN_ON)
1940525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_SCREEN_OFF)
1941525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_USER_PRESENT)) {
1942525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
19434309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                int screenState = ScreenStateHelper.SCREEN_STATE_OFF;
1944525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
19454309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    screenState = ScreenStateHelper.SCREEN_STATE_OFF;
1946525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
19474309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    screenState = mKeyguard.isKeyguardLocked()
19484309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                            ? ScreenStateHelper.SCREEN_STATE_ON_LOCKED
19494309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                            : ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1950525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
19514309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    screenState = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1952525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
1953525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
195431949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
195531949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
195631949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
195731949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
195831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
195931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
196031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
196131949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
196231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
196331949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
19641668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
19651668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
196631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
196731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
196831949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
196931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
197031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
19713859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
1972d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1973d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                synchronized (this) {
1974d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                    mUserId = userId;
1975d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                }
1976d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                mP2pLinkManager.onUserSwitched(getUserId());
1977341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen                if (mIsHceCapable) {
1978af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen                    mCardEmulationManager.onUserSwitched(getUserId());
19794358172f18871d58d5bc2050e4d9d0bf9bc2d5e5Martijn Coenen                }
1980f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1981f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1982f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
198331949217328bf2357ff044f0d18677fe588c790cNick Pelly
1984c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
1985c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        @Override
1986c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        public void onReceive(Context context, Intent intent) {
1987c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            String action = intent.getAction();
1988c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
1989c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
1990c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
1991c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
1992c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                updatePackageCache();
1993c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
1994c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
1995c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    // Clear the NFCEE access cache in case a UID gets recycled
1996c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    mNfceeAccessControl.invalidateCache();
1997c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                }
1998c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            }
1999c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        }
2000c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    };
2001c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
2002b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz    private final BroadcastReceiver mPolicyReceiver = new BroadcastReceiver() {
2003b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        @Override
2004b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        public void onReceive(Context context, Intent intent){
2005b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            String action = intent.getAction();
2006b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
2007b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    .equals(action)) {
2008b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                enforceBeamShareActivityPolicy(context,
2009b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                        new UserHandle(getSendingUserId()), mIsNdefPushEnabled);
2010b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            }
2011b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        }
2012b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz    };
2013c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
20144309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
20154309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * Returns true if airplane mode is currently on
20164309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
201731949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
20187d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        return Settings.System.getInt(mContentResolver,
20197d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
202031949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
202131949217328bf2357ff044f0d18677fe588c790cNick Pelly
20224309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
20234309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * for debugging only - no i18n
20244309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
202531949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
202631949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
202731949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
202831949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
202931949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
203031949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
203131949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
203231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
203331949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
203431949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
203531949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
203631949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
203731949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
203831949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
203931949217328bf2357ff044f0d18677fe588c790cNick Pelly
204031949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
204150effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
204250effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
204350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
204450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
204550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
204650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
204750effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
204850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
204931949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
205031949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
20510b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
20524309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            pw.println("mScreenState=" + ScreenStateHelper.screenStateToString(mScreenState));
205331949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
205431949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
20550799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            pw.println(mCurrentDiscoveryParameters);
205677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
2057341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen            if (mIsHceCapable) {
2058af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen                mCardEmulationManager.dump(fd, pw, args);
2059341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen            }
2060391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            mNfcDispatcher.dump(fd, pw, args);
206156f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
206231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
206331949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
206474180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
2065