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 1938609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevotimport android.app.ActivityManager; 20b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport android.bluetooth.BluetoothAdapter; 2138609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevotimport android.os.UserManager; 22b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 23d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamiltonimport com.android.nfc.RegisteredComponentCache.ComponentInfo; 24b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.handover.HandoverDataParser; 25b82d80d891077ccd74729e4143925a66eb89eef2Andres Moralesimport com.android.nfc.handover.PeripheralHandoverService; 26d704c298a5a1e783c71db6f39b2eef0a909b0e88Jeff Hamilton 2776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.app.Activity; 28525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.app.ActivityManager; 2976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.app.IActivityManager; 3076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.app.PendingIntent; 3176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.app.PendingIntent.CanceledException; 3276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.ComponentName; 33391cfe2479eca2080c14d1832599ad51cafae918Nick Pellyimport android.content.ContentResolver; 3476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.Context; 3576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.Intent; 3676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.IntentFilter; 3776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.pm.PackageManager; 38525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.content.pm.PackageManager.NameNotFoundException; 3976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.content.pm.ResolveInfo; 407d8987f233985a5ff29226890e11012275d325f5Martijn Coenenimport android.content.res.Resources.NotFoundException; 4176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.net.Uri; 4276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.nfc.NdefMessage; 4376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.nfc.NdefRecord; 4476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.nfc.NfcAdapter; 4576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.nfc.Tag; 46ea78e5beebff19ece23870b4ff5e5fd69d61aaa1Nick Pellyimport android.nfc.tech.Ndef; 47492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczykimport android.nfc.tech.NfcBarcode; 4876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.os.RemoteException; 49525c260303268a83da4c3413b953d13c9084e834The Android Open Source Projectimport android.os.UserHandle; 5076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport android.util.Log; 5176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 52391cfe2479eca2080c14d1832599ad51cafae918Nick Pellyimport java.io.FileDescriptor; 53391cfe2479eca2080c14d1832599ad51cafae918Nick Pellyimport java.io.PrintWriter; 54893bc90a71883f8d2bfc82818abbf21c9745efdaElliott Hughesimport java.nio.charset.StandardCharsets; 5576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport java.util.ArrayList; 5676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pellyimport java.util.Arrays; 57391cfe2479eca2080c14d1832599ad51cafae918Nick Pellyimport java.util.LinkedList; 58ea9898eb8041802bca345b59de9e0e9302e8232bBen Dodsonimport java.util.List; 5976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 6076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly/** 6176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly * Dispatch of NFC events to start activities 6276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly */ 634309f9c7c0097bdd95cf791eef78700b106dec21Andres Moralesclass NfcDispatcher { 6432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private static final boolean DBG = false; 6532cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private static final String TAG = "NfcDispatcher"; 6632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales 6732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales static final int DISPATCH_SUCCESS = 1; 6832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales static final int DISPATCH_FAIL = 2; 6932cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales static final int DISPATCH_UNLOCK = 3; 7032cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales 7132cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final Context mContext; 7232cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final IActivityManager mIActivityManager; 7332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final RegisteredComponentCache mTechListFilters; 7432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final ContentResolver mContentResolver; 75b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales private final HandoverDataParser mHandoverDataParser; 7632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final String[] mProvisioningMimes; 770f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi private final String[] mLiveCaseMimes; 7832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private final ScreenStateHelper mScreenStateHelper; 7916ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales private final NfcUnlockManager mNfcUnlockManager; 80b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales private final boolean mDeviceSupportsBluetooth; 81222b8c18c4a9cf800f2dd615ef116f796ef7942cMartijn Coenen 8276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly // Locked on this 8332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private PendingIntent mOverrideIntent; 8432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private IntentFilter[] mOverrideFilters; 8532cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private String[][] mOverrideTechLists; 8632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales private boolean mProvisioningOnly; 8776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 884309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales NfcDispatcher(Context context, 89b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales HandoverDataParser handoverDataParser, 90766d24ccb639ed3bf23f7fe918290df6d372e611Andres Morales boolean provisionOnly) { 9176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mContext = context; 923da6676ebb7a18a53621a5bc7eec21ca24becdf0Sudheer Shanka mIActivityManager = ActivityManager.getService(); 9376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mTechListFilters = new RegisteredComponentCache(mContext, 9476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly NfcAdapter.ACTION_TECH_DISCOVERED, NfcAdapter.ACTION_TECH_DISCOVERED); 95391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly mContentResolver = context.getContentResolver(); 96b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mHandoverDataParser = handoverDataParser; 974309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales mScreenStateHelper = new ScreenStateHelper(context); 9816ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales mNfcUnlockManager = NfcUnlockManager.getInstance(); 99b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mDeviceSupportsBluetooth = BluetoothAdapter.getDefaultAdapter() != null; 1004309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales 1017d8987f233985a5ff29226890e11012275d325f5Martijn Coenen synchronized (this) { 1027d8987f233985a5ff29226890e11012275d325f5Martijn Coenen mProvisioningOnly = provisionOnly; 1037d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } 1047d8987f233985a5ff29226890e11012275d325f5Martijn Coenen String[] provisionMimes = null; 1057d8987f233985a5ff29226890e11012275d325f5Martijn Coenen if (provisionOnly) { 1067d8987f233985a5ff29226890e11012275d325f5Martijn Coenen try { 1077d8987f233985a5ff29226890e11012275d325f5Martijn Coenen // Get accepted mime-types 1087d8987f233985a5ff29226890e11012275d325f5Martijn Coenen provisionMimes = context.getResources(). 1097d8987f233985a5ff29226890e11012275d325f5Martijn Coenen getStringArray(R.array.provisioning_mime_types); 1107d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } catch (NotFoundException e) { 1117d8987f233985a5ff29226890e11012275d325f5Martijn Coenen provisionMimes = null; 1127d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } 1137d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } 1147d8987f233985a5ff29226890e11012275d325f5Martijn Coenen mProvisioningMimes = provisionMimes; 1150f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi 1160f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi String[] liveCaseMimes = null; 1170f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi try { 1180f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi // Get accepted mime-types 1190f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi liveCaseMimes = context.getResources(). 1200f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi getStringArray(R.array.live_case_mime_types); 1210f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi } catch (NotFoundException e) { 1220f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi liveCaseMimes = null; 1230f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi } 1240f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi mLiveCaseMimes = liveCaseMimes; 12576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 12676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 1270b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly public synchronized void setForegroundDispatch(PendingIntent intent, 12876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly IntentFilter[] filters, String[][] techLists) { 1290b3b8ab69835cb66c96691dae3ba9b75705980a5Nick Pelly if (DBG) Log.d(TAG, "Set Foreground Dispatch"); 13076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mOverrideIntent = intent; 13176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mOverrideFilters = filters; 13276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly mOverrideTechLists = techLists; 13376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 13476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 1357d8987f233985a5ff29226890e11012275d325f5Martijn Coenen public synchronized void disableProvisioningMode() { 1367d8987f233985a5ff29226890e11012275d325f5Martijn Coenen mProvisioningOnly = false; 1377d8987f233985a5ff29226890e11012275d325f5Martijn Coenen } 1387d8987f233985a5ff29226890e11012275d325f5Martijn Coenen 139391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly /** 140391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * Helper for re-used objects and methods during a single tag dispatch. 141391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly */ 142391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static class DispatchInfo { 143391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public final Intent intent; 144391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 145391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final Intent rootIntent; 146391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final Uri ndefUri; 147391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final String ndefMimeType; 148391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final PackageManager packageManager; 149391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly final Context context; 150391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 151391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public DispatchInfo(Context context, Tag tag, NdefMessage message) { 152391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent = new Intent(); 153391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putExtra(NfcAdapter.EXTRA_TAG, tag); 154391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId()); 155391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (message != null) { 156391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[] {message}); 157391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ndefUri = message.getRecords()[0].toUri(); 158391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ndefMimeType = message.getRecords()[0].toMimeType(); 159391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } else { 160391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ndefUri = null; 161391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ndefMimeType = null; 162391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 163391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 164391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly rootIntent = new Intent(context, NfcRootActivity.class); 165391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intent); 166391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly rootIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 167391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 168391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly this.context = context; 169391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly packageManager = context.getPackageManager(); 17076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 17176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 172391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public Intent setNdefIntent() { 173391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setAction(NfcAdapter.ACTION_NDEF_DISCOVERED); 174391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (ndefUri != null) { 175391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setData(ndefUri); 176391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return intent; 177391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } else if (ndefMimeType != null) { 178391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setType(ndefMimeType); 179391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return intent; 180391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 181391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return null; 182391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 183391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 184391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public Intent setTechIntent() { 185391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setData(null); 186391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setType(null); 187391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setAction(NfcAdapter.ACTION_TECH_DISCOVERED); 188391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return intent; 189391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 190391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 191391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly public Intent setTagIntent() { 192391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setData(null); 193391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setType(null); 194391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.setAction(NfcAdapter.ACTION_TAG_DISCOVERED); 195391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return intent; 196391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 197391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 198391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly /** 199391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * Launch the activity via a (single) NFC root task, so that it 200391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * creates a new task stack instead of interfering with any existing 201391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * task stack for that activity. 202391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * NfcRootActivity acts as the task root, it immediately calls 203391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly * start activity on the intent it is passed. 204391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly */ 205391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean tryStartActivity() { 206391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Ideally we'd have used startActivityForResult() to determine whether the 207391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // NfcRootActivity was able to launch the intent, but startActivityForResult() 208391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // is not available on Context. Instead, we query the PackageManager beforehand 209391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // to determine if there is an Activity to handle this intent, and base the 210391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // result of off that. 211525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(intent, 0, 212525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project ActivityManager.getCurrentUser()); 213391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (activities.size() > 0) { 214525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project context.startActivityAsUser(rootIntent, UserHandle.CURRENT); 215391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 216391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 217391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 218391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 219391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 220391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean tryStartActivity(Intent intentToStart) { 221525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser( 222525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project intentToStart, 0, ActivityManager.getCurrentUser()); 223391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (activities.size() > 0) { 224391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intentToStart); 225525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project context.startActivityAsUser(rootIntent, UserHandle.CURRENT); 226391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 227391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 228391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 229391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 230391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 231391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 23232cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales /** Returns: 23332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * <ul> 23432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * <li /> DISPATCH_SUCCESS if dispatched to an activity, 23532cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * <li /> DISPATCH_FAIL if no activities were found to dispatch to, 23632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * <li /> DISPATCH_UNLOCK if the tag was used to unlock the device 23732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales * </ul> 23832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales */ 23932cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales public int dispatchTag(Tag tag) { 24076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly PendingIntent overrideIntent; 241391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly IntentFilter[] overrideFilters; 24276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly String[][] overrideTechLists; 24393aa66518ba76514149a749937529095ef8b5761Martijn Coenen String[] provisioningMimes; 2440f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi String[] liveCaseMimes; 2450f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi NdefMessage message = null; 2467d8987f233985a5ff29226890e11012275d325f5Martijn Coenen boolean provisioningOnly; 247391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 24876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly synchronized (this) { 24976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly overrideFilters = mOverrideFilters; 25076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly overrideIntent = mOverrideIntent; 25176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly overrideTechLists = mOverrideTechLists; 2527d8987f233985a5ff29226890e11012275d325f5Martijn Coenen provisioningOnly = mProvisioningOnly; 25393aa66518ba76514149a749937529095ef8b5761Martijn Coenen provisioningMimes = mProvisioningMimes; 2540f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi liveCaseMimes = mLiveCaseMimes; 25576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 25676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 2576ac9196b397a5f3554fe1c416bc005bcef9ac520Andres Morales boolean screenUnlocked = false; 2580f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi boolean liveCaseDetected = false; 2590f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi Ndef ndef = Ndef.get(tag); 26028a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales if (!provisioningOnly && 26128a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales mScreenStateHelper.checkScreenState() == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) { 262731fd8a52cec0dbe8d6ec6a4c7aa36ff52812112Andres Morales screenUnlocked = handleNfcUnlock(tag); 2630f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi 2640f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi if (ndef != null) { 2650f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi message = ndef.getCachedNdefMessage(); 2660f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi if (message != null) { 2670f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi String ndefMimeType = message.getRecords()[0].toMimeType(); 2680f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi if (liveCaseMimes != null && 2690f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi Arrays.asList(liveCaseMimes).contains(ndefMimeType)) { 2700f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi liveCaseDetected = true; 2710f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi } 2720f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi } 27328a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales } 2740f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi 2750f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi if (!screenUnlocked && !liveCaseDetected) 2760f4ebd13084ff9b9c9b3fcdc4ec8ab6509f9995fRuchi Kandoi return DISPATCH_FAIL; 27728a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales } 27828a49f0de26c4cc6f0b8c30dc67bebcb1a3110b6Andres Morales 2794309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales if (ndef != null) { 2804309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales message = ndef.getCachedNdefMessage(); 281492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } else { 282492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk NfcBarcode nfcBarcode = NfcBarcode.get(tag); 283492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk if (nfcBarcode != null && nfcBarcode.getType() == NfcBarcode.TYPE_KOVIO) { 284492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk message = decodeNfcBarcodeUri(nfcBarcode); 285492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 2864309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales } 2874309f9c7c0097bdd95cf791eef78700b106dec21Andres Morales 2885ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen if (DBG) Log.d(TAG, "dispatch tag: " + tag.toString() + " message: " + message); 2895ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen 2905ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen DispatchInfo dispatch = new DispatchInfo(mContext, tag, message); 2915ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen 2925ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen resumeAppSwitches(); 2935ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen 2945ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters, 2955ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen overrideTechLists)) { 2965ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS; 2975ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen } 2985ef11b7525885a42e681c31ebe2adb8b9317d0d2Martijn Coenen 29906486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen if (tryPeripheralHandover(message)) { 30006486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen if (DBG) Log.i(TAG, "matched BT HANDOVER"); 30106486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS; 30206486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen } 30306486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen 30406486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen if (NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mContext)) { 30506486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen if (DBG) Log.i(TAG, "matched NFC WPS TOKEN"); 30606486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS; 30706486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen } 30806486f58530d456a9a8d99bf14936539b3540ddeMartijn Coenen 30993aa66518ba76514149a749937529095ef8b5761Martijn Coenen if (provisioningOnly) { 31093aa66518ba76514149a749937529095ef8b5761Martijn Coenen if (message == null) { 31193aa66518ba76514149a749937529095ef8b5761Martijn Coenen // We only allow NDEF-message dispatch in provisioning mode 31293aa66518ba76514149a749937529095ef8b5761Martijn Coenen return DISPATCH_FAIL; 31393aa66518ba76514149a749937529095ef8b5761Martijn Coenen } 31493aa66518ba76514149a749937529095ef8b5761Martijn Coenen // Restrict to mime-types in whitelist. 31593aa66518ba76514149a749937529095ef8b5761Martijn Coenen String ndefMimeType = message.getRecords()[0].toMimeType(); 31693aa66518ba76514149a749937529095ef8b5761Martijn Coenen if (provisioningMimes == null || 31793aa66518ba76514149a749937529095ef8b5761Martijn Coenen !(Arrays.asList(provisioningMimes).contains(ndefMimeType))) { 31893aa66518ba76514149a749937529095ef8b5761Martijn Coenen Log.e(TAG, "Dropping NFC intent in provisioning mode."); 31993aa66518ba76514149a749937529095ef8b5761Martijn Coenen return DISPATCH_FAIL; 32093aa66518ba76514149a749937529095ef8b5761Martijn Coenen } 32193aa66518ba76514149a749937529095ef8b5761Martijn Coenen } 32293aa66518ba76514149a749937529095ef8b5761Martijn Coenen 32393aa66518ba76514149a749937529095ef8b5761Martijn Coenen if (tryNdef(dispatch, message)) { 32432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS; 32532cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales } 32632cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales 32732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales if (screenUnlocked) { 32832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales // We only allow NDEF-based mimeType matching in case of an unlock 32932cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return DISPATCH_UNLOCK; 33076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 33176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 33234cfff42771acf6d889dd0e5fedc2c2313d9784aAndres Morales // Only allow NDEF-based mimeType matching for unlock tags 33332cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales if (tryTech(dispatch, tag)) { 33432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return DISPATCH_SUCCESS; 335391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 33676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 33732cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales dispatch.setTagIntent(); 33832cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales if (dispatch.tryStartActivity()) { 33932cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales if (DBG) Log.i(TAG, "matched TAG"); 34032cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return DISPATCH_SUCCESS; 341f955ec07aefda9d15b9a64afabedd8d927e0aff7Martijn Coenen } 342391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 343391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "no match"); 34432cdfbf250f2611bb7624c13cfd7d111a847676eAndres Morales return DISPATCH_FAIL; 345f955ec07aefda9d15b9a64afabedd8d927e0aff7Martijn Coenen } 346f955ec07aefda9d15b9a64afabedd8d927e0aff7Martijn Coenen 34716ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales private boolean handleNfcUnlock(Tag tag) { 34816ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales return mNfcUnlockManager.tryUnlock(tag); 34916ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales } 35016ee2fe0e0f6d2f811bd06c37cbd53c8b395e6d6Andres Morales 351492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk /** 352492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * Checks for the presence of a URL stored in a tag with tech NfcBarcode. 353492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * If found, decodes URL and returns NdefMessage message containing an 354492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * NdefRecord containing the decoded URL. If not found, returns null. 355492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 356492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * URLs are decoded as follows: 357492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 358492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * Ignore first byte (which is 0x80 ORd with a manufacturer ID, corresponding 359492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * to ISO/IEC 7816-6). 360492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * The second byte describes the payload data format. There are four defined data 361492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * format values that identify URL data. Depending on the data format value, the 362492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * associated prefix is appended to the URL data: 363492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 364492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 0x01: URL with "http://www." prefix 365492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 0x02: URL with "https://www." prefix 366492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 0x03: URL with "http://" prefix 367492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 0x04: URL with "https://" prefix 368492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 369492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * Other data format values do not identify URL data and are not handled by this function. 370492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * URL payload is encoded in US-ASCII, following the limitations defined in RFC3987. 371492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * see http://www.ietf.org/rfc/rfc3987.txt 372492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 373492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * The final two bytes of a tag with tech NfcBarcode are always reserved for CRC data, 374492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * and are therefore not part of the payload. They are ignored in the decoding of a URL. 375492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * 376492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * The default assumption is that the URL occupies the entire payload of the NfcBarcode 377492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * ID and all bytes of the NfcBarcode payload are decoded until the CRC (final two bytes) 378492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * is reached. However, the OPTIONAL early terminator byte 0xfe can be used to signal 379492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * an early end of the URL. Once this function reaches an early terminator byte 0xfe, 380492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * URL decoding stops and the NdefMessage is created and returned. Any payload data after 381492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk * the first early terminator byte is ignored for the purposes of URL decoding. 382492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk */ 383492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk private NdefMessage decodeNfcBarcodeUri(NfcBarcode nfcBarcode) { 384492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk final byte URI_PREFIX_HTTP_WWW = (byte) 0x01; // "http://www." 385492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk final byte URI_PREFIX_HTTPS_WWW = (byte) 0x02; // "https://www." 386492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk final byte URI_PREFIX_HTTP = (byte) 0x03; // "http://" 387492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk final byte URI_PREFIX_HTTPS = (byte) 0x04; // "https://" 388492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk 389492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk NdefMessage message = null; 390492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk byte[] tagId = nfcBarcode.getTag().getId(); 391492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // All tags of NfcBarcode technology and Kovio type have lengths of a multiple of 16 bytes 392492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk if (tagId.length >= 4 393492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk && (tagId[1] == URI_PREFIX_HTTP_WWW || tagId[1] == URI_PREFIX_HTTPS_WWW 394492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk || tagId[1] == URI_PREFIX_HTTP || tagId[1] == URI_PREFIX_HTTPS)) { 395492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // Look for optional URI terminator (0xfe), used to indicate the end of a URI prior to 396492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // the end of the full NfcBarcode payload. No terminator means that the URI occupies the 397492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // entire length of the payload field. Exclude checking the CRC in the final two bytes 398492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk // of the NfcBarcode tagId. 399492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk int end = 2; 400492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk for (; end < tagId.length - 2; end++) { 401492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk if (tagId[end] == (byte) 0xfe) { 402492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk break; 403492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 404492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 405492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk byte[] payload = new byte[end - 1]; // Skip also first byte (manufacturer ID) 406492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk System.arraycopy(tagId, 1, payload, 0, payload.length); 407492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk NdefRecord uriRecord = new NdefRecord( 408492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, tagId, payload); 409492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk message = new NdefMessage(uriRecord); 410492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 411492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk return message; 412492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk } 413492469777a9bf75c5f9232256746acdfca3d4cdeBartek Teodorczyk 414391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean tryOverrides(DispatchInfo dispatch, Tag tag, NdefMessage message, PendingIntent overrideIntent, 415391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly IntentFilter[] overrideFilters, String[][] overrideTechLists) { 416391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (overrideIntent == null) { 417391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 418391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 41976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly Intent intent; 42076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 421391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // NDEF 422391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (message != null) { 423391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent = dispatch.setNdefIntent(); 424bfaee054834ade31c52002f00553c63701f1c0b0Martijn Coenen if (intent != null && 425bfaee054834ade31c52002f00553c63701f1c0b0Martijn Coenen isFilterMatch(intent, overrideFilters, overrideTechLists != null)) { 426391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly try { 427391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly overrideIntent.send(mContext, Activity.RESULT_OK, intent); 428391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched NDEF override"); 429391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 430391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } catch (CanceledException e) { 431391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 43276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 43376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 43476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 43576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 436391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // TECH 437391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent = dispatch.setTechIntent(); 438391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (isTechMatch(tag, overrideTechLists)) { 439391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly try { 440391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly overrideIntent.send(mContext, Activity.RESULT_OK, intent); 441391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched TECH override"); 442391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 443391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } catch (CanceledException e) { 444391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 44576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 446391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 447391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 448391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // TAG 449391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent = dispatch.setTagIntent(); 450391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (isFilterMatch(intent, overrideFilters, overrideTechLists != null)) { 451391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly try { 452391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly overrideIntent.send(mContext, Activity.RESULT_OK, intent); 453391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched TAG override"); 454391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 455391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } catch (CanceledException e) { 456391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 45776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 458391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 459391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 460391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 46176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 462391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean isFilterMatch(Intent intent, IntentFilter[] filters, boolean hasTechFilter) { 463391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (filters != null) { 464391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (IntentFilter filter : filters) { 465391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (filter.match(mContentResolver, intent, false, TAG) >= 0) { 46676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return true; 46776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 46876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 469391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } else if (!hasTechFilter) { 470391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; // always match if both filters and techlists are null 47176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 472391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 473391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 47476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 475391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean isTechMatch(Tag tag, String[][] techLists) { 476391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (techLists == null) { 47776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return false; 47876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 479391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 480391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly String[] tagTechs = tag.getTechList(); 481391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Arrays.sort(tagTechs); 482391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (String[] filterTechs : techLists) { 483391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (filterMatch(tagTechs, filterTechs)) { 484391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 485391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 486391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 487391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 48876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 48976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 49093aa66518ba76514149a749937529095ef8b5761Martijn Coenen boolean tryNdef(DispatchInfo dispatch, NdefMessage message) { 491391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (message == null) { 492391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 493391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 494525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project Intent intent = dispatch.setNdefIntent(); 495525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project 496525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project // Bail out if the intent does not contain filterable NDEF data 497525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project if (intent == null) return false; 498391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 499391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Try to start AAR activity with matching filter 500391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly List<String> aarPackages = extractAarPackages(message); 501391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (String pkg : aarPackages) { 502391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly dispatch.intent.setPackage(pkg); 503391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (dispatch.tryStartActivity()) { 504391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched AAR to NDEF"); 505391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 506391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 507391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 508391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 509391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Try to perform regular launch of the first AAR 510391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (aarPackages.size() > 0) { 511391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly String firstPackage = aarPackages.get(0); 512525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project PackageManager pm; 513525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project try { 514525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser()); 515525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project pm = mContext.createPackageContextAsUser("android", 0, 516525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project currentUser).getPackageManager(); 517525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } catch (NameNotFoundException e) { 518525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project Log.e(TAG, "Could not create user package context"); 519525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project return false; 520525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } 521525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project Intent appLaunchIntent = pm.getLaunchIntentForPackage(firstPackage); 522391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (appLaunchIntent != null && dispatch.tryStartActivity(appLaunchIntent)) { 523391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched AAR to application launch"); 524391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 525391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 526f955ec07aefda9d15b9a64afabedd8d927e0aff7Martijn Coenen // Find the package in Market: 527391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Intent marketIntent = getAppSearchIntent(firstPackage); 528391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (marketIntent != null && dispatch.tryStartActivity(marketIntent)) { 529391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched AAR to market launch"); 530391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 531391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 532391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 533391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 534391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // regular launch 535391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly dispatch.intent.setPackage(null); 536391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (dispatch.tryStartActivity()) { 537391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched NDEF"); 538391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 539391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 540391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 541391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 542391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 543391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 544391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static List<String> extractAarPackages(NdefMessage message) { 545391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly List<String> aarPackages = new LinkedList<String>(); 546391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (NdefRecord record : message.getRecords()) { 547391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly String pkg = checkForAar(record); 548391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (pkg != null) { 549391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly aarPackages.add(pkg); 550391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 551222b8c18c4a9cf800f2dd615ef116f796ef7942cMartijn Coenen } 552391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return aarPackages; 553222b8c18c4a9cf800f2dd615ef116f796ef7942cMartijn Coenen } 554222b8c18c4a9cf800f2dd615ef116f796ef7942cMartijn Coenen 555391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean tryTech(DispatchInfo dispatch, Tag tag) { 556391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly dispatch.setTechIntent(); 557391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 558391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly String[] tagTechs = tag.getTechList(); 559391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Arrays.sort(tagTechs); 560391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 561391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Standard tech dispatch path 562391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>(); 563391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly List<ComponentInfo> registered = mTechListFilters.getComponents(); 564391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 565525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project PackageManager pm; 566525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project try { 567525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser()); 568525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project pm = mContext.createPackageContextAsUser("android", 0, 569525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project currentUser).getPackageManager(); 570525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } catch (NameNotFoundException e) { 571525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project Log.e(TAG, "Could not create user package context"); 572525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project return false; 573525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project } 574391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Check each registered activity to see if it matches 575391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly for (ComponentInfo info : registered) { 576391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Don't allow wild card matching 577391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (filterMatch(tagTechs, info.techs) && 578525c260303268a83da4c3413b953d13c9084e834The Android Open Source Project isComponentEnabled(pm, info.resolveInfo)) { 579391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Add the activity as a match if it's not already in the list 580391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (!matches.contains(info.resolveInfo)) { 581391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly matches.add(info.resolveInfo); 58276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 58376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 584391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 58576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 586391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (matches.size() == 1) { 587391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Single match, launch directly 588391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly ResolveInfo info = matches.get(0); 589391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly dispatch.intent.setClassName(info.activityInfo.packageName, info.activityInfo.name); 590391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (dispatch.tryStartActivity()) { 591391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched single TECH"); 59276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return true; 59376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 5947d8987f233985a5ff29226890e11012275d325f5Martijn Coenen dispatch.intent.setComponent(null); 595391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } else if (matches.size() > 1) { 596391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly // Multiple matches, show a custom activity chooser dialog 597391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Intent intent = new Intent(mContext, TechListChooserActivity.class); 598391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putExtra(Intent.EXTRA_INTENT, dispatch.intent); 599391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly intent.putParcelableArrayListExtra(TechListChooserActivity.EXTRA_RESOLVE_INFOS, 600391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly matches); 601391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (dispatch.tryStartActivity(intent)) { 602391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (DBG) Log.i(TAG, "matched multiple TECH"); 603391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return true; 604b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson } 60576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 606391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return false; 60776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 60876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 609b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales public boolean tryPeripheralHandover(NdefMessage m) { 610b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (m == null || !mDeviceSupportsBluetooth) return false; 611b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 612b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (DBG) Log.d(TAG, "tryHandover(): " + m.toString()); 613b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 614b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales HandoverDataParser.BluetoothHandoverData handover = mHandoverDataParser.parseBluetooth(m); 615b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales if (handover == null || !handover.valid) return false; 61638609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot if (UserManager.get(mContext).hasUserRestriction( 61738609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot UserManager.DISALLOW_CONFIG_BLUETOOTH, 61838609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot // hasUserRestriction does not support UserHandle.CURRENT 61938609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot UserHandle.of(ActivityManager.getCurrentUser()))) { 62038609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot return false; 62138609ffd78908af4d6bd5156e6b297b357c0dda6Nicolas Prevot } 622b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 623b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales Intent intent = new Intent(mContext, PeripheralHandoverService.class); 624b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device); 625b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_NAME, handover.name); 626b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_TRANSPORT, handover.transport); 627ca75f7282125255caee81f4bcd8f765d709acc38Jakub Pawlowski if (handover.oobData != null) { 628ca75f7282125255caee81f4bcd8f765d709acc38Jakub Pawlowski intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_OOB_DATA, handover.oobData); 629ca75f7282125255caee81f4bcd8f765d709acc38Jakub Pawlowski } 6307bbbebc8a12cb19168a819489a87dda1318766d1Hiroki Yamamoto if (handover.uuids != null) { 6317bbbebc8a12cb19168a819489a87dda1318766d1Hiroki Yamamoto intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_UUIDS, handover.uuids); 6327bbbebc8a12cb19168a819489a87dda1318766d1Hiroki Yamamoto } 6337bbbebc8a12cb19168a819489a87dda1318766d1Hiroki Yamamoto if (handover.btClass != null) { 6347bbbebc8a12cb19168a819489a87dda1318766d1Hiroki Yamamoto intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_CLASS, handover.btClass); 6357bbbebc8a12cb19168a819489a87dda1318766d1Hiroki Yamamoto } 636b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales mContext.startServiceAsUser(intent, UserHandle.CURRENT); 637b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 638b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales return true; 639b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales } 640b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 641b82d80d891077ccd74729e4143925a66eb89eef2Andres Morales 6428e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly /** 6438e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * Tells the ActivityManager to resume allowing app switches. 6448e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * 6458e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * If the current app called stopAppSwitches() then our startActivity() can 6468e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * be delayed for several seconds. This happens with the default home 6478e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * screen. As a system service we can override this behavior with 6488e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly * resumeAppSwitches(). 6498e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly */ 6508e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly void resumeAppSwitches() { 6518e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly try { 6528e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly mIActivityManager.resumeAppSwitches(); 6538e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly } catch (RemoteException e) { } 6548e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly } 6558e85fe445d229fba5d101b4f95fe0dfa34a8601emike wakerly 65676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly /** Returns true if the tech list filter matches the techs on the tag */ 657391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly boolean filterMatch(String[] tagTechs, String[] filterTechs) { 65876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly if (filterTechs == null || filterTechs.length == 0) return false; 65976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 66076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly for (String tech : filterTechs) { 66176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly if (Arrays.binarySearch(tagTechs, tech) < 0) { 66276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return false; 66376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 66476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 66576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return true; 66676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 66776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 668391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static String checkForAar(NdefRecord record) { 669391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly if (record.getTnf() == NdefRecord.TNF_EXTERNAL_TYPE && 670391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly Arrays.equals(record.getType(), NdefRecord.RTD_ANDROID_APP)) { 671893bc90a71883f8d2bfc82818abbf21c9745efdaElliott Hughes return new String(record.getPayload(), StandardCharsets.US_ASCII); 67276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 673391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly return null; 67476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 67576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly 676b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson /** 677b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson * Returns an intent that can be used to find an application not currently 678b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson * installed on the device. 679b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson */ 680391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static Intent getAppSearchIntent(String pkg) { 681b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson Intent market = new Intent(Intent.ACTION_VIEW); 682b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson market.setData(Uri.parse("market://details?id=" + pkg)); 683b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson return market; 684b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson } 685b442e5fc49f235c228d3989c73e333d58caa2adeBen Dodson 686391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly static boolean isComponentEnabled(PackageManager pm, ResolveInfo info) { 68776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly boolean enabled = false; 68876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly ComponentName compname = new ComponentName( 68976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly info.activityInfo.packageName, info.activityInfo.name); 69076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly try { 69176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly // Note that getActivityInfo() will internally call 69276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly // isEnabledLP() to determine whether the component 69376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly // enabled. If it's not, null is returned. 69476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly if (pm.getActivityInfo(compname,0) != null) { 69576a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly enabled = true; 69676a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 69776a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } catch (PackageManager.NameNotFoundException e) { 69876a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly enabled = false; 69976a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 70076a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly if (!enabled) { 70176a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly Log.d(TAG, "Component not enabled: " + compname); 70276a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 70376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly return enabled; 70476a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly } 705391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly 706391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 707391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly synchronized (this) { 708391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly pw.println("mOverrideIntent=" + mOverrideIntent); 709391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly pw.println("mOverrideFilters=" + mOverrideFilters); 710391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly pw.println("mOverrideTechLists=" + mOverrideTechLists); 711391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 712391cfe2479eca2080c14d1832599ad51cafae918Nick Pelly } 71376a412f47ff57ce05d84fd51adbf8e72fd37a448Nick Pelly} 714