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