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;
83d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenenimport java.util.ArrayList;
843ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamiltonimport java.util.HashMap;
85c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenenimport java.util.List;
8628a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Moralesimport java.util.Map;
87c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenenimport java.util.NoSuchElementException;
883ca6ffff72f4599e80f85de5ae8e7f55012f38d6Jeff Hamilton
89d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen
90525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectpublic class NfcService implements DeviceHostListener {
91c05387ef4e6d6d024b03254e7e2ea5ad001cf2d2Jeff Hamilton    static final boolean DBG = false;
9276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    static final String TAG = "NfcService";
93fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
94d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static final String SERVICE_NAME = "nfc";
95fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks
9677d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    public static final String PREF = "NfcServicePrefs";
97f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
98416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NFC_ON = "nfc_on";
99416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NFC_ON_DEFAULT = true;
100416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
101416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final boolean NDEF_PUSH_ON_DEFAULT = true;
102416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BEAM = "first_beam";
103416e2fc507d696486a127f932105b3b95519d0cbJeff Hamilton    static final String PREF_FIRST_BOOT = "first_boot";
1041668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
105a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly
106b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    static final int MSG_NDEF_TAG = 0;
107c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_LLCP_LINK_ACTIVATION = 1;
108c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_LLCP_LINK_DEACTIVATED = 2;
109c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_MOCK_NDEF = 3;
110c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_LLCP_LINK_FIRST_PACKET = 4;
111c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_ROUTE_AID = 5;
112c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_UNROUTE_AID = 6;
113c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_COMMIT_ROUTING = 7;
114c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_INVOKE_BEAM = 8;
115c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_RF_FIELD_ACTIVATED = 9;
116c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    static final int MSG_RF_FIELD_DEACTIVATED = 10;
117e276d3323d755d8bdaccd59a551332c064970215Andres Morales    static final int MSG_RESUME_POLLING = 11;
11842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
11942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales    static final long MAX_POLLING_PAUSE_TIMEOUT = 40000;
120b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
12131949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_ENABLE = 1;
12231949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_DISABLE = 2;
12331949217328bf2357ff044f0d18677fe588c790cNick Pelly    static final int TASK_BOOT = 3;
124c3981b9a0b39faed474480bc3dbd3e33bbd50b99Martijn Coenen
125a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    // Polling technology masks
126a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_A = 0x01;
127a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_B = 0x02;
128a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_F = 0x04;
129a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_ISO15693 = 0x08;
130a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_B_PRIME = 0x10;
131a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales    static final int NFC_POLL_KOVIO = 0x20;
132fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1330799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales    // minimum screen state that enables NFC polling
1340799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales    static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1350799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales
136525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for NFC controller to initialize before watchdog
137525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off. This time is chosen large, because firmware download
138525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // may be a part of initialization.
139525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int INIT_WATCHDOG_MS = 90000;
140525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
141525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // Time to wait for routing to be applied before watchdog
142525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    // goes off
143525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    static final int ROUTING_WATCHDOG_MS = 10000;
144525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
14531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    // Default delay used for presence checks
14631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    static final int DEFAULT_PRESENCE_CHECK_DELAY = 125;
14731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
14834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    // The amount of time we wait before manually launching
14934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    // the Beam animation when called through the share menu.
15034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    static final int INVOKE_BEAM_DELAY_MS = 1000;
15134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen
152c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    // RF field events as defined in NFC extras
153c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    public static final String ACTION_RF_FIELD_ON_DETECTED =
154c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
155c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    public static final String ACTION_RF_FIELD_OFF_DETECTED =
156c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
157c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
158d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    // for use with playSound()
159d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_START = 0;
160d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_END = 1;
161d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public static final int SOUND_ERROR = 2;
162d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
16396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_UP =
16496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_UP";
16596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
16696e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    public static final String ACTION_LLCP_DOWN =
16796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen            "com.android.nfc.action.LLCP_DOWN";
16896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
16942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales    // Timeout to re-apply routing if a tag was present and we postponed it
17042c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales    private static final int APPLY_ROUTING_RETRY_TIMEOUT_MS = 5000;
17142c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
1725c452dad7b24f28223414ce5e953bfcab782570eAndres Morales    private final UserManager mUserManager;
1735c452dad7b24f28223414ce5e953bfcab782570eAndres Morales
17449d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // NFC Execution Environment
17549d53329a0c720a7e430220d77805bc1763545b1Nick Pelly    // fields below are protected by this
176c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    private final ReaderModeDeathRecipient mReaderModeDeathRecipient =
177c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            new ReaderModeDeathRecipient();
17816ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales    private final NfcUnlockManager mNfcUnlockManager;
1790bd11735e8a28db1692f28abcc3e065abae0e8ddDaniel Tomas
180c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    private final NfceeAccessControl mNfceeAccessControl;
181c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
182c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    List<PackageInfo> mInstalledPackages; // cached version of installed packages
183c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
1842f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are used in multiple threads and protected by synchronized(this)
185fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
186fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    int mScreenState;
1877d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
188fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    boolean mIsNdefPushEnabled;
189ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen    NfcDiscoveryParameters mCurrentDiscoveryParameters =
190ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen            NfcDiscoveryParameters.getNfcOffParameters();
19128a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
19231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    ReaderModeParams mReaderModeParams;
19331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
19431949217328bf2357ff044f0d18677fe588c790cNick Pelly    // mState is protected by this, however it is only modified in onCreate()
19531949217328bf2357ff044f0d18677fe588c790cNick Pelly    // and the default AsyncTask thread so it is read unprotected from that
19631949217328bf2357ff044f0d18677fe588c790cNick Pelly    // thread
19731949217328bf2357ff044f0d18677fe588c790cNick Pelly    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
1982f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly    // fields below are final after onCreate()
19905973d55daf68a286c932ee4e7ffbd6bb53789e0Jeff Hamilton    Context mContext;
2004a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    private DeviceHost mDeviceHost;
2010e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences mPrefs;
2020e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    private SharedPreferences.Editor mPrefsEditor;
203525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private PowerManager.WakeLock mRoutingWakeLock;
204525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
205d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mStartSound;
206d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mEndSound;
207d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    int mErrorSound;
208d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    SoundPool mSoundPool; // playback synchronized on this
20977d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly    P2pLinkManager mP2pLinkManager;
2104a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    TagService mNfcTagService;
2114a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    NfcAdapterService mNfcAdapter;
21231949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneSensitive;
21331949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean mIsAirplaneToggleable;
21496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen    boolean mIsDebugBuild;
2150a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen    boolean mIsHceCapable;
21642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales    boolean mPollingPaused;
2172ef360deaff9f17aa72d5749ceee283cc80897afBen Dodson
21876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly    private NfcDispatcher mNfcDispatcher;
219fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    private PowerManager mPowerManager;
220275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks    private KeyguardManager mKeyguard;
221b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales    private HandoverDataParser mHandoverDataParser;
2227d8987f233985a5ff29226890e11012275d325f5Martijn Coenen    private ContentResolver mContentResolver;
223af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen    private CardEmulationManager mCardEmulationManager;
22428a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
2254309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    private ScreenStateHelper mScreenStateHelper;
22634322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen    private ForegroundUtils mForegroundUtils;
227d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
22828a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales    private int mUserId;
2294309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    private static NfcService sService;
23089c893312d524f50c47b0d32071f3de8631197f3Martijn Coenen
231d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    public static NfcService getInstance() {
232d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        return sService;
233d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
234f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
2350e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    @Override
236f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
237f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_NDEF_TAG, tag);
238f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
239f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
240f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
241f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies transaction
242f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
243d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
2449f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationActivated() {
245af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen        if (mCardEmulationManager != null) {
246af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen            mCardEmulationManager.onHostCardEmulationActivated();
2470a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
2489f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
2499f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
2509f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
2519f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationData(byte[] data) {
252af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen        if (mCardEmulationManager != null) {
253af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen            mCardEmulationManager.onHostCardEmulationData(data);
2540a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
2559f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
2569f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
2579f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    @Override
2589f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    public void onHostCardEmulationDeactivated() {
259af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen        if (mCardEmulationManager != null) {
260af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen            mCardEmulationManager.onHostCardEmulationDeactivated();
2610a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        }
2629f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
2639f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
2649f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    /**
265f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
266f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
267f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    @Override
268f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkActivated(NfcDepEndpoint device) {
269f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
270f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
271f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
272f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    /**
273f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     * Notifies P2P Device detected, to activate LLCP link
274f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton     */
275d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    @Override
276f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
277f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
278f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton    }
279f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton
28057a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    /**
28157a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     * Notifies P2P Device detected, first packet received over LLCP link
28257a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen     */
28357a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    @Override
28457a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
28557a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
28657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen    }
28757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen
288c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    @Override
289c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    public void onRemoteFieldActivated() {
290c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        sendMessage(NfcService.MSG_RF_FIELD_ACTIVATED, null);
291c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    }
292c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
293c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    public void onRemoteFieldDeactivated() {
294c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        sendMessage(NfcService.MSG_RF_FIELD_DEACTIVATED, null);
295c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    }
296c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
29731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    final class ReaderModeParams {
29831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public int flags;
29931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public IAppCallback callback;
30031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public int presenceCheckDelay;
30131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen    }
30231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen
303525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    public NfcService(Application nfcApplication) {
304d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales        mUserId = ActivityManager.getCurrentUser();
3054309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        mContext = nfcApplication;
3064309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales
3074a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcTagService = new TagService();
3084a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        mNfcAdapter = new NfcAdapterService();
3092f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly        Log.i(TAG, "Starting NFC service");
3102f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly
311d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        sService = this;
312d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
3134309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        mScreenStateHelper = new ScreenStateHelper(mContext);
3147d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        mContentResolver = mContext.getContentResolver();
315525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mDeviceHost = new NativeNfcManager(mContext, this);
31674180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick
31716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        mNfcUnlockManager = NfcUnlockManager.getInstance();
31816ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
319b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mHandoverDataParser = new HandoverDataParser();
3207d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        boolean isNfcProvisioningEnabled = false;
3217d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        try {
3227d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
3237d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    R.bool.enable_nfc_provisioning);
3247d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } catch (NotFoundException e) {
3257d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
3267d8987f233985a5ff29226890e11012275d325f5Martijn Coenen
3277d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        if (isNfcProvisioningEnabled) {
3287d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
3297d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
3307d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        } else {
3317d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            mInProvisionMode = false;
3327d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        }
333525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
334b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, mInProvisionMode);
335b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverDataParser,
336525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
33724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton
338525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
3390e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        mPrefsEditor = mPrefs.edit();
340f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
341c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        mNfceeAccessControl = new NfceeAccessControl(mContext);
342c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
34331949217328bf2357ff044f0d18677fe588c790cNick Pelly        mState = NfcAdapter.STATE_OFF;
3440b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
345a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen        setBeamShareActivityState(mIsNdefPushEnabled);
346f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
34796e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
34896e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen
349525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
350525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
351525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mRoutingWakeLock = mPowerManager.newWakeLock(
3524309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
353275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks
354525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
3555c452dad7b24f28223414ce5e953bfcab782570eAndres Morales        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
3565c452dad7b24f28223414ce5e953bfcab782570eAndres Morales
3574309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        mScreenState = mScreenStateHelper.checkScreenState();
358533043d1003de2f6a20a29201100d94c3c7bc9caNick Pelly
359d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
360f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
361525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        // Intents for all users
362c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
36365945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        filter.addAction(Intent.ACTION_SCREEN_ON);
364275fd2b59ae8a9e3eb6e77e8663aea9ca08f1159Jason parks        filter.addAction(Intent.ACTION_USER_PRESENT);
3653859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen        filter.addAction(Intent.ACTION_USER_SWITCHED);
36631949217328bf2357ff044f0d18677fe588c790cNick Pelly        registerForAirplaneMode(filter);
367525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
3680e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
369c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        IntentFilter ownerFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
370c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
371c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
372c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
373c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter = new IntentFilter();
374c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
375c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
376c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        ownerFilter.addDataScheme("package");
377c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        mContext.registerReceiver(mOwnerReceiver, ownerFilter);
378c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
379b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        IntentFilter policyFilter = new IntentFilter(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
380b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        mContext.registerReceiverAsUser(mPolicyReceiver, UserHandle.ALL, policyFilter, null, null);
381b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz
382c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        updatePackageCache();
383c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
3840a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        PackageManager pm = mContext.getPackageManager();
385341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen        mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
3860a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen        if (mIsHceCapable) {
387af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen            mCardEmulationManager = new CardEmulationManager(mContext);
388a56a84a384db51809101e149d83bf41b5e198ca0Martijn Coenen        }
38934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        mForegroundUtils = ForegroundUtils.getInstance();
39031949217328bf2357ff044f0d18677fe588c790cNick Pelly        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
39131949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
39231949217328bf2357ff044f0d18677fe588c790cNick Pelly
393d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void initSoundPool() {
3944309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        synchronized (this) {
395d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
396d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
397525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
398525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
399525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
400d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
401d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
402d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
403d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
404d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    void releaseSoundPool() {
4054309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        synchronized (this) {
406d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool != null) {
407d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool.release();
408d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                mSoundPool = null;
409d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
410d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen        }
411d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    }
412d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
41331949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerForAirplaneMode(IntentFilter filter) {
4147d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
4157d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_RADIOS);
4167d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        final String toggleableRadios = Settings.System.getString(mContentResolver,
4177d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
41831949217328bf2357ff044f0d18677fe588c790cNick Pelly
41931949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
4207d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
42131949217328bf2357ff044f0d18677fe588c790cNick Pelly        mIsAirplaneToggleable = toggleableRadios == null ? false :
4224309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                toggleableRadios.contains(Settings.Global.RADIO_NFC);
42331949217328bf2357ff044f0d18677fe588c790cNick Pelly
42431949217328bf2357ff044f0d18677fe588c790cNick Pelly        if (mIsAirplaneSensitive) {
42531949217328bf2357ff044f0d18677fe588c790cNick Pelly            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
42631949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
42731949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
42831949217328bf2357ff044f0d18677fe588c790cNick Pelly
429c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    void updatePackageCache() {
430c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        PackageManager pm = mContext.getPackageManager();
431c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        List<PackageInfo> packages = pm.getInstalledPackages(0, UserHandle.USER_OWNER);
432c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        synchronized (this) {
433c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            mInstalledPackages = packages;
434c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        }
435c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    }
436c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
43731949217328bf2357ff044f0d18677fe588c790cNick Pelly    /**
43831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * Manages tasks that involve turning on/off the NFC controller.
4394309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * <p/>
44031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>All work that might turn the NFC adapter on or off must be done
44131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * through this task, to keep the handling of mState simple.
44231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * In other words, mState is only modified in these tasks (and we
44331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * don't need a lock to read it in these tasks).
4444309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * <p/>
44531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>These tasks are all done on the same AsyncTask background
44631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * thread, so they are serialized. Each task may temporarily transition
44731949217328bf2357ff044f0d18677fe588c790cNick Pelly     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
44831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
44931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * of starting in either STATE_OFF or STATE_ON, without needing to hold
45031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * NfcService.this for the entire task.
4514309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * <p/>
45231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>AsyncTask's are also implicitly queued. This is useful for corner
45331949217328bf2357ff044f0d18677fe588c790cNick Pelly     * cases like turning airplane mode on while TASK_ENABLE is in progress.
45431949217328bf2357ff044f0d18677fe588c790cNick Pelly     * The TASK_DISABLE triggered by airplane mode will be correctly executed
45531949217328bf2357ff044f0d18677fe588c790cNick Pelly     * immediately after TASK_ENABLE is complete. This seems like the most sane
45631949217328bf2357ff044f0d18677fe588c790cNick Pelly     * way to deal with these situations.
4574309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * <p/>
45831949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
45931949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
46031949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
46131949217328bf2357ff044f0d18677fe588c790cNick Pelly     * preferences
46231949217328bf2357ff044f0d18677fe588c790cNick Pelly     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
46331949217328bf2357ff044f0d18677fe588c790cNick Pelly     */
46431949217328bf2357ff044f0d18677fe588c790cNick Pelly    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
46531949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
46631949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected Void doInBackground(Integer... params) {
46731949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Sanity check mState
46831949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (mState) {
46931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_OFF:
47031949217328bf2357ff044f0d18677fe588c790cNick Pelly                case NfcAdapter.STATE_TURNING_ON:
47131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
47231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mState);
47331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return null;
47431949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
47531949217328bf2357ff044f0d18677fe588c790cNick Pelly
4764467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
4774467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * override with the default. THREAD_PRIORITY_BACKGROUND causes
4784467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * us to service software I2C too slow for firmware download
4794467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * with the NXP PN544.
4804467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
4814467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             * problem only occurs on I2C platforms using PN544
4824467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly             */
4834467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
4844467dca5650a170af5020c10a8ccb25f86f1007fNick Pelly
48531949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (params[0].intValue()) {
48631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_ENABLE:
48731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    enableInternal();
48831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
48931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_DISABLE:
49031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    disableInternal();
49131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
49231949217328bf2357ff044f0d18677fe588c790cNick Pelly                case TASK_BOOT:
4934309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    Log.d(TAG, "checking on firmware download");
4941668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
49531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
4961668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
4974309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                        Log.d(TAG, "NFC is on. Doing normal stuff");
49831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        enableInternal();
4990fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                    } else {
5004309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                        Log.d(TAG, "NFC is off.  Checking firmware version");
5010fe7049a3224aa7b29cc980be07387e17607b0deJeff Hamilton                        mDeviceHost.checkFirmware();
50231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
50331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
50431949217328bf2357ff044f0d18677fe588c790cNick Pelly                        Log.i(TAG, "First Boot");
50531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
50631949217328bf2357ff044f0d18677fe588c790cNick Pelly                        mPrefsEditor.apply();
50731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
50831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
50931949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
510d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly
511d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            // Restore default AsyncTask priority
512d1936808c5f37f97fdb876836194ecbfe1cdfff5Nick Pelly            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
51331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return null;
51431949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
51531949217328bf2357ff044f0d18677fe588c790cNick Pelly
51631949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
51731949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Enable NFC adapter functions.
51831949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
51931949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
52031949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean enableInternal() {
52131949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_ON) {
52231949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
52331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
52431949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Enabling NFC");
52531949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_ON);
52631949217328bf2357ff044f0d18677fe588c790cNick Pelly
527525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
528525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            watchDog.start();
529525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            try {
530525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
531525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
532304a6342ee7e5620d3b50d988755c035f1686dc2Martijn Coenen                    if (!mDeviceHost.initialize()) {
533525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        Log.w(TAG, "Error enabling NFC");
534525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        updateState(NfcAdapter.STATE_OFF);
535525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                        return false;
536525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    }
537525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
538525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
539525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
540525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            } finally {
541525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                watchDog.cancel();
54231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
54331949217328bf2357ff044f0d18677fe588c790cNick Pelly
5440a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            if (mIsHceCapable) {
5450a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen                // Generate the initial card emulation routing table
546af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen                mCardEmulationManager.onNfcEnabled();
5470a9487f8aad77ed5f1a8f142b690396446858247Martijn Coenen            }
548d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
5494309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            synchronized (NfcService.this) {
55031949217328bf2357ff044f0d18677fe588c790cNick Pelly                mObjectMap.clear();
5510b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
55231949217328bf2357ff044f0d18677fe588c790cNick Pelly                updateState(NfcAdapter.STATE_ON);
55331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
55431949217328bf2357ff044f0d18677fe588c790cNick Pelly
555d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            initSoundPool();
556d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
55731949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Start polling loop */
5580c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
559fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
56031949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
56131949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
56231949217328bf2357ff044f0d18677fe588c790cNick Pelly
56331949217328bf2357ff044f0d18677fe588c790cNick Pelly        /**
56431949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Disable all NFC adapter functions.
56531949217328bf2357ff044f0d18677fe588c790cNick Pelly         * Does not toggle preferences.
56631949217328bf2357ff044f0d18677fe588c790cNick Pelly         */
56731949217328bf2357ff044f0d18677fe588c790cNick Pelly        boolean disableInternal() {
56831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (mState == NfcAdapter.STATE_OFF) {
56931949217328bf2357ff044f0d18677fe588c790cNick Pelly                return true;
57031949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
57131949217328bf2357ff044f0d18677fe588c790cNick Pelly            Log.i(TAG, "Disabling NFC");
57231949217328bf2357ff044f0d18677fe588c790cNick Pelly            updateState(NfcAdapter.STATE_TURNING_OFF);
57331949217328bf2357ff044f0d18677fe588c790cNick Pelly
57431949217328bf2357ff044f0d18677fe588c790cNick Pelly            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
57531949217328bf2357ff044f0d18677fe588c790cNick Pelly             * Implemented with a new thread (instead of a Handler or AsyncTask),
57631949217328bf2357ff044f0d18677fe588c790cNick Pelly             * because the UI Thread and AsyncTask thread-pools can also get hung
57731949217328bf2357ff044f0d18677fe588c790cNick Pelly             * when the NFC controller stops responding */
578525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
57931949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.start();
58031949217328bf2357ff044f0d18677fe588c790cNick Pelly
581953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            if (mIsHceCapable) {
582af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen                mCardEmulationManager.onNfcDisabled();
583953c3dd151419d497205246d4bfa8a818d39d00aMartijn Coenen            }
584d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
58577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.enableDisable(false, false);
58631949217328bf2357ff044f0d18677fe588c790cNick Pelly
58731949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Stop watchdog if tag present
58831949217328bf2357ff044f0d18677fe588c790cNick Pelly            // A convenient way to stop the watchdog properly consists of
58931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // disconnecting the tag. The polling loop shall be stopped before
59031949217328bf2357ff044f0d18677fe588c790cNick Pelly            // to avoid the tag being discovered again.
59131949217328bf2357ff044f0d18677fe588c790cNick Pelly            maybeDisconnectTarget();
59231949217328bf2357ff044f0d18677fe588c790cNick Pelly
5930b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(null, null, null);
59431949217328bf2357ff044f0d18677fe588c790cNick Pelly
595ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen
59631949217328bf2357ff044f0d18677fe588c790cNick Pelly            boolean result = mDeviceHost.deinitialize();
59731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
59831949217328bf2357ff044f0d18677fe588c790cNick Pelly
59931949217328bf2357ff044f0d18677fe588c790cNick Pelly            watchDog.cancel();
60031949217328bf2357ff044f0d18677fe588c790cNick Pelly
601ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen            synchronized (NfcService.this) {
602ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen                mCurrentDiscoveryParameters = NfcDiscoveryParameters.getNfcOffParameters();
603ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen                updateState(NfcAdapter.STATE_OFF);
604ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen            }
60531949217328bf2357ff044f0d18677fe588c790cNick Pelly
606d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            releaseSoundPool();
607d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen
60831949217328bf2357ff044f0d18677fe588c790cNick Pelly            return result;
60931949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
61031949217328bf2357ff044f0d18677fe588c790cNick Pelly
61131949217328bf2357ff044f0d18677fe588c790cNick Pelly        void updateState(int newState) {
6122a3f6f141fdaf746a81ce850a8ab0ef251041966mike wakerly            synchronized (NfcService.this) {
61331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (newState == mState) {
61431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
61531949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
61631949217328bf2357ff044f0d18677fe588c790cNick Pelly                mState = newState;
61731949217328bf2357ff044f0d18677fe588c790cNick Pelly                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
61831949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
61931949217328bf2357ff044f0d18677fe588c790cNick Pelly                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
620525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
62131949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
62231949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
62331949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
62431949217328bf2357ff044f0d18677fe588c790cNick Pelly
62531949217328bf2357ff044f0d18677fe588c790cNick Pelly    void saveNfcOnSetting(boolean on) {
62631949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (NfcService.this) {
62731949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
62831949217328bf2357ff044f0d18677fe588c790cNick Pelly            mPrefsEditor.apply();
62931949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
6300e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly    }
6310e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
632d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen    public void playSound(int sound) {
633d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        synchronized (this) {
634d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            if (mSoundPool == null) {
635d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                Log.w(TAG, "Not playing sound when NFC is disabled");
636d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                return;
637d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
638d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            switch (sound) {
639d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_START:
640d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
641d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
642d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_END:
643d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
644d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
645d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                case SOUND_ERROR:
646d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
647d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                    break;
648d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen            }
649d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
650d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton    }
651d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
652d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales    synchronized int getUserId() {
653d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales        return mUserId;
654d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales    }
655d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales
656a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen    void setBeamShareActivityState(boolean enabled) {
657b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
658b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        // Propagate the state change to all user profiles related to the current
659b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        // user. Note that the list returned by getUserProfiles contains the
660b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        // current user.
661b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        List <UserHandle> luh = um.getUserProfiles();
662b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        for (UserHandle uh : luh){
663b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            enforceBeamShareActivityPolicy(mContext, uh, enabled);
664b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        }
665b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz    }
666b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz
667b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz    void enforceBeamShareActivityPolicy(Context context, UserHandle uh,
668b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            boolean isGlobalEnabled){
669b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
670b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        IPackageManager mIpm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
671b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        boolean isActiveForUser =
672b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                (!um.hasUserRestriction(UserManager.DISALLOW_OUTGOING_BEAM, uh)) &&
673b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                isGlobalEnabled;
674b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        if (DBG){
675b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            Log.d(TAG, "Enforcing a policy change on user: " + uh +
676b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    ", isActiveForUser = " + isActiveForUser);
677b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        }
678b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        try {
679b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            mIpm.setComponentEnabledSetting(new ComponentName(
680b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    BeamShareActivity.class.getPackageName$(),
681b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    BeamShareActivity.class.getName()),
682b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    isActiveForUser ?
683b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
684b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
685b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                            PackageManager.DONT_KILL_APP,
686b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    uh.getIdentifier());
687b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        } catch (RemoteException e) {
688b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            Log.w(TAG, "Unable to change Beam status for user " + uh);
689b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        }
690a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen    }
6910e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
6924a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class NfcAdapterService extends INfcAdapter.Stub {
693fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
6940e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public boolean enable() throws RemoteException {
6954309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
6960e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
69731949217328bf2357ff044f0d18677fe588c790cNick Pelly            saveNfcOnSetting(true);
6981668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen
6991668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
7001668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                if (!mIsAirplaneToggleable) {
7011668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    Log.i(TAG, "denying enable() request (airplane mode)");
7021668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                    return false;
7031668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                }
7041668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                // Make sure the override survives a reboot
7051668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
7061668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
707f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
70831949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_ENABLE);
70931949217328bf2357ff044f0d18677fe588c790cNick Pelly
71031949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
711f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
712f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
713fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
714290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi        public boolean disable(boolean saveState) throws RemoteException {
7154309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
7160e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
717290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            if (saveState) {
718290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi                saveNfcOnSetting(false);
719290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi            }
720290a6967a04f49dc3969dced9f82c1636a7e7902Sunil Jogi
72131949217328bf2357ff044f0d18677fe588c790cNick Pelly            new EnableDisableTask().execute(TASK_DISABLE);
72231949217328bf2357ff044f0d18677fe588c790cNick Pelly
72331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return true;
724f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
725f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
726dbcee970ef57927e73c269f573d06e2f133a34c1Martijn Coenen        @Override
72742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales        public void pausePolling(int timeoutInMs) {
72842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
72942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
73042c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            if (timeoutInMs <= 0 || timeoutInMs > MAX_POLLING_PAUSE_TIMEOUT) {
73142c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                Log.e(TAG, "Refusing to pause polling for " + timeoutInMs + "ms.");
73242c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                return;
73342c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            }
73442c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
73542c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            synchronized (NfcService.this) {
73642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mPollingPaused = true;
73742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mDeviceHost.disableDiscovery();
73842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mHandler.sendMessageDelayed(
73942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                        mHandler.obtainMessage(MSG_RESUME_POLLING), timeoutInMs);
74042c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            }
74142c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales        }
74242c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
743dbcee970ef57927e73c269f573d06e2f133a34c1Martijn Coenen        @Override
74442c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales        public void resumePolling() {
74542c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
74642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
74742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            synchronized (NfcService.this) {
74842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                if (!mPollingPaused) {
74942c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                    return;
75042c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                }
75142c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
75242c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mHandler.removeMessages(MSG_RESUME_POLLING);
75342c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mPollingPaused = false;
75442c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                new ApplyRoutingTask().execute();
75542c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales            }
75642c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales        }
75742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales
758fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
7590b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean isNdefPushEnabled() throws RemoteException {
76031949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
7619993a5a96a862cea4512509b413d0de6cacb7c14Nick Pelly                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
76231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
763d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
764d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
765d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
7660b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean enableNdefPush() throws RemoteException {
7674309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
7684309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            synchronized (NfcService.this) {
7690b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (mIsNdefPushEnabled) {
77031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
77131949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
7720b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "enabling NDEF Push");
7730b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
77431949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
7750b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = true;
776a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen                setBeamShareActivityState(true);
77731949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
77877d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(true, true);
779d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
780d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
781d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
782d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
783d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
784d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
7850b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public boolean disableNdefPush() throws RemoteException {
7864309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
7874309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            synchronized (NfcService.this) {
7880b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                if (!mIsNdefPushEnabled) {
78931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return true;
79031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
7910b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                Log.i(TAG, "disabling NDEF Push");
7920b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
79331949217328bf2357ff044f0d18677fe588c790cNick Pelly                mPrefsEditor.apply();
7940b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mIsNdefPushEnabled = false;
795a7a09dbc3e681de3054d61b544753cbb8406c649Martijn Coenen                setBeamShareActivityState(false);
79631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isNfcEnabled()) {
79777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.enableDisable(false, true);
798d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                }
799d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            }
800d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen            return true;
801d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        }
802d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen
803d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen        @Override
8040b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly        public void setForegroundDispatch(PendingIntent intent,
80524dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                IntentFilter[] filters, TechListParcel techListsParcel) {
8064309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
807a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
8080b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            // Short-cut the disable path
8090b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            if (intent == null && filters == null && techListsParcel == null) {
8100b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                mNfcDispatcher.setForegroundDispatch(null, null, null);
8110b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly                return;
812ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton            }
813a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
814a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            // Validate the IntentFilters
815a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            if (filters != null) {
816a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                if (filters.length == 0) {
817a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    filters = null;
818a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                } else {
819a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    for (IntentFilter filter : filters) {
820a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        if (filter == null) {
821a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                            throw new IllegalArgumentException("null IntentFilter");
822a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                        }
823a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                    }
824a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton                }
825a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton            }
826a1935861ea244b45e29b0ec9b6f263de3c08a2d6Jeff Hamilton
82724dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            // Validate the tech lists
82824dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            String[][] techLists = null;
82924dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            if (techListsParcel != null) {
83024dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton                techLists = techListsParcel.getTechLists();
83124dbea55709219e42aa3b6b6578f29ffd447a786Jeff Hamilton            }
83249d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
8330b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
8342094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        }
8352094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks
8369340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8372094515fca0cfa0ac87e9cc260d3953d416afe3eJason parks        @Override
83831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public void setAppCallback(IAppCallback callback) {
8394309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
8405c452dad7b24f28223414ce5e953bfcab782570eAndres Morales
841b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales            // don't allow Beam for managed profiles, or devices with a device owner or policy owner
842b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales            UserInfo userInfo = mUserManager.getUserInfo(UserHandle.getCallingUserId());
84365860bb589c5802ffadb14540670408d6c8dfaa9Benjamin Franz            if(!mUserManager.hasUserRestriction(
844b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales                            UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle())) {
8455c452dad7b24f28223414ce5e953bfcab782570eAndres Morales                mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
846b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales            } else if (DBG) {
847b42756d47f39774a07654f68af27bf3cc2c41511Andres Morales                Log.d(TAG, "Disabling default Beam behavior");
8485c452dad7b24f28223414ce5e953bfcab782570eAndres Morales            }
849ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        }
850ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton
851ca1a86ecb8edce740a232c3439355e8d5b706e7aJeff Hamilton        @Override
8525d0258c45b65f1051add13d35ff6adc7b6e67697Martijn Coenen        public void verifyNfcPermission() {
8535d0258c45b65f1051add13d35ff6adc7b6e67697Martijn Coenen            NfcPermissions.enforceUserPermissions(mContext);
8545d0258c45b65f1051add13d35ff6adc7b6e67697Martijn Coenen        }
8555d0258c45b65f1051add13d35ff6adc7b6e67697Martijn Coenen
8565d0258c45b65f1051add13d35ff6adc7b6e67697Martijn Coenen        @Override
8579340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        public void invokeBeam() {
8589340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            NfcPermissions.enforceUserPermissions(mContext);
8599340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
86034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            if (mForegroundUtils.isInForeground(Binder.getCallingUid())) {
8619340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                mP2pLinkManager.onManualBeamInvoke(null);
8629340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            } else {
8639340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                Log.e(TAG, "Calling activity not in foreground.");
8649340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen            }
8659340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        }
8669340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen
8679340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen        @Override
86834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        public void invokeBeamInternal(BeamShareData shareData) {
86934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            NfcPermissions.enforceAdminPermissions(mContext);
87034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            Message msg = Message.obtain();
87134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            msg.what = MSG_INVOKE_BEAM;
87234322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            msg.obj = shareData;
87334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            // We have to send this message delayed for two reasons:
87434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            // 1) This is an IPC call from BeamShareActivity, which is
87534322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    running when the user has invoked Beam through the
87634322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    share menu. As soon as BeamShareActivity closes, the UI
87734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    will need some time to rebuild the original Activity.
87834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    Waiting here for a while gives a better chance of the UI
87934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    having been rebuilt, which means the screenshot that the
88034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    Beam animation is using will be more accurate.
88134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            // 2) Similarly, because the Activity that launched BeamShareActivity
88234322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    with an ACTION_SEND intent is now in paused state, the NDEF
88334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    callbacks that it has registered may no longer be valid.
88434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    Allowing the original Activity to resume will make sure we
88534322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    it has a chance to re-register the NDEF message / callback,
88634322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    so we share the right data.
88734322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //
88834322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    Note that this is somewhat of a hack because the delay may not actually
88934322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    be long enough for 2) on very slow devices, but there's no better
89034322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            //    way to do this right now without additional framework changes.
89134322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen            mHandler.sendMessageDelayed(msg, INVOKE_BEAM_DELAY_MS);
89234322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        }
89334322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen
89434322b73c1e09907cb007e86bae77c744b338cd7Martijn Coenen        @Override
8950e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        public INfcTag getNfcTagInterface() throws RemoteException {
8960e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly            return mNfcTagService;
8970e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
8980e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
899fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
900a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        public INfcCardEmulation getNfcCardEmulationInterface() {
90135b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen            if (mIsHceCapable) {
90235b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen                return mCardEmulationManager.getNfcCardEmulationInterface();
90335b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen            } else {
90435b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen                return null;
90535b004b876ba3d10a8f204beeaa282289ad9b13bMartijn Coenen            }
906a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        }
907a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen
908a0b908c58b5ab0d242ccc545d14573901774bd29Martijn Coenen        @Override
90931949217328bf2357ff044f0d18677fe588c790cNick Pelly        public int getState() throws RemoteException {
91031949217328bf2357ff044f0d18677fe588c790cNick Pelly            synchronized (NfcService.this) {
91131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return mState;
91231949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
91331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
91431949217328bf2357ff044f0d18677fe588c790cNick Pelly
91531949217328bf2357ff044f0d18677fe588c790cNick Pelly        @Override
91631949217328bf2357ff044f0d18677fe588c790cNick Pelly        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
91731949217328bf2357ff044f0d18677fe588c790cNick Pelly            NfcService.this.dump(fd, pw, args);
9180e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
919391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly
920391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        @Override
921ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly        public void dispatch(Tag tag) throws RemoteException {
9224309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
923ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pelly            mNfcDispatcher.dispatchTag(tag);
924391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly        }
9250c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen
9260c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        @Override
9270c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
9284309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
9290c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pInitiatorModes(initiatorModes);
9300c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen            mDeviceHost.setP2pTargetModes(targetModes);
9310799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            applyRouting(true);
9320c39284106d29e8852197d163dcc95c01da29f0dMartijn Coenen        }
933c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
934c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        @Override
93531f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        public void setReaderMode(IBinder binder, IAppCallback callback, int flags, Bundle extras)
93631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                throws RemoteException {
937c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            synchronized (NfcService.this) {
938c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                if (flags != 0) {
939c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    try {
94031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams = new ReaderModeParams();
94131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.callback = callback;
94231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams.flags = flags;
9434309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                        mReaderModeParams.presenceCheckDelay = extras != null
9444309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                                ? (extras.getInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY,
9454309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                                        DEFAULT_PRESENCE_CHECK_DELAY))
9464309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                                : DEFAULT_PRESENCE_CHECK_DELAY;
947c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        binder.linkToDeath(mReaderModeDeathRecipient, 0);
948c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    } catch (RemoteException e) {
949c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        Log.e(TAG, "Remote binder has already died.");
950c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        return;
951c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
952c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                } else {
953c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    try {
95431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        mReaderModeParams = null;
955c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        binder.unlinkToDeath(mReaderModeDeathRecipient, 0);
956c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    } catch (NoSuchElementException e) {
957c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                        Log.e(TAG, "Reader mode Binder was never registered.");
958c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
959c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                }
960c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                applyRouting(false);
961c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            }
962c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        }
963c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen
964c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen        @Override
965c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) throws RemoteException {
966c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen            // nfc-extras implementation is no longer present in AOSP.
967c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen            return null;
968c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen        }
96928a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
97028a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales        @Override
97116ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        public void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, int[] techList) {
97216ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            NfcPermissions.enforceAdminPermissions(mContext);
97316ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
97416ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            int lockscreenPollMask = computeLockscreenPollMask(techList);
97516ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            synchronized (NfcService.this) {
97616ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales                mNfcUnlockManager.addUnlockHandler(unlockHandler, lockscreenPollMask);
97716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            }
97816ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
97916ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            applyRouting(false);
98016ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        }
98116ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
98216ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        @Override
983af05d4f78bca45a13f54444a67c1da09bdd599a3Andres Morales        public void removeNfcUnlockHandler(INfcUnlockHandler token) throws RemoteException {
98416ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            synchronized (NfcService.this) {
985af05d4f78bca45a13f54444a67c1da09bdd599a3Andres Morales                mNfcUnlockManager.removeUnlockHandler(token.asBinder());
98616ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            }
98716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
98816ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales            applyRouting(false);
98916ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales        }
99016ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales
99128a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales        private int computeLockscreenPollMask(int[] techList) {
99228a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
99328a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            Map<Integer, Integer> techCodeToMask = new HashMap<Integer, Integer>();
99428a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
99528a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_A, NfcService.NFC_POLL_A);
996616980fe53b2595f6320d344a6b8ebb0e898485eAndres Morales            techCodeToMask.put(TagTechnology.NFC_B, NfcService.NFC_POLL_B);
99728a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_V, NfcService.NFC_POLL_ISO15693);
99828a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_F, NfcService.NFC_POLL_F);
99928a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            techCodeToMask.put(TagTechnology.NFC_BARCODE, NfcService.NFC_POLL_KOVIO);
100028a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
100128a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            int mask = 0;
100228a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
100328a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            for (int i = 0; i < techList.length; i++) {
100428a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales                if (techCodeToMask.containsKey(techList[i])) {
100528a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales                    mask |= techCodeToMask.get(techList[i]).intValue();
100628a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales                }
100728a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            }
100828a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales
100928a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales            return mask;
101028a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales        }
1011c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    }
1012c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen
1013c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen    final class ReaderModeDeathRecipient implements IBinder.DeathRecipient {
1014c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        @Override
1015c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        public void binderDied() {
1016c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            synchronized (NfcService.this) {
101731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                if (mReaderModeParams != null) {
101831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    mReaderModeParams = null;
1019c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    applyRouting(false);
1020c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                }
1021c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen            }
1022c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen        }
1023c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
10240e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly
10254a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    final class TagService extends INfcTag.Stub {
1026fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1027f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public int close(int nativeHandle) throws RemoteException {
10284309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1029bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1030f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1031f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
103231949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1033f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1034f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1035f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1036f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1037f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1038f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1039b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                /* Remove the device from the hmap */
1040b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                unregisterObject(nativeHandle);
104121545af22f9b913ec9cb124287aab2fcb0cf2b3bNick Pelly                tag.disconnect();
1042b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.SUCCESS;
1043f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1044f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* Restart polling loop for notification */
1045fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            applyRouting(true);
1046f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return ErrorCodes.ERROR_DISCONNECT;
1047f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1048f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1049fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1050ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen        public int connect(int nativeHandle, int technology) throws RemoteException {
10514309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1052bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1053f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1054f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
105531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1056f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1057f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1058f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1059f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1060f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1061b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1062b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return ErrorCodes.ERROR_DISCONNECT;
1063f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1064ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen
1065cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            if (!tag.isPresent()) {
1066cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1067cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen            }
1068cd7f018ec0cff0fcdcfe1399aa2398b809f2e35eMartijn Coenen
1069ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // Note that on most tags, all technologies are behind a single
1070ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // handle. This means that the connect at the lower levels
1071ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            // will do nothing, as the tag is already connected to that handle.
1072ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            if (tag.connect(technology)) {
1073ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.SUCCESS;
1074ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            } else {
1075ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen                return ErrorCodes.ERROR_DISCONNECT;
1076ae7d8d800ba73502d21e54d1deef16be0f061866Martijn Coenen            }
1077f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1078f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1079fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1080aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        public int reconnect(int nativeHandle) throws RemoteException {
10814309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1082aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1083f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1084aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1085aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            // Check if NFC is enabled
108631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1087aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
1088aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1089aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1090aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            /* find the tag in the hmap */
1091f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1092aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            if (tag != null) {
1093aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                if (tag.reconnect()) {
1094aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.SUCCESS;
1095aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                } else {
1096aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                    return ErrorCodes.ERROR_DISCONNECT;
1097aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen                }
1098aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            }
1099aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen            return ErrorCodes.ERROR_DISCONNECT;
1100aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        }
1101aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen
1102aae427142dc22e7e419c146bc7748d9daff518e8Martijn Coenen        @Override
1103b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        public int[] getTechList(int nativeHandle) throws RemoteException {
11044309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1105bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1106f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
110731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1108f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1109f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1110f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1111f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1112f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1113f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1114b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton                return tag.getTechList();
1115f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1116f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1117f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1118f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1119fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1120b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public boolean isPresent(int nativeHandle) throws RemoteException {
1121f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1122b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1123b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            // Check if NFC is enabled
112431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1125b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1126b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1127b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1128b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            /* find the tag in the hmap */
1129f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1130b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            if (tag == null) {
1131b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau                return false;
1132b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau            }
1133b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1134ab2b44b97936d2c5dbf6eda1245ca793e840713fMartijn Coenen            return tag.isPresent();
1135b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1136b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1137fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1138f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        public boolean isNdef(int nativeHandle) throws RemoteException {
11394309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1140182152b054d555fc4ac5d5c2cd2367cb8c205782Martijn Coenen
1141f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1142f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1143f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
114431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
11452c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1146f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1147f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1148f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1149f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
11503ba3b10867c36bff57b72ff99c7b56d63d418f3fMartijn Coenen            int[] ndefInfo = new int[2];
11512c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas            if (tag == null) {
11522c3f9be8111dd454e430ffb327c051ff9d2bba21Daniel Tomas                return false;
1153f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
115470bbea61637e3f9eb7202efd243b9d2f9516a06aNick Pelly            return tag.checkNdef(ndefInfo);
1155f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1156f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1157fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11589d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
115997c6942c7c7f9df3bb8dbcc01cf7bb6e2e090005Martijn Coenen                throws RemoteException {
11604309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1161bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1162f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
1163f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            byte[] response;
1164f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1165f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
116631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1167f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1168f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1169f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1170f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1171f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1172f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1173bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                // Check if length is within limits
1174bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1175bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1176bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
11779d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                int[] targetLost = new int[1];
11789d5511f2640903a79d24578a12a93e50a96f0c0eMartijn Coenen                response = tag.transceive(data, raw, targetLost);
1179bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                int result;
1180bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                if (response != null) {
1181bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_SUCCESS;
1182bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else if (targetLost[0] == 1) {
1183bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_TAGLOST;
1184bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                } else {
1185bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                    result = TransceiveResult.RESULT_FAILURE;
1186bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                }
1187bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen                return new TransceiveResult(result, response);
1188f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1189f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1190f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1191f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1192fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
11933fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
11944309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1195bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1196f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1197f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1198f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
119931949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1200f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return null;
1201f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1202f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1203f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1204f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1205f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag != null) {
1206f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                byte[] buf = tag.readNdef();
1207f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                if (buf == null) {
1208f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1209f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                }
1210f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1211f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                /* Create an NdefMessage */
1212f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                try {
1213f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return new NdefMessage(buf);
1214f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                } catch (FormatException e) {
1215f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                    return null;
1216f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                }
1217f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1218f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            return null;
1219f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1220f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1221fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12223fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
12234309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1224bebaa6cc1a1eb2ce0656e17b0e09ed4747878d8eNick Pelly
1225f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
1226f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1227f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            // Check if NFC is enabled
122831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
1229f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_NOT_INITIALIZED;
1230f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1231f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1232f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            /* find the tag in the hmap */
1233f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
1234f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            if (tag == null) {
1235f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1236f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1237f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1238791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1239791ab7ad5b2fafaa4587d9ba7fb0fe39a815f278Martijn Coenen
1240f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.writeNdef(msg.toByteArray())) {
1241f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.SUCCESS;
1242f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
1243f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly                return ErrorCodes.ERROR_IO;
1244f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
1245f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1246f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1247f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1248fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12493fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
12503fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            throw new UnsupportedOperationException();
1251f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1252f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
1253fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
12543fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
12554309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
125603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1257f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
125803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
125903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            // Check if NFC is enabled
126031949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
126103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
126203ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
126303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
126403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            /* find the tag in the hmap */
1265f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
126603ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            if (tag == null) {
126703ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
126803ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
126903ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen
1270f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            if (tag.makeReadOnly()) {
127103ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.SUCCESS;
1272f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
127303ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen                return ErrorCodes.ERROR_IO;
127403ee488afaa982ce934c5de399db9f9fa88c7d1eMartijn Coenen            }
1275f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1276f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
12770aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        @Override
12780aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
12794309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
12800aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
1281f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag;
12820aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12830aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            // Check if NFC is enabled
128431949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
12850aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_NOT_INITIALIZED;
12860aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12870aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12880aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            /* find the tag in the hmap */
1289f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
12900aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag == null) {
12910aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
12920aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12930aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
12940aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            if (tag.formatNdef(key)) {
12950aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.SUCCESS;
1296f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            } else {
12970aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen                return ErrorCodes.ERROR_IO;
12980aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen            }
12990aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen        }
13000aac9419555e69512a886a6b7fa6ce2d1947c72fMartijn Coenen
13011b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
13023fb14d0868594c78a777e805545209636814e223Martijn Coenen        public Tag rediscover(int nativeHandle) throws RemoteException {
13034309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
13043fb14d0868594c78a777e805545209636814e223Martijn Coenen
1305f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            TagEndpoint tag = null;
13063fb14d0868594c78a777e805545209636814e223Martijn Coenen
13073fb14d0868594c78a777e805545209636814e223Martijn Coenen            // Check if NFC is enabled
130831949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (!isNfcEnabled()) {
13093fb14d0868594c78a777e805545209636814e223Martijn Coenen                return null;
13103fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
13113fb14d0868594c78a777e805545209636814e223Martijn Coenen
13123fb14d0868594c78a777e805545209636814e223Martijn Coenen            /* find the tag in the hmap */
1313f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            tag = (TagEndpoint) findObject(nativeHandle);
13143fb14d0868594c78a777e805545209636814e223Martijn Coenen            if (tag != null) {
13153fb14d0868594c78a777e805545209636814e223Martijn Coenen                // For now the prime usecase for rediscover() is to be able
13163fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to access the NDEF technology after formatting without
13173fb14d0868594c78a777e805545209636814e223Martijn Coenen                // having to remove the tag from the field, or similar
13183fb14d0868594c78a777e805545209636814e223Martijn Coenen                // to have access to NdefFormatable in case low-level commands
13193fb14d0868594c78a777e805545209636814e223Martijn Coenen                // were used to remove NDEF. So instead of doing a full stack
13203fb14d0868594c78a777e805545209636814e223Martijn Coenen                // rediscover (which is poorly supported at the moment anyway),
13213fb14d0868594c78a777e805545209636814e223Martijn Coenen                // we simply remove these two technologies and detect them
13223fb14d0868594c78a777e805545209636814e223Martijn Coenen                // again.
13233fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF);
13243fb14d0868594c78a777e805545209636814e223Martijn Coenen                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1325391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                tag.findAndReadNdef();
13263fb14d0868594c78a777e805545209636814e223Martijn Coenen                // Build a new Tag object to return
13273fb14d0868594c78a777e805545209636814e223Martijn Coenen                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
13284a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton                        tag.getTechExtras(), tag.getHandle(), this);
13293fb14d0868594c78a777e805545209636814e223Martijn Coenen                return newTag;
13303fb14d0868594c78a777e805545209636814e223Martijn Coenen            }
13313fb14d0868594c78a777e805545209636814e223Martijn Coenen            return null;
13323fb14d0868594c78a777e805545209636814e223Martijn Coenen        }
13333fb14d0868594c78a777e805545209636814e223Martijn Coenen
13341b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        @Override
1335fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen        public int setTimeout(int tech, int timeout) throws RemoteException {
13364309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1337f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            boolean success = mDeviceHost.setTimeout(tech, timeout);
1338fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            if (success) {
1339fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.SUCCESS;
1340fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            } else {
1341fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen                return ErrorCodes.ERROR_INVALID_PARAM;
1342fbd90779b1525b254726eb58d07883ca74e1b21cMartijn Coenen            }
1343dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        }
1344dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1345dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        @Override
1346358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        public int getTimeout(int tech) throws RemoteException {
13474309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1348358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1349358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen            return mDeviceHost.getTimeout(tech);
1350358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        }
1351358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen
1352358d8b6ad611aba11e69a3b1dd9d132dbc9a7605Martijn Coenen        @Override
1353dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen        public void resetTimeouts() throws RemoteException {
13544309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            NfcPermissions.enforceUserPermissions(mContext);
1355dfebdbf803bf01404255f964e571056aa84173caMartijn Coenen
1356f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            mDeviceHost.resetTimeouts();
13571b61f1dee91101e249b9be65d95366fa745b3b78Martijn Coenen        }
1358bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1359bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1360bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1361bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.canMakeReadOnly(ndefType);
1362bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1363bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen
1364bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        @Override
1365bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        public int getMaxTransceiveLength(int tech) throws RemoteException {
1366bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen            return mDeviceHost.getMaxTransceiveLength(tech);
1367bf6e5d1655d5ad524a8ec007413c7011ed969df8Martijn Coenen        }
1368ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen
1369ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        @Override
1370ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1371ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen            return mDeviceHost.getExtendedLengthApdusSupported();
1372ba15143ff54f5078f9b2cef5804525d387c52c72Martijn Coenen        }
1373c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly    }
1374f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
13759a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    boolean isNfcEnabledOrShuttingDown() {
13769a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        synchronized (this) {
13779a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
13789a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        }
13799a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen    }
13809a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen
138131949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isNfcEnabled() {
138231949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
138331949217328bf2357ff044f0d18677fe588c790cNick Pelly            return mState == NfcAdapter.STATE_ON;
1384e7a398f2f0256a4a80a4ee08b70d48dbfd8da6d2Nick Pelly        }
1385aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly    }
1386aa122139d77645149c09c9815fd45e7b87ce7170Nick Pelly
138731949217328bf2357ff044f0d18677fe588c790cNick Pelly    class WatchDogThread extends Thread {
1388a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        final Object mCancelWaiter = new Object();
1389525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        final int mTimeout;
1390a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project        boolean mCanceled = false;
1391525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
1392525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public WatchDogThread(String threadName, int timeout) {
1393525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            super(threadName);
1394525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            mTimeout = timeout;
1395525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        }
1396525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project
13972edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        @Override
13982edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public void run() {
1399a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            try {
1400a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                synchronized (mCancelWaiter) {
1401a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    mCancelWaiter.wait(mTimeout);
1402a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    if (mCanceled) {
1403a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                        return;
1404a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                    }
14052edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly                }
1406a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            } catch (InterruptedException e) {
1407a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                // Should not happen; fall-through to abort.
1408a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                Log.w(TAG, "Watchdog thread interruped.");
1409a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                interrupt();
14102edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly            }
1411a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            Log.e(TAG, "Watchdog triggered, aborting.");
1412a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            mDeviceHost.doAbort();
14132edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
1414a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project
14152edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        public synchronized void cancel() {
1416a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            synchronized (mCancelWaiter) {
1417a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCanceled = true;
1418a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project                mCancelWaiter.notify();
1419a1af766ba0b1fc5a016b796f76c29f56519dec15The Android Open Source Project            }
14202edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly        }
14212edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly    }
14222edb3ee5e28ab719a3bb17b8d76b2b588405be9aNick Pelly
14239f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    static byte[] hexStringToBytes(String s) {
14249f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (s == null || s.length() == 0) return null;
14259f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        int len = s.length();
14269f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        if (len % 2 != 0) {
14279f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            s = '0' + s;
14289f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            len++;
14299f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
14309f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        byte[] data = new byte[len / 2];
14319f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        for (int i = 0; i < len; i += 2) {
14329f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
14334309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    + Character.digit(s.charAt(i + 1), 16));
14349f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        }
14359f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen        return data;
14369f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
14379f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1438fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    /**
1439fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1440fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly     */
1441fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    void applyRouting(boolean force) {
1442e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton        synchronized (this) {
1443c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen            if (!isNfcEnabledOrShuttingDown()) {
1444e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton                return;
1445e0b5fcb7e6422d1a788c48dd8f2936832ab8b397Jeff Hamilton            }
1446525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
14477d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            if (mInProvisionMode) {
14487d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
14497d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
14507d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                if (!mInProvisionMode) {
14517d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // Notify dispatcher it's fine to dispatch to any package now
14527d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    // and allow handover transfers.
14537d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                    mNfcDispatcher.disableProvisioningMode();
14547d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                }
14557d8987f233985a5ff29226890e11012275d325f5Martijn Coenen            }
14560799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // Special case: if we're transitioning to unlocked state while
14570799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // still talking to a tag, postpone re-configuration.
14580799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && isTagPresent()) {
14590799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                Log.d(TAG, "Not updating discovery parameters, tag connected.");
146042c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESUME_POLLING),
146142c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                        APPLY_ROUTING_RETRY_TIMEOUT_MS);
14620799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                return;
14630799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            }
14640799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales
1465f439271150e4548f116919e0254d57655421581cMartijn Coenen            try {
1466f439271150e4548f116919e0254d57655421581cMartijn Coenen                watchDog.start();
14670799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                // Compute new polling parameters
14680799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                NfcDiscoveryParameters newParams = computeDiscoveryParameters(mScreenState);
14690799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if (force || !newParams.equals(mCurrentDiscoveryParameters)) {
14700799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    if (newParams.shouldEnableDiscovery()) {
1471ffeeef8e8d6d5f7c15f9f041d691cd9b64ddc58bMartijn Coenen                        boolean shouldRestart = mCurrentDiscoveryParameters.shouldEnableDiscovery();
14720799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                        mDeviceHost.enableDiscovery(newParams, shouldRestart);
14730799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    } else {
1474a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales                        mDeviceHost.disableDiscovery();
1475a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales                    }
14760799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    mCurrentDiscoveryParameters = newParams;
14770799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                } else {
14780799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    Log.d(TAG, "Discovery configuration equal, not updating.");
1479fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                }
1480a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales            } finally {
1481a1e95d30dbe8dad0a8bb333b4ca17c009fc34e2fAndres Morales                watchDog.cancel();
1482221b4d6ee301fbfe19402798f7d3c11e6878c888daniel_tomas            }
148365945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly        }
148465945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly    }
148565945ad77cadb7a3bdf171497877d2325b23def5Nick Pelly
14860799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales    private NfcDiscoveryParameters computeDiscoveryParameters(int screenState) {
14870799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        // Recompute discovery parameters based on screen state
14880799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        NfcDiscoveryParameters.Builder paramsBuilder = NfcDiscoveryParameters.newBuilder();
14890799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        // Polling
14900799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        if (screenState >= NFC_POLLING_MODE) {
14910799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // Check if reader-mode is enabled
14920799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            if (mReaderModeParams != null) {
14930799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                int techMask = 0;
14940799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_A) != 0)
14950799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_A;
14960799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_B) != 0)
14970799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_B;
14980799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_F) != 0)
14990799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_F;
15000799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_V) != 0)
15010799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_ISO15693;
15020799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_BARCODE) != 0)
15030799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    techMask |= NFC_POLL_KOVIO;
15040799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales
15050799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                paramsBuilder.setTechMask(techMask);
15060799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                paramsBuilder.setEnableReaderMode(true);
15070799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            } else {
15080799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
150931b0f4653686119d74876cae5d637c5baf52b935Andres Morales                paramsBuilder.setEnableP2p(mIsNdefPushEnabled);
15100799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            }
15110799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mInProvisionMode) {
15120799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
151331b0f4653686119d74876cae5d637c5baf52b935Andres Morales            // enable P2P for MFM/EDU/Corp provisioning
151431b0f4653686119d74876cae5d637c5baf52b935Andres Morales            paramsBuilder.setEnableP2p(true);
15150799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED &&
1516731fd8a52cec0dbe8d6ec6a4c7aa36ff52812112Andres Morales                mNfcUnlockManager.isLockscreenPollingEnabled()) {
15170799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // For lock-screen tags, no low-power polling
1518731fd8a52cec0dbe8d6ec6a4c7aa36ff52812112Andres Morales            paramsBuilder.setTechMask(mNfcUnlockManager.getLockscreenPollMask());
15190799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            paramsBuilder.setEnableLowPowerDiscovery(false);
152031b0f4653686119d74876cae5d637c5baf52b935Andres Morales            paramsBuilder.setEnableP2p(false);
1521a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales        }
1522a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales
15230799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        if (mIsHceCapable && mScreenState >= ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
15240799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            // Host routing is always enabled at lock screen or later
15250799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            paramsBuilder.setEnableHostRouting(true);
15260799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        }
152731b0f4653686119d74876cae5d637c5baf52b935Andres Morales
15280799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales        return paramsBuilder.build();
1529a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales    }
1530a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales
1531a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales    private boolean isTagPresent() {
1532a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales        for (Object object : mObjectMap.values()) {
1533a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales            if (object instanceof TagEndpoint) {
1534a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                return ((TagEndpoint) object).isPresent();
1535a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales            }
1536a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales        }
1537a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales        return false;
1538a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales    }
15394309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
15404309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * Disconnect any target if present
15414309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
154231949217328bf2357ff044f0d18677fe588c790cNick Pelly    void maybeDisconnectTarget() {
15439a93cf5cf4b845c7983f202fe0e03615f31f6db0Martijn Coenen        if (!isNfcEnabledOrShuttingDown()) {
1544a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly            return;
1545a8b7cca914e4a17f5c432f7bbeed0f1b236c55b4Nick Pelly        }
154631949217328bf2357ff044f0d18677fe588c790cNick Pelly        Object[] objectsToDisconnect;
154731949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
154831949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object[] objectValues = mObjectMap.values().toArray();
154931949217328bf2357ff044f0d18677fe588c790cNick Pelly            // Copy the array before we clear mObjectMap,
155031949217328bf2357ff044f0d18677fe588c790cNick Pelly            // just in case the HashMap values are backed by the same array
155131949217328bf2357ff044f0d18677fe588c790cNick Pelly            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
155231949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.clear();
155331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
155431949217328bf2357ff044f0d18677fe588c790cNick Pelly        for (Object o : objectsToDisconnect) {
155531949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
155631949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (o instanceof TagEndpoint) {
155731949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from tags
155831949217328bf2357ff044f0d18677fe588c790cNick Pelly                TagEndpoint tag = (TagEndpoint) o;
155931949217328bf2357ff044f0d18677fe588c790cNick Pelly                tag.disconnect();
156031949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (o instanceof NfcDepEndpoint) {
156131949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Disconnect from P2P devices
156231949217328bf2357ff044f0d18677fe588c790cNick Pelly                NfcDepEndpoint device = (NfcDepEndpoint) o;
156331949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
156431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is target, request disconnection
156531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    device.disconnect();
156631949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else {
156731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Remote peer is initiator, we cannot disconnect
156831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    // Just wait for field removal
1569bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks                }
1570bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks            }
1571bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks        }
1572bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks    }
1573bcd6a9954c5abafc6b14aabcc7768d0f03cc956cJason parks
157431949217328bf2357ff044f0d18677fe588c790cNick Pelly    Object findObject(int key) {
157531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
157631949217328bf2357ff044f0d18677fe588c790cNick Pelly            Object device = mObjectMap.get(key);
157731949217328bf2357ff044f0d18677fe588c790cNick Pelly            if (device == null) {
157831949217328bf2357ff044f0d18677fe588c790cNick Pelly                Log.w(TAG, "Handle not found");
15792f8ac1e6cdeb32569bc6477d53a2d0d5608758b1Nick Pelly            }
158031949217328bf2357ff044f0d18677fe588c790cNick Pelly            return device;
15810e6a0a0f50132e14d5ecad61c46e07c67fbb26fbNick Pelly        }
1582f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1583f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
158431949217328bf2357ff044f0d18677fe588c790cNick Pelly    void registerTagObject(TagEndpoint tag) {
158531949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
158631949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.put(tag.getHandle(), tag);
1587f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
1588b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1589b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
159031949217328bf2357ff044f0d18677fe588c790cNick Pelly    void unregisterObject(int handle) {
159131949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
159231949217328bf2357ff044f0d18677fe588c790cNick Pelly            mObjectMap.remove(handle);
159331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
1594f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    }
1595f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly
15964309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
15974309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * For use by code in this process
15984309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
15994a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1600c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            throws LlcpException {
16014a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1602d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1603d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
16044309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
16054309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * For use by code in this process
16064309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
16073b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
1608e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen            throws LlcpException {
16093b82eef50f734cab061330f55de8b8bf5396f24bMartijn Coenen        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
1610e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen    }
1611e008eba3b51c5303d52bf3e9e989dfd03b18435aMartijn Coenen
16124309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
16134309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * For use by code in this process
16144309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
16154a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1616c9342fef947c49e247495b83f94f16d43cd3562cmike wakerly            int linearBufferLength) throws LlcpException {
16174a61d3b45e81c0070538f94747a70a49c78f12faJeff Hamilton        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1618d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton    }
1619d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
162057d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    public void sendMockNdefTag(NdefMessage msg) {
1621b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton        sendMessage(MSG_MOCK_NDEF, msg);
162257d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton    }
162357d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
1624d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void routeAids(String aid, int route) {
1625d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        Message msg = mHandler.obtainMessage();
1626d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.what = MSG_ROUTE_AID;
1627d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.arg1 = route;
1628d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        msg.obj = aid;
1629d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendMessage(msg);
1630d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1631d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
1632d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void unrouteAids(String aid) {
1633d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        sendMessage(MSG_UNROUTE_AID, aid);
1634d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1635d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
1636d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    public void commitRouting() {
1637d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen        mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
1638d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen    }
1639d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen
16404309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    public boolean sendData(byte[] data) {
16414309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales        return mDeviceHost.sendRawFrame(data);
16429f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen    }
16439f8f6cf9c58405ecafe2d425801e6c14088db8c7Martijn Coenen
1644b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    void sendMessage(int what, Object obj) {
1645b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        Message msg = mHandler.obtainMessage();
1646b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.what = what;
1647b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        msg.obj = obj;
1648b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        mHandler.sendMessage(msg);
1649b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau    }
1650b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
16513fb14d0868594c78a777e805545209636814e223Martijn Coenen    final class NfcServiceHandler extends Handler {
1652b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        @Override
1653b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        public void handleMessage(Message msg) {
165431949217328bf2357ff044f0d18677fe588c790cNick Pelly            switch (msg.what) {
1655d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_ROUTE_AID: {
1656d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    int route = msg.arg1;
1657d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
1658d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.routeAid(hexStringToBytes(aid), route);
1659d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    // Restart polling config
1660d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1661d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
1662d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_UNROUTE_AID: {
1663d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    String aid = (String) msg.obj;
1664d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    mDeviceHost.unrouteAid(hexStringToBytes(aid));
1665d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1666d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
16679340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                case MSG_INVOKE_BEAM: {
16689340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    mP2pLinkManager.onManualBeamInvoke((BeamShareData)msg.obj);
16699340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                    break;
16709340b42304a512cb8fe9f4c068ba1b908876fb10Martijn Coenen                }
1671d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                case MSG_COMMIT_ROUTING: {
1672f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    boolean commit = false;
1673f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    synchronized (NfcService.this) {
1674f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                        if (mCurrentDiscoveryParameters.shouldEnableDiscovery()) {
1675f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                            commit = true;
1676f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                        } else {
1677f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                            Log.d(TAG, "Not committing routing because discovery is disabled.");
1678f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                        }
1679f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    }
1680f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    if (commit) {
1681f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                        mDeviceHost.commitRouting();
1682f5c979220fadb2c3ac0bca09e16d0d281ed20eb2Martijn Coenen                    }
1683d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                    break;
1684d53c2b599c73f7404b5a604be4d9a5449cafdd72Martijn Coenen                }
168531949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_MOCK_NDEF: {
168631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
168731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Bundle extras = new Bundle();
168831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
168931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
169031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
169131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
16924309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    Tag tag = Tag.createMockTag(new byte[]{0x00},
16934309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                            new int[]{TagTechnology.NDEF},
16944309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                            new Bundle[]{extras});
169531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
169631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, tag.toString());
169732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales                    int dispatchStatus = mNfcDispatcher.dispatchTag(tag);
169832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales                    if (dispatchStatus == NfcDispatcher.DISPATCH_SUCCESS) {
1699d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_END);
170032cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales                    } else if (dispatchStatus == NfcDispatcher.DISPATCH_FAIL) {
1701d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                        playSound(SOUND_ERROR);
170231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
170331949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
170431949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
170557d376f1ee1a3939977b95759525585abb9601fbJeff Hamilton
170631949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_NDEF_TAG:
170731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
170831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    TagEndpoint tag = (TagEndpoint) msg.obj;
170931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    ReaderModeParams readerParams = null;
171031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    int presenceCheckDelay = DEFAULT_PRESENCE_CHECK_DELAY;
1711a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                    DeviceHost.TagDisconnectedCallback callback =
1712a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                            new DeviceHost.TagDisconnectedCallback() {
1713a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                                @Override
1714a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                                public void onTagDisconnected(long handle) {
1715a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                                    applyRouting(false);
1716a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                                }
1717a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                            };
1718c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    synchronized (NfcService.this) {
171931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        readerParams = mReaderModeParams;
1720c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
172131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if (readerParams != null) {
172231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        presenceCheckDelay = readerParams.presenceCheckDelay;
172331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
172431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
1725a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                            tag.startPresenceChecking(presenceCheckDelay, callback);
172631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            dispatchTagEndpoint(tag, readerParams);
172731f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            break;
172831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        }
172931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    }
17303e8b9a06407baa7c17e6f4c6bac20e0a3deaef31Andres Morales
17313e8b9a06407baa7c17e6f4c6bac20e0a3deaef31Andres Morales                    boolean playSound = readerParams == null ||
17323e8b9a06407baa7c17e6f4c6bac20e0a3deaef31Andres Morales                        (readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0;
17333e8b9a06407baa7c17e6f4c6bac20e0a3deaef31Andres Morales                    if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && playSound) {
173431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        playSound(SOUND_START);
1735c4e4277a71c70e96198cb760676ad3b40f9e0e3dMartijn Coenen                    }
173689baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
173789baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // When these tags start containing NDEF, they will require
173889baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // the stack to deal with them in a different way, since
173989baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // they are activated only really shortly.
174089baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        // For now, don't consider NDEF on these.
174189baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
1742a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                        tag.startPresenceChecking(presenceCheckDelay, callback);
174331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        dispatchTagEndpoint(tag, readerParams);
174489baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                        break;
174589baa7140bbc7899e8c2735bcfd69021a1240487Martijn Coenen                    }
1746391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    NdefMessage ndefMsg = tag.findAndReadNdef();
1747c9a2ae7cb238e4c72818d084cba0b05e76cba1efdaniel_tomas
1748391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly                    if (ndefMsg != null) {
1749a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                        tag.startPresenceChecking(presenceCheckDelay, callback);
175031f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        dispatchTagEndpoint(tag, readerParams);
175131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    } else {
175231949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (tag.reconnect()) {
1753a30388eb7ddeabe1c9b85d49a65b82aac6a845caAndres Morales                            tag.startPresenceChecking(presenceCheckDelay, callback);
175431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                            dispatchTagEndpoint(tag, readerParams);
175531949217328bf2357ff044f0d18677fe588c790cNick Pelly                        } else {
175631949217328bf2357ff044f0d18677fe588c790cNick Pelly                            tag.disconnect();
1757d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                            playSound(SOUND_ERROR);
175831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
175931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
176031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
176131949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_ACTIVATION:
176296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
176396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent actIntent = new Intent(ACTION_LLCP_UP);
176496e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(actIntent);
176596e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
176631949217328bf2357ff044f0d18677fe588c790cNick Pelly                    llcpActivated((NfcDepEndpoint) msg.obj);
176731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
176831949217328bf2357ff044f0d18677fe588c790cNick Pelly
176931949217328bf2357ff044f0d18677fe588c790cNick Pelly                case MSG_LLCP_LINK_DEACTIVATED:
177096e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    if (mIsDebugBuild) {
177196e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
177296e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                        mContext.sendBroadcast(deactIntent);
177396e8f30552ad5b420cc89b97ffdc486962701afaMartijn Coenen                    }
177431949217328bf2357ff044f0d18677fe588c790cNick Pelly                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
177531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    boolean needsDisconnect = false;
177631949217328bf2357ff044f0d18677fe588c790cNick Pelly
177731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
177831949217328bf2357ff044f0d18677fe588c790cNick Pelly                    synchronized (NfcService.this) {
177931949217328bf2357ff044f0d18677fe588c790cNick Pelly                        /* Check if the device has been already unregistered */
178031949217328bf2357ff044f0d18677fe588c790cNick Pelly                        if (mObjectMap.remove(device.getHandle()) != null) {
178131949217328bf2357ff044f0d18677fe588c790cNick Pelly                            /* Disconnect if we are initiator */
178231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
178331949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "disconnecting from target");
178431949217328bf2357ff044f0d18677fe588c790cNick Pelly                                needsDisconnect = true;
178531949217328bf2357ff044f0d18677fe588c790cNick Pelly                            } else {
178631949217328bf2357ff044f0d18677fe588c790cNick Pelly                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
178731949217328bf2357ff044f0d18677fe588c790cNick Pelly                            }
178831949217328bf2357ff044f0d18677fe588c790cNick Pelly                        }
178931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
179031949217328bf2357ff044f0d18677fe588c790cNick Pelly                    if (needsDisconnect) {
179131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        device.disconnect();  // restarts polling loop
179231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    }
179331949217328bf2357ff044f0d18677fe588c790cNick Pelly
179477d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                    mP2pLinkManager.onLlcpDeactivated();
179531949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
179657a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                case MSG_LLCP_LINK_FIRST_PACKET:
179757a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    mP2pLinkManager.onLlcpFirstPacketReceived();
179857a44d07a3de327e8cdbbcd622118aa517313dbeMartijn Coenen                    break;
1799c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                case MSG_RF_FIELD_ACTIVATED:
1800c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    Intent fieldOnIntent = new Intent(ACTION_RF_FIELD_ON_DETECTED);
1801c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    sendNfcEeAccessProtectedBroadcast(fieldOnIntent);
1802c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    break;
1803c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                case MSG_RF_FIELD_DEACTIVATED:
1804c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    Intent fieldOffIntent = new Intent(ACTION_RF_FIELD_OFF_DETECTED);
1805c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    sendNfcEeAccessProtectedBroadcast(fieldOffIntent);
1806dbcee970ef57927e73c269f573d06e2f133a34c1Martijn Coenen                    break;
180742c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                case MSG_RESUME_POLLING:
180842c0f35783e2849de525cdbe743c95c197fdcf50Andres Morales                    mNfcAdapter.resumePolling();
1809c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    break;
181031949217328bf2357ff044f0d18677fe588c790cNick Pelly                default:
181131949217328bf2357ff044f0d18677fe588c790cNick Pelly                    Log.e(TAG, "Unknown message received");
181231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    break;
181331949217328bf2357ff044f0d18677fe588c790cNick Pelly            }
1814b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau        }
1815d0ec3981792e38afd119fc1c995f111f6182f6c8Jeff Hamilton
1816c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        private void sendNfcEeAccessProtectedBroadcast(Intent intent) {
1817c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
1818c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            // Resume app switches so the receivers can start activites without delay
1819c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            mNfcDispatcher.resumeAppSwitches();
1820d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen            ArrayList<String> matchingPackages = new ArrayList<String>();
1821d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen            ArrayList<String> preferredPackages = new ArrayList<String>();
1822c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            synchronized (this) {
1823c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                for (PackageInfo pkg : mInstalledPackages) {
1824c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    if (pkg != null && pkg.applicationInfo != null) {
1825c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                        if (mNfceeAccessControl.check(pkg.applicationInfo)) {
1826d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                            matchingPackages.add(pkg.packageName);
1827d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                            if (mCardEmulationManager != null &&
1828d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                                    mCardEmulationManager.packageHasPreferredService(pkg.packageName)) {
1829d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                                preferredPackages.add(pkg.packageName);
1830d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                            }
1831c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                        }
1832c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    }
1833c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                }
1834d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                if (preferredPackages.size() > 0) {
1835d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                    // If there's any packages in here which are preferred, only
1836d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                    // send field events to those packages, to prevent other apps
1837d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                    // with signatures in nfcee_access.xml from acting upon the events.
1838d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                    for (String packageName : preferredPackages){
1839d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                        intent.setPackage(packageName);
1840d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                        mContext.sendBroadcast(intent);
1841d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                    }
1842d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                } else {
1843d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                    for (String packageName : matchingPackages){
1844d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                        intent.setPackage(packageName);
1845d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                        mContext.sendBroadcast(intent);
1846d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                    }
1847d943597d17fb8aa462b119040334478756f9e2f9Martijn Coenen                }
1848c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            }
1849c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        }
1850c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
1851d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        private boolean llcpActivated(NfcDepEndpoint device) {
1852d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            Log.d(TAG, "LLCP Activation message");
1853d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1854d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1855d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1856d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (device.connect()) {
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, "Initiator 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                        } else {
1869d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            /* should not happen */
1870d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1871d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                            device.disconnect();
1872d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        }
1873d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    } else {
1874d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1875d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        device.disconnect();
1876d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1877d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1878d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1879d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /*
1880d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * The polling loop should have been restarted in failing
1881d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     * doConnect
1882d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                     */
1883d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1884d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1885d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1886d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                /* Check LLCP compliancy */
1887d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                if (mDeviceHost.doCheckLlcp()) {
1888d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    /* Activate LLCP Link */
1889d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    if (mDeviceHost.doActivateLlcp()) {
1890d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
189131949217328bf2357ff044f0d18677fe588c790cNick Pelly                        synchronized (NfcService.this) {
189231949217328bf2357ff044f0d18677fe588c790cNick Pelly                            // Register P2P device
189331949217328bf2357ff044f0d18677fe588c790cNick Pelly                            mObjectMap.put(device.getHandle(), device);
1894d9567994fefe21743131adc7390acdb97f81ed67Martijn Coenen                        }
189577d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly                        mP2pLinkManager.onLlcpActivated();
1896d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                        return true;
1897d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    }
1898d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                } else {
1899d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                    Log.w(TAG, "checkLlcp failed");
1900d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton                }
1901d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            }
1902d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
1903d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton            return false;
1904d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton        }
1905d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton
190631f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, ReaderModeParams readerParams) {
1907f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
1908f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
1909f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton            registerTagObject(tagEndpoint);
19103dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen            if (readerParams != null) {
191131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                try {
191231f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    if ((readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
191331f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                        playSound(SOUND_END);
191431f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                    }
19153dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    if (readerParams.callback != null) {
19163dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        readerParams.callback.onTagDiscovered(tag);
19173dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        return;
19183dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    } else {
19193dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                        // Follow normal dispatch below
19203dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    }
192131f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                } catch (RemoteException e) {
19220799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    Log.e(TAG, "Reader mode remote has died, falling back.", e);
19233dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    // Intentional fall-through
19243dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                } catch (Exception e) {
19253dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    // Catch any other exception
19260799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales                    Log.e(TAG, "App exception, not dispatching.", e);
19273dd24ecefb71ce4f585faa002ba1054a0c6dbd06Martijn Coenen                    return;
192831f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen                }
192931f39aee25964dad1038b7a9cc335d5a386113c8Martijn Coenen            }
193032cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales            int dispatchResult = mNfcDispatcher.dispatchTag(tag);
193132cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales            if (dispatchResult == NfcDispatcher.DISPATCH_FAIL) {
1932f6c56a2191d58e3f9f68e3e7d94908b04b9b66ffJeff Hamilton                unregisterObject(tagEndpoint.getHandle());
1933d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_ERROR);
193432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales            } else if (dispatchResult == NfcDispatcher.DISPATCH_SUCCESS) {
1935d92037714c289cffb9ed1e6e6df36cd3b7292a21Martijn Coenen                playSound(SOUND_END);
19363fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton            }
19373fb30ae5bf51d9ffe6271a345d55905dade8040dJeff Hamilton        }
1938b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    }
1939b230214bcb557184cb54174889cbede53b92d54fSylvain Fonteneau
1940b74200f40f9d4f536b8782974d444f1f9178076fJeff Hamilton    private NfcServiceHandler mHandler = new NfcServiceHandler();
194149d53329a0c720a7e430220d77805bc1763545b1Nick Pelly
1942fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
1943fa746bcc16d57ff12d373b9139558f5bc7164b30Jason parks        @Override
1944fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly        protected Void doInBackground(Integer... params) {
1945fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly            synchronized (NfcService.this) {
1946fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                if (params == null || params.length != 1) {
1947fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    // force apply current routing
1948fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    applyRouting(true);
1949fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                    return null;
1950161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
1951fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                mScreenState = params[0].intValue();
1952fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly
1953525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                mRoutingWakeLock.acquire();
1954525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                try {
1955525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    applyRouting(false);
1956525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } finally {
1957525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    mRoutingWakeLock.release();
1958161f84b5487ce4c1ebef9fe24ba4de00f6f756eaNick Pelly                }
1959fc87b4294aa0a2c85c2332a4c5229161a83961d8mike wakerly                return null;
19607c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly            }
19617c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly        }
19627c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly    }
19637c034a7fe7d36b1ab039af2c44717812ea02657eNick Pelly
1964525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1965525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        @Override
1966525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project        public void onReceive(Context context, Intent intent) {
1967525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project            String action = intent.getAction();
1968c8768e4b2ab114d227bd8af441d81525837f78cbMartijn Coenen            if (action.equals(Intent.ACTION_SCREEN_ON)
1969525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_SCREEN_OFF)
1970525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                    || action.equals(Intent.ACTION_USER_PRESENT)) {
1971525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                // Perform applyRouting() in AsyncTask to serialize blocking calls
19724309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                int screenState = ScreenStateHelper.SCREEN_STATE_OFF;
1973525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
19744309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    screenState = ScreenStateHelper.SCREEN_STATE_OFF;
1975525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
19764309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    screenState = mKeyguard.isKeyguardLocked()
19774309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                            ? ScreenStateHelper.SCREEN_STATE_ON_LOCKED
19784309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                            : ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1979525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
19804309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales                    screenState = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1981525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                }
198231b0f4653686119d74876cae5d637c5baf52b935Andres Morales
1983525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
198431949217328bf2357ff044f0d18677fe588c790cNick Pelly            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
198531949217328bf2357ff044f0d18677fe588c790cNick Pelly                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
198631949217328bf2357ff044f0d18677fe588c790cNick Pelly                // Query the airplane mode from Settings.System just to make sure that
198731949217328bf2357ff044f0d18677fe588c790cNick Pelly                // some random app is not sending this intent
198831949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn != isAirplaneModeOn()) {
198931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
199031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
199131949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (!mIsAirplaneSensitive) {
199231949217328bf2357ff044f0d18677fe588c790cNick Pelly                    return;
199331949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
19941668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
19951668f533e6a2f041703919bafa4c3ceee62dbc38Martijn Coenen                mPrefsEditor.apply();
199631949217328bf2357ff044f0d18677fe588c790cNick Pelly                if (isAirplaneModeOn) {
199731949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_DISABLE);
199831949217328bf2357ff044f0d18677fe588c790cNick Pelly                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
199931949217328bf2357ff044f0d18677fe588c790cNick Pelly                    new EnableDisableTask().execute(TASK_ENABLE);
200031949217328bf2357ff044f0d18677fe588c790cNick Pelly                }
20013859c5cccb202c20882fb3887cfa87babb1d85a3Martijn Coenen            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
2002d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
2003d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                synchronized (this) {
2004d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                    mUserId = userId;
2005d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                }
2006d2604c0544f7bc26e5b2407f0215cccfffedae2cAndres Morales                mP2pLinkManager.onUserSwitched(getUserId());
2007341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen                if (mIsHceCapable) {
2008af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen                    mCardEmulationManager.onUserSwitched(getUserId());
20094358172f18871d58d5bc2050e4d9d0bf9bc2d5e5Martijn Coenen                }
2010f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly            }
2011f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly        }
2012f067256d9556b1e01143f9ae2fd824fa5dc03138Nick Pelly    };
201331949217328bf2357ff044f0d18677fe588c790cNick Pelly
201431b0f4653686119d74876cae5d637c5baf52b935Andres Morales
2015c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    private final BroadcastReceiver mOwnerReceiver = new BroadcastReceiver() {
2016c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        @Override
2017c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        public void onReceive(Context context, Intent intent) {
2018c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            String action = intent.getAction();
2019c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            if (action.equals(Intent.ACTION_PACKAGE_REMOVED) ||
2020c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    action.equals(Intent.ACTION_PACKAGE_ADDED) ||
2021c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE) ||
2022c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
2023c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                updatePackageCache();
2024c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
2025c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
2026c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    // Clear the NFCEE access cache in case a UID gets recycled
2027c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                    mNfceeAccessControl.invalidateCache();
2028c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen                }
2029c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen            }
2030c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen        }
2031c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen    };
2032c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
2033b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz    private final BroadcastReceiver mPolicyReceiver = new BroadcastReceiver() {
2034b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        @Override
2035b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        public void onReceive(Context context, Intent intent){
2036b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            String action = intent.getAction();
2037b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
2038b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                    .equals(action)) {
2039b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                enforceBeamShareActivityPolicy(context,
2040b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz                        new UserHandle(getSendingUserId()), mIsNdefPushEnabled);
2041b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz            }
2042b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz        }
2043b708f80d56ba6d6ed110b9b7d1008563689821a4Benjamin Franz    };
2044c19c065b6d0e1a088780c4dca27a1404d5926765Martijn Coenen
20454309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
20464309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * Returns true if airplane mode is currently on
20474309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
204831949217328bf2357ff044f0d18677fe588c790cNick Pelly    boolean isAirplaneModeOn() {
20497d8987f233985a5ff29226890e11012275d325f5Martijn Coenen        return Settings.System.getInt(mContentResolver,
20507d8987f233985a5ff29226890e11012275d325f5Martijn Coenen                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
205131949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
205231949217328bf2357ff044f0d18677fe588c790cNick Pelly
20534309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales    /**
20544309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     * for debugging only - no i18n
20554309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales     */
205631949217328bf2357ff044f0d18677fe588c790cNick Pelly    static String stateToString(int state) {
205731949217328bf2357ff044f0d18677fe588c790cNick Pelly        switch (state) {
205831949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_OFF:
205931949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "off";
206031949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_ON:
206131949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning on";
206231949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_ON:
206331949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "on";
206431949217328bf2357ff044f0d18677fe588c790cNick Pelly            case NfcAdapter.STATE_TURNING_OFF:
206531949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "turning off";
206631949217328bf2357ff044f0d18677fe588c790cNick Pelly            default:
206731949217328bf2357ff044f0d18677fe588c790cNick Pelly                return "<error>";
206831949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
206931949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
207031949217328bf2357ff044f0d18677fe588c790cNick Pelly
207131949217328bf2357ff044f0d18677fe588c790cNick Pelly    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
207250effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
207350effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                != PackageManager.PERMISSION_GRANTED) {
207450effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            pw.println("Permission Denial: can't dump nfc from from pid="
207550effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
207650effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
207750effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root            return;
207850effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root        }
207950effe4645b6ea57a1dc90777995f41dd9624e55Kenny Root
208031949217328bf2357ff044f0d18677fe588c790cNick Pelly        synchronized (this) {
208131949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mState=" + stateToString(mState));
20820b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
20834309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales            pw.println("mScreenState=" + ScreenStateHelper.screenStateToString(mScreenState));
208431949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
208531949217328bf2357ff044f0d18677fe588c790cNick Pelly            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
20860799bcbe2469aa6a88c6cbdf0cdee5b50e1994f0Andres Morales            pw.println(mCurrentDiscoveryParameters);
208777d0b56bfa6a4e4e1449c476a1141a7486f34ad9Nick Pelly            mP2pLinkManager.dump(fd, pw, args);
2088341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen            if (mIsHceCapable) {
2089af3e301d7820bc0a2447db8af16ab5335e6bd520Martijn Coenen                mCardEmulationManager.dump(fd, pw, args);
2090341b2c02da8b4d2a681f3fbcc5657921ad421e32Martijn Coenen            }
2091391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly            mNfcDispatcher.dump(fd, pw, args);
209256f2a7bc39a14487f01cbf2d131ba3cde4126f2dMartijn Coenen            pw.println(mDeviceHost.dump());
209331949217328bf2357ff044f0d18677fe588c790cNick Pelly        }
209431949217328bf2357ff044f0d18677fe588c790cNick Pelly    }
209574180bda362a8bc9d2f701d2c17bec0f63c20bbfBrad Fitzpatrick}
2096