176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly/* 276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * Copyright (C) 2011 The Android Open Source Project 376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * 476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License"); 576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * you may not use this file except in compliance with the License. 676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * You may obtain a copy of the License at 776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * 876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * http://www.apache.org/licenses/LICENSE-2.0 976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * 1076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * Unless required by applicable law or agreed to in writing, software 1176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS, 1276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * See the License for the specific language governing permissions and 1476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * limitations under the License. 1576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly */ 1676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 1776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellypackage com.android.nfc; 1876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 19e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargentimport android.Manifest; 2038609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevotimport android.app.ActivityManager; 21b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.bluetooth.BluetoothAdapter; 2238609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevotimport android.os.UserManager; 23b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 24d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport com.android.nfc.RegisteredComponentCache.ComponentInfo; 25b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.handover.HandoverDataParser; 26b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.handover.PeripheralHandoverService; 27d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton 2876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.app.Activity; 29525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.app.ActivityManager; 30e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargentimport android.app.AlertDialog; 3176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.app.IActivityManager; 3276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.app.PendingIntent; 3376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.app.PendingIntent.CanceledException; 3476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.ComponentName; 35391cfe2479eca2080c14d1832599ad51cafae918Nick Pellyimport android.content.ContentResolver; 3676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.Context; 37e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargentimport android.content.DialogInterface; 3876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.Intent; 3976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.IntentFilter; 4076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.pm.PackageManager; 41525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.content.pm.PackageManager.NameNotFoundException; 4276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.pm.ResolveInfo; 437d8987f233985a5ff29226890e11012275d325f5Martijn Coenenimport android.content.res.Resources.NotFoundException; 4476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.net.Uri; 4576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.nfc.NdefMessage; 4676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.nfc.NdefRecord; 4776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.nfc.NfcAdapter; 4876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.nfc.Tag; 49ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pellyimport android.nfc.tech.Ndef; 50492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczykimport android.nfc.tech.NfcBarcode; 5176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.os.RemoteException; 52525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.os.UserHandle; 5376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.util.Log; 54e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargentimport android.view.LayoutInflater; 55e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargentimport android.view.View; 56e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargentimport android.view.WindowManager; 57e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargentimport android.widget.TextView; 5876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 59391cfe2479eca2080c14d1832599ad51cafae918Nick Pellyimport java.io.FileDescriptor; 60391cfe2479eca2080c14d1832599ad51cafae918Nick Pellyimport java.io.PrintWriter; 61893bc90a71883f8d2bfc82818abbf21c9745efdaElliott Hughesimport java.nio.charset.StandardCharsets; 6276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport java.util.ArrayList; 6376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport java.util.Arrays; 64391cfe2479eca2080c14d1832599ad51cafae918Nick Pellyimport java.util.LinkedList; 65ea9898eb8041802bca345b59de9e0e9302e8232bBen Dodsonimport java.util.List; 66e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargentimport java.util.Locale; 6776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 6876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly/** 6976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * Dispatch of NFC events to start activities 7076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly */ 714309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesclass NfcDispatcher { 7232cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private static final boolean DBG = false; 7332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private static final String TAG = "NfcDispatcher"; 7432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales 7532cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales static final int DISPATCH_SUCCESS = 1; 7632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales static final int DISPATCH_FAIL = 2; 7732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales static final int DISPATCH_UNLOCK = 3; 7832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales 7932cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final Context mContext; 8032cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final IActivityManager mIActivityManager; 8132cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final RegisteredComponentCache mTechListFilters; 8232cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final ContentResolver mContentResolver; 83b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales private final HandoverDataParser mHandoverDataParser; 8432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final String[] mProvisioningMimes; 850f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi private final String[] mLiveCaseMimes; 8632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final ScreenStateHelper mScreenStateHelper; 8716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales private final NfcUnlockManager mNfcUnlockManager; 88b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales private final boolean mDeviceSupportsBluetooth; 89222b8c18c4a9cf800f2dd615ef116f796ef7942cMartijn Coenen 9076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly // Locked on this 9132cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private PendingIntent mOverrideIntent; 9232cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private IntentFilter[] mOverrideFilters; 9332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private String[][] mOverrideTechLists; 9432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private boolean mProvisioningOnly; 9576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 964309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales NfcDispatcher(Context context, 97b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales HandoverDataParser handoverDataParser, 9844a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto boolean provisionOnly, 9944a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto boolean isLiveCaseEnabled) { 10076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mContext = context; 1013da6676ebb7a18a53621a5bc7eec21ca24becdf0Sudheer Shanka mIActivityManager = ActivityManager.getService(); 10276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mTechListFilters = new RegisteredComponentCache(mContext, 10376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly NfcAdapter.ACTION_TECH_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED); 104391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly mContentResolver = context.getContentResolver(); 105b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mHandoverDataParser = handoverDataParser; 1064309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales mScreenStateHelper = new ScreenStateHelper(context); 10716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales mNfcUnlockManager = NfcUnlockManager.getInstance(); 108b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mDeviceSupportsBluetooth = BluetoothAdapter.getDefaultAdapter() != null; 1094309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales 1107d8987f233985a5ff29226890e11012275d325f5Martijn Coenen synchronized (this) { 1117d8987f233985a5ff29226890e11012275d325f5Martijn Coenen mProvisioningOnly = provisionOnly; 1127d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } 1137d8987f233985a5ff29226890e11012275d325f5Martijn Coenen String[] provisionMimes = null; 1147d8987f233985a5ff29226890e11012275d325f5Martijn Coenen if (provisionOnly) { 1157d8987f233985a5ff29226890e11012275d325f5Martijn Coenen try { 1167d8987f233985a5ff29226890e11012275d325f5Martijn Coenen // Get accepted mime-types 1177d8987f233985a5ff29226890e11012275d325f5Martijn Coenen provisionMimes = context.getResources(). 1187d8987f233985a5ff29226890e11012275d325f5Martijn Coenen getStringArray(R.array.provisioning_mime_types); 1197d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } catch (NotFoundException e) { 1207d8987f233985a5ff29226890e11012275d325f5Martijn Coenen provisionMimes = null; 1217d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } 1227d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } 1237d8987f233985a5ff29226890e11012275d325f5Martijn Coenen mProvisioningMimes = provisionMimes; 1240f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi 1250f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi String[] liveCaseMimes = null; 12644a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto if (isLiveCaseEnabled) { 12744a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto try { 12844a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto // Get accepted mime-types 12944a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto liveCaseMimes = context.getResources(). 13044a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto getStringArray(R.array.live_case_mime_types); 13144a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto } catch (NotFoundException e) { 13244a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto liveCaseMimes = null; 13344a27fea4133fd8fa0afaad8db4480afe005140dHiroki Yamamoto } 1340f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi } 1350f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi mLiveCaseMimes = liveCaseMimes; 13676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 13776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 1380b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly public synchronized void setForegroundDispatch(PendingIntent intent, 13976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly IntentFilter[] filters, String[][] techLists) { 1400b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly if (DBG) Log.d(TAG, "Set Foreground Dispatch"); 14176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mOverrideIntent = intent; 14276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mOverrideFilters = filters; 14376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mOverrideTechLists = techLists; 14476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 14576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 1467d8987f233985a5ff29226890e11012275d325f5Martijn Coenen public synchronized void disableProvisioningMode() { 1477d8987f233985a5ff29226890e11012275d325f5Martijn Coenen mProvisioningOnly = false; 1487d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } 1497d8987f233985a5ff29226890e11012275d325f5Martijn Coenen 150391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly /** 151391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * Helper for re-used objects and methods during a single tag dispatch. 152391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly */ 153391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static class DispatchInfo { 154391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public final Intent intent; 155391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 156391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final Intent rootIntent; 157391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final Uri ndefUri; 158391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final String ndefMimeType; 159391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final PackageManager packageManager; 160391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final Context context; 161391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 162391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public DispatchInfo(Context context, Tag tag, NdefMessage message) { 163391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent = new Intent(); 164391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putExtra(NfcAdapter.EXTRA_TAG, tag); 165391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId()); 166391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (message != null) { 167391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[] {message}); 168391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ndefUri = message.getRecords()[0].toUri(); 169391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ndefMimeType = message.getRecords()[0].toMimeType(); 170391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } else { 171391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ndefUri = null; 172391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ndefMimeType = null; 173391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 174391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 175391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly rootIntent = new Intent(context, NfcRootActivity.class); 176391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intent); 177391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly rootIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 178391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 179391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly this.context = context; 180391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly packageManager = context.getPackageManager(); 18176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 18276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 183391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public Intent setNdefIntent() { 184391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setAction(NfcAdapter.ACTION_NDEF_DISCOVERED); 185391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (ndefUri != null) { 186391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setData(ndefUri); 187391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return intent; 188391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } else if (ndefMimeType != null) { 189391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setType(ndefMimeType); 190391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return intent; 191391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 192391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return null; 193391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 194391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 195391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public Intent setTechIntent() { 196391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setData(null); 197391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setType(null); 198391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setAction(NfcAdapter.ACTION_TECH_DISCOVERED); 199391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return intent; 200391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 201391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 202391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public Intent setTagIntent() { 203391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setData(null); 204391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setType(null); 205391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setAction(NfcAdapter.ACTION_TAG_DISCOVERED); 206391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return intent; 207391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 208391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 209e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent public boolean isWebIntent() { 210e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent return ndefUri != null && ndefUri.normalizeScheme().getScheme().startsWith("http"); 211e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent } 212e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent 213e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent public String getUri() { 214e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent return ndefUri.toString(); 215e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent } 216e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent 217391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly /** 218391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * Launch the activity via a (single) NFC root task, so that it 219391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * creates a new task stack instead of interfering with any existing 220391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * task stack for that activity. 221391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * NfcRootActivity acts as the task root, it immediately calls 222391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * start activity on the intent it is passed. 223391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly */ 224391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean tryStartActivity() { 225391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Ideally we'd have used startActivityForResult() to determine whether the 226391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // NfcRootActivity was able to launch the intent, but startActivityForResult() 227391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // is not available on Context. Instead, we query the PackageManager beforehand 228391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // to determine if there is an Activity to handle this intent, and base the 229391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // result of off that. 230525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(intent, 0, 231525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project ActivityManager.getCurrentUser()); 232391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (activities.size() > 0) { 233525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project context.startActivityAsUser(rootIntent, UserHandle.CURRENT); 234391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 235391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 236391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 237391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 238391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 239391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean tryStartActivity(Intent intentToStart) { 240525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser( 241525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project intentToStart, 0, ActivityManager.getCurrentUser()); 242391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (activities.size() > 0) { 243391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intentToStart); 244525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project context.startActivityAsUser(rootIntent, UserHandle.CURRENT); 245391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 246391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 247391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 248391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 249391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 250391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 25132cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales /** Returns: 25232cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * <ul> 25332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * <li /> DISPATCH_SUCCESS if dispatched to an activity, 25432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * <li /> DISPATCH_FAIL if no activities were found to dispatch to, 25532cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * <li /> DISPATCH_UNLOCK if the tag was used to unlock the device 25632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * </ul> 25732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales */ 25832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales public int dispatchTag(Tag tag) { 25976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly PendingIntent overrideIntent; 260391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly IntentFilter[] overrideFilters; 26176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly String[][] overrideTechLists; 26293aa66518ba76514149a749937529095ef8b5761Martijn Coenen String[] provisioningMimes; 2630f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi String[] liveCaseMimes; 2640f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi NdefMessage message = null; 2657d8987f233985a5ff29226890e11012275d325f5Martijn Coenen boolean provisioningOnly; 266391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 26776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly synchronized (this) { 26876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly overrideFilters = mOverrideFilters; 26976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly overrideIntent = mOverrideIntent; 27076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly overrideTechLists = mOverrideTechLists; 2717d8987f233985a5ff29226890e11012275d325f5Martijn Coenen provisioningOnly = mProvisioningOnly; 27293aa66518ba76514149a749937529095ef8b5761Martijn Coenen provisioningMimes = mProvisioningMimes; 2730f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi liveCaseMimes = mLiveCaseMimes; 27476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 27576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 2766ac9196b397a5f3554fe1c416bc005bcef9ac520Andres Morales boolean screenUnlocked = false; 2770f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi boolean liveCaseDetected = false; 2780f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi Ndef ndef = Ndef.get(tag); 27928a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales if (!provisioningOnly && 28028a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales mScreenStateHelper.checkScreenState() == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) { 281731fd8a52cec0dbe8d6ec6a4c7aa36ff52812112Andres Morales screenUnlocked = handleNfcUnlock(tag); 2820f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi 2830f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi if (ndef != null) { 2840f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi message = ndef.getCachedNdefMessage(); 2850f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi if (message != null) { 2860f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi String ndefMimeType = message.getRecords()[0].toMimeType(); 2870f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi if (liveCaseMimes != null && 2880f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi Arrays.asList(liveCaseMimes).contains(ndefMimeType)) { 2890f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi liveCaseDetected = true; 2900f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi } 2910f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi } 29228a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales } 2930f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi 2940f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi if (!screenUnlocked && !liveCaseDetected) 2950f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi return DISPATCH_FAIL; 29628a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales } 29728a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales 2984309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales if (ndef != null) { 2994309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales message = ndef.getCachedNdefMessage(); 300492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } else { 301492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk NfcBarcode nfcBarcode = NfcBarcode.get(tag); 302492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk if (nfcBarcode != null && nfcBarcode.getType() == NfcBarcode.TYPE_KOVIO) { 303492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk message = decodeNfcBarcodeUri(nfcBarcode); 304492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 3054309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales } 3064309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales 3075ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen if (DBG) Log.d(TAG, "dispatch tag: " + tag.toString() + " message: " + message); 3085ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen 3095ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen DispatchInfo dispatch = new DispatchInfo(mContext, tag, message); 3105ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen 3115ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen resumeAppSwitches(); 3125ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen 3135ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters, 3145ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen overrideTechLists)) { 3155ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS; 3165ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen } 3175ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen 31806486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen if (tryPeripheralHandover(message)) { 31906486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen if (DBG) Log.i(TAG, "matched BT HANDOVER"); 32006486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS; 32106486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen } 32206486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen 32306486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen if (NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mContext)) { 32406486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen if (DBG) Log.i(TAG, "matched NFC WPS TOKEN"); 32506486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS; 32606486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen } 32706486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen 32893aa66518ba76514149a749937529095ef8b5761Martijn Coenen if (provisioningOnly) { 32993aa66518ba76514149a749937529095ef8b5761Martijn Coenen if (message == null) { 33093aa66518ba76514149a749937529095ef8b5761Martijn Coenen // We only allow NDEF-message dispatch in provisioning mode 33193aa66518ba76514149a749937529095ef8b5761Martijn Coenen return DISPATCH_FAIL; 33293aa66518ba76514149a749937529095ef8b5761Martijn Coenen } 33393aa66518ba76514149a749937529095ef8b5761Martijn Coenen // Restrict to mime-types in whitelist. 33493aa66518ba76514149a749937529095ef8b5761Martijn Coenen String ndefMimeType = message.getRecords()[0].toMimeType(); 33593aa66518ba76514149a749937529095ef8b5761Martijn Coenen if (provisioningMimes == null || 33693aa66518ba76514149a749937529095ef8b5761Martijn Coenen !(Arrays.asList(provisioningMimes).contains(ndefMimeType))) { 33793aa66518ba76514149a749937529095ef8b5761Martijn Coenen Log.e(TAG, "Dropping NFC intent in provisioning mode."); 33893aa66518ba76514149a749937529095ef8b5761Martijn Coenen return DISPATCH_FAIL; 33993aa66518ba76514149a749937529095ef8b5761Martijn Coenen } 34093aa66518ba76514149a749937529095ef8b5761Martijn Coenen } 34193aa66518ba76514149a749937529095ef8b5761Martijn Coenen 34293aa66518ba76514149a749937529095ef8b5761Martijn Coenen if (tryNdef(dispatch, message)) { 34332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS; 34432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales } 34532cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales 34632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales if (screenUnlocked) { 34732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales // We only allow NDEF-based mimeType matching in case of an unlock 34832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return DISPATCH_UNLOCK; 34976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 35076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 35134cfff42771acf6d889dd0e5fedc2c2313d9784aAndres Morales // Only allow NDEF-based mimeType matching for unlock tags 35232cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales if (tryTech(dispatch, tag)) { 35332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return DISPATCH_SUCCESS; 354391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 35576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 35632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales dispatch.setTagIntent(); 35732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales if (dispatch.tryStartActivity()) { 35832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales if (DBG) Log.i(TAG, "matched TAG"); 35932cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return DISPATCH_SUCCESS; 360f955ec07aefda9d15b9a64afabedd8d927e0aff7Martijn Coenen } 361391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 362391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "no match"); 36332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return DISPATCH_FAIL; 364f955ec07aefda9d15b9a64afabedd8d927e0aff7Martijn Coenen } 365f955ec07aefda9d15b9a64afabedd8d927e0aff7Martijn Coenen 36616ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales private boolean handleNfcUnlock(Tag tag) { 36716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales return mNfcUnlockManager.tryUnlock(tag); 36816ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales } 36916ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales 370492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk /** 371492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * Checks for the presence of a URL stored in a tag with tech NfcBarcode. 372492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * If found, decodes URL and returns NdefMessage message containing an 373492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * NdefRecord containing the decoded URL. If not found, returns null. 374492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 375492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * URLs are decoded as follows: 376492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 377492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * Ignore first byte (which is 0x80 ORd with a manufacturer ID, corresponding 378492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * to ISO/IEC 7816-6). 379492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * The second byte describes the payload data format. There are four defined data 380492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * format values that identify URL data. Depending on the data format value, the 381492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * associated prefix is appended to the URL data: 382492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 383492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 0x01: URL with "http://www." prefix 384492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 0x02: URL with "https://www." prefix 385492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 0x03: URL with "http://" prefix 386492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 0x04: URL with "https://" prefix 387492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 388492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * Other data format values do not identify URL data and are not handled by this function. 389492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * URL payload is encoded in US-ASCII, following the limitations defined in RFC3987. 390492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * see http://www.ietf.org/rfc/rfc3987.txt 391492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 392492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * The final two bytes of a tag with tech NfcBarcode are always reserved for CRC data, 393492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * and are therefore not part of the payload. They are ignored in the decoding of a URL. 394492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 395492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * The default assumption is that the URL occupies the entire payload of the NfcBarcode 396492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * ID and all bytes of the NfcBarcode payload are decoded until the CRC (final two bytes) 397492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * is reached. However, the OPTIONAL early terminator byte 0xfe can be used to signal 398492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * an early end of the URL. Once this function reaches an early terminator byte 0xfe, 399492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * URL decoding stops and the NdefMessage is created and returned. Any payload data after 400492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * the first early terminator byte is ignored for the purposes of URL decoding. 401492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk */ 402492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk private NdefMessage decodeNfcBarcodeUri(NfcBarcode nfcBarcode) { 403492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk final byte URI_PREFIX_HTTP_WWW = (byte) 0x01; // "http://www." 404492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk final byte URI_PREFIX_HTTPS_WWW = (byte) 0x02; // "https://www." 405492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk final byte URI_PREFIX_HTTP = (byte) 0x03; // "http://" 406492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk final byte URI_PREFIX_HTTPS = (byte) 0x04; // "https://" 407492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk 408492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk NdefMessage message = null; 409492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk byte[] tagId = nfcBarcode.getTag().getId(); 410492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // All tags of NfcBarcode technology and Kovio type have lengths of a multiple of 16 bytes 411492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk if (tagId.length >= 4 412492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk && (tagId[1] == URI_PREFIX_HTTP_WWW || tagId[1] == URI_PREFIX_HTTPS_WWW 413492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk || tagId[1] == URI_PREFIX_HTTP || tagId[1] == URI_PREFIX_HTTPS)) { 414492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // Look for optional URI terminator (0xfe), used to indicate the end of a URI prior to 415492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // the end of the full NfcBarcode payload. No terminator means that the URI occupies the 416492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // entire length of the payload field. Exclude checking the CRC in the final two bytes 417492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // of the NfcBarcode tagId. 418492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk int end = 2; 419492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk for (; end < tagId.length - 2; end++) { 420492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk if (tagId[end] == (byte) 0xfe) { 421492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk break; 422492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 423492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 424492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk byte[] payload = new byte[end - 1]; // Skip also first byte (manufacturer ID) 425492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk System.arraycopy(tagId, 1, payload, 0, payload.length); 426492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk NdefRecord uriRecord = new NdefRecord( 427492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, tagId, payload); 428492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk message = new NdefMessage(uriRecord); 429492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 430492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk return message; 431492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 432492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk 433391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean tryOverrides(DispatchInfo dispatch, Tag tag, NdefMessage message, PendingIntent overrideIntent, 434391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly IntentFilter[] overrideFilters, String[][] overrideTechLists) { 435391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (overrideIntent == null) { 436391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 437391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 43876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly Intent intent; 43976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 440391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // NDEF 441391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (message != null) { 442391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent = dispatch.setNdefIntent(); 443bfaee054834ade31c52002f00553c63701f1c0b0Martijn Coenen if (intent != null && 444bfaee054834ade31c52002f00553c63701f1c0b0Martijn Coenen isFilterMatch(intent, overrideFilters, overrideTechLists != null)) { 445391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly try { 446391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly overrideIntent.send(mContext, Activity.RESULT_OK, intent); 447391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched NDEF override"); 448391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 449391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } catch (CanceledException e) { 450391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 45176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 45276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 45376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 45476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 455391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // TECH 456391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent = dispatch.setTechIntent(); 457391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (isTechMatch(tag, overrideTechLists)) { 458391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly try { 459391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly overrideIntent.send(mContext, Activity.RESULT_OK, intent); 460391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched TECH override"); 461391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 462391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } catch (CanceledException e) { 463391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 46476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 465391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 466391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 467391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // TAG 468391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent = dispatch.setTagIntent(); 469391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (isFilterMatch(intent, overrideFilters, overrideTechLists != null)) { 470391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly try { 471391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly overrideIntent.send(mContext, Activity.RESULT_OK, intent); 472391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched TAG override"); 473391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 474391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } catch (CanceledException e) { 475391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 47676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 477391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 478391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 479391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 48076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 481391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean isFilterMatch(Intent intent, IntentFilter[] filters, boolean hasTechFilter) { 482391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (filters != null) { 483391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (IntentFilter filter : filters) { 484391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (filter.match(mContentResolver, intent, false, TAG) >= 0) { 48576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return true; 48676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 48776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 488391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } else if (!hasTechFilter) { 489391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; // always match if both filters and techlists are null 49076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 491391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 492391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 49376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 494391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean isTechMatch(Tag tag, String[][] techLists) { 495391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (techLists == null) { 49676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return false; 49776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 498391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 499391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly String[] tagTechs = tag.getTechList(); 500391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Arrays.sort(tagTechs); 501391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (String[] filterTechs : techLists) { 502391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (filterMatch(tagTechs, filterTechs)) { 503391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 504391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 505391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 506391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 50776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 50876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 50993aa66518ba76514149a749937529095ef8b5761Martijn Coenen boolean tryNdef(DispatchInfo dispatch, NdefMessage message) { 510391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (message == null) { 511391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 512391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 513525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project Intent intent = dispatch.setNdefIntent(); 514525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project 515525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project // Bail out if the intent does not contain filterable NDEF data 516525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project if (intent == null) return false; 517391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 518391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Try to start AAR activity with matching filter 519391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly List<String> aarPackages = extractAarPackages(message); 520391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (String pkg : aarPackages) { 521391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly dispatch.intent.setPackage(pkg); 522391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (dispatch.tryStartActivity()) { 523391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched AAR to NDEF"); 524391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 525391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 526391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 527391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 528391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Try to perform regular launch of the first AAR 529391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (aarPackages.size() > 0) { 530391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly String firstPackage = aarPackages.get(0); 531525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project PackageManager pm; 532525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project try { 533525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser()); 534525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project pm = mContext.createPackageContextAsUser("android", 0, 535525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project currentUser).getPackageManager(); 536525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } catch (NameNotFoundException e) { 537525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project Log.e(TAG, "Could not create user package context"); 538525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project return false; 539525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } 540525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project Intent appLaunchIntent = pm.getLaunchIntentForPackage(firstPackage); 541391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (appLaunchIntent != null && dispatch.tryStartActivity(appLaunchIntent)) { 542391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched AAR to application launch"); 543391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 544391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 545f955ec07aefda9d15b9a64afabedd8d927e0aff7Martijn Coenen // Find the package in Market: 546391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Intent marketIntent = getAppSearchIntent(firstPackage); 547391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (marketIntent != null && dispatch.tryStartActivity(marketIntent)) { 548391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched AAR to market launch"); 549391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 550391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 551391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 552391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 553391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // regular launch 554391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly dispatch.intent.setPackage(null); 555e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent 556e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent if (dispatch.isWebIntent()) { 557e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent if (DBG) Log.i(TAG, "matched Web link - prompting user"); 558e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent showWebLinkConfirmation(dispatch); 559e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent return true; 560e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent } 561e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent 562391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (dispatch.tryStartActivity()) { 563391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched NDEF"); 564391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 565391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 566391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 567391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 568391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 569391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 570391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static List<String> extractAarPackages(NdefMessage message) { 571391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly List<String> aarPackages = new LinkedList<String>(); 572391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (NdefRecord record : message.getRecords()) { 573391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly String pkg = checkForAar(record); 574391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (pkg != null) { 575391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly aarPackages.add(pkg); 576391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 577222b8c18c4a9cf800f2dd615ef116f796ef7942cMartijn Coenen } 578391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return aarPackages; 579222b8c18c4a9cf800f2dd615ef116f796ef7942cMartijn Coenen } 580222b8c18c4a9cf800f2dd615ef116f796ef7942cMartijn Coenen 581391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean tryTech(DispatchInfo dispatch, Tag tag) { 582391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly dispatch.setTechIntent(); 583391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 584391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly String[] tagTechs = tag.getTechList(); 585391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Arrays.sort(tagTechs); 586391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 587391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Standard tech dispatch path 588391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>(); 589391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly List<ComponentInfo> registered = mTechListFilters.getComponents(); 590391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 591525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project PackageManager pm; 592525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project try { 593525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser()); 594525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project pm = mContext.createPackageContextAsUser("android", 0, 595525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project currentUser).getPackageManager(); 596525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } catch (NameNotFoundException e) { 597525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project Log.e(TAG, "Could not create user package context"); 598525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project return false; 599525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } 600391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Check each registered activity to see if it matches 601391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (ComponentInfo info : registered) { 602391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Don't allow wild card matching 603391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (filterMatch(tagTechs, info.techs) && 604525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project isComponentEnabled(pm, info.resolveInfo)) { 605391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Add the activity as a match if it's not already in the list 606391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (!matches.contains(info.resolveInfo)) { 607391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly matches.add(info.resolveInfo); 60876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 60976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 610391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 61176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 612391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (matches.size() == 1) { 613391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Single match, launch directly 614391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ResolveInfo info = matches.get(0); 615391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly dispatch.intent.setClassName(info.activityInfo.packageName, info.activityInfo.name); 616391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (dispatch.tryStartActivity()) { 617391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched single TECH"); 61876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return true; 61976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 6207d8987f233985a5ff29226890e11012275d325f5Martijn Coenen dispatch.intent.setComponent(null); 621391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } else if (matches.size() > 1) { 622391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Multiple matches, show a custom activity chooser dialog 623391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Intent intent = new Intent(mContext, TechListChooserActivity.class); 624391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putExtra(Intent.EXTRA_INTENT, dispatch.intent); 625391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putParcelableArrayListExtra(TechListChooserActivity.EXTRA_RESOLVE_INFOS, 626391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly matches); 627391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (dispatch.tryStartActivity(intent)) { 628391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched multiple TECH"); 629391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 630b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson } 63176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 632391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 63376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 63476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 635b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales public boolean tryPeripheralHandover(NdefMessage m) { 636b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (m == null || !mDeviceSupportsBluetooth) return false; 637b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 638b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (DBG) Log.d(TAG, "tryHandover(): " + m.toString()); 639b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 640b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales HandoverDataParser.BluetoothHandoverData handover = mHandoverDataParser.parseBluetooth(m); 641b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (handover == null || !handover.valid) return false; 64238609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot if (UserManager.get(mContext).hasUserRestriction( 64338609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot UserManager.DISALLOW_CONFIG_BLUETOOTH, 64438609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot // hasUserRestriction does not support UserHandle.CURRENT 64538609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot UserHandle.of(ActivityManager.getCurrentUser()))) { 64638609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot return false; 64738609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot } 648b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 649b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Intent intent = new Intent(mContext, PeripheralHandoverService.class); 650b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device); 651b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_NAME, handover.name); 652b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_TRANSPORT, handover.transport); 653ca75f7282125255caee81f4bcd8f765d709acc38Jakub Pawlowski if (handover.oobData != null) { 654ca75f7282125255caee81f4bcd8f765d709acc38Jakub Pawlowski intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_OOB_DATA, handover.oobData); 655ca75f7282125255caee81f4bcd8f765d709acc38Jakub Pawlowski } 6567490b54650e48bbe3e0da8e142f83c4cc63ddc49Hiroki Yamamoto if (handover.uuids != null) { 6577490b54650e48bbe3e0da8e142f83c4cc63ddc49Hiroki Yamamoto intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_UUIDS, handover.uuids); 6587490b54650e48bbe3e0da8e142f83c4cc63ddc49Hiroki Yamamoto } 6597490b54650e48bbe3e0da8e142f83c4cc63ddc49Hiroki Yamamoto if (handover.btClass != null) { 6607490b54650e48bbe3e0da8e142f83c4cc63ddc49Hiroki Yamamoto intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_CLASS, handover.btClass); 6617490b54650e48bbe3e0da8e142f83c4cc63ddc49Hiroki Yamamoto } 662b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mContext.startServiceAsUser(intent, UserHandle.CURRENT); 663b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 664b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales return true; 665b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 666b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 667b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 6688e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly /** 6698e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * Tells the ActivityManager to resume allowing app switches. 6708e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * 6718e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * If the current app called stopAppSwitches() then our startActivity() can 6728e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * be delayed for several seconds. This happens with the default home 6738e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * screen. As a system service we can override this behavior with 6748e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * resumeAppSwitches(). 6758e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly */ 6768e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly void resumeAppSwitches() { 6778e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly try { 6788e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly mIActivityManager.resumeAppSwitches(); 6798e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly } catch (RemoteException e) { } 6808e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly } 6818e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly 68276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly /** Returns true if the tech list filter matches the techs on the tag */ 683391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean filterMatch(String[] tagTechs, String[] filterTechs) { 68476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly if (filterTechs == null || filterTechs.length == 0) return false; 68576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 68676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly for (String tech : filterTechs) { 68776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly if (Arrays.binarySearch(tagTechs, tech) < 0) { 68876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return false; 68976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 69076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 69176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return true; 69276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 69376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 694391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static String checkForAar(NdefRecord record) { 695391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (record.getTnf() == NdefRecord.TNF_EXTERNAL_TYPE && 696391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Arrays.equals(record.getType(), NdefRecord.RTD_ANDROID_APP)) { 697893bc90a71883f8d2bfc82818abbf21c9745efdaElliott Hughes return new String(record.getPayload(), StandardCharsets.US_ASCII); 69876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 699391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return null; 70076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 70176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 702b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson /** 703b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson * Returns an intent that can be used to find an application not currently 704b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson * installed on the device. 705b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson */ 706391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static Intent getAppSearchIntent(String pkg) { 707b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson Intent market = new Intent(Intent.ACTION_VIEW); 708b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson market.setData(Uri.parse("market://details?id=" + pkg)); 709b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson return market; 710b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson } 711b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson 712391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static boolean isComponentEnabled(PackageManager pm, ResolveInfo info) { 71376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly boolean enabled = false; 71476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly ComponentName compname = new ComponentName( 71576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly info.activityInfo.packageName, info.activityInfo.name); 71676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly try { 71776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly // Note that getActivityInfo() will internally call 71876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly // isEnabledLP() to determine whether the component 71976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly // enabled. If it's not, null is returned. 72076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly if (pm.getActivityInfo(compname,0) != null) { 72176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly enabled = true; 72276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 72376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } catch (PackageManager.NameNotFoundException e) { 72476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly enabled = false; 72576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 72676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly if (!enabled) { 72776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly Log.d(TAG, "Component not enabled: " + compname); 72876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 72976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return enabled; 73076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 731391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 732e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent void showWebLinkConfirmation(DispatchInfo dispatch) { 733e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent if (!mContext.getResources().getBoolean(R.bool.enable_nfc_url_open_dialog)) { 734e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent dispatch.tryStartActivity(); 735e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent return; 736e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent } 737e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent AlertDialog.Builder builder = new AlertDialog.Builder( 738e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent mContext.getApplicationContext(), 739e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent android.R.style.Theme_DeviceDefault_Light_Dialog_Alert); 740e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent builder.setTitle(R.string.title_confirm_url_open); 741e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent LayoutInflater inflater = LayoutInflater.from(mContext); 742e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent View view = inflater.inflate(R.layout.url_open_confirmation, null); 743e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent if (view != null) { 744e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent TextView url = view.findViewById(R.id.url_open_confirmation_link); 745e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent if (url != null) { 746e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent url.setText(dispatch.getUri()); 747e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent } 748e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent builder.setView(view); 749e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent } 750e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent builder.setNegativeButton(R.string.cancel, (dialog, which) -> {}); 751e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent builder.setPositiveButton(R.string.action_confirm_url_open, (dialog, which) -> { 752e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent dispatch.tryStartActivity(); 753e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent }); 754e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent AlertDialog dialog = builder.create(); 755e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); 756e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent dialog.show(); 757e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent } 758e594363266714de153e5b07f050a05acb2ad6ff9Antony Sargent 759391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 760391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly synchronized (this) { 761391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly pw.println("mOverrideIntent=" + mOverrideIntent); 762391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly pw.println("mOverrideFilters=" + mOverrideFilters); 763391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly pw.println("mOverrideTechLists=" + mOverrideTechLists); 764391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 765391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 76676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly} 767