152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen/*
252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Copyright (C) 2013 The Android Open Source Project
352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen *
452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License");
552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * you may not use this file except in compliance with the License.
652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * You may obtain a copy of the License at
752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen *
852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen *      http://www.apache.org/licenses/LICENSE-2.0
952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen *
1052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * Unless required by applicable law or agreed to in writing, software
1152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS,
1252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * See the License for the specific language governing permissions and
1452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen * limitations under the License.
1552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen */
1652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
1752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenpackage android.nfc.cardemulation;
1852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
1952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.annotation.SdkConstant;
2052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.annotation.SdkConstant.SdkConstantType;
212f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenenimport android.app.Activity;
2252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.app.ActivityThread;
2352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.ComponentName;
2452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.Context;
2552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.pm.IPackageManager;
2652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.pm.PackageManager;
2752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.nfc.INfcCardEmulation;
2852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.nfc.NfcAdapter;
2952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.os.RemoteException;
3052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.os.UserHandle;
3152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.provider.Settings;
322f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenenimport android.provider.Settings.SettingNotFoundException;
3352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.util.Log;
3452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
3552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport java.util.HashMap;
3652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport java.util.List;
3752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
3835bf6288527b177a04100585321a1266f020004aMartijn Coenen/**
3935bf6288527b177a04100585321a1266f020004aMartijn Coenen * This class can be used to query the state of
4035bf6288527b177a04100585321a1266f020004aMartijn Coenen * NFC card emulation services.
4135bf6288527b177a04100585321a1266f020004aMartijn Coenen *
4235bf6288527b177a04100585321a1266f020004aMartijn Coenen * For a general introduction into NFC card emulation,
43f64c80a6cd46ce40018f66ae6f156c5f56bb68d3Robert Schaub * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">
4435bf6288527b177a04100585321a1266f020004aMartijn Coenen * NFC card emulation developer guide</a>.</p>
4535bf6288527b177a04100585321a1266f020004aMartijn Coenen *
4635bf6288527b177a04100585321a1266f020004aMartijn Coenen * <p class="note">Use of this class requires the
4735bf6288527b177a04100585321a1266f020004aMartijn Coenen * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
4835bf6288527b177a04100585321a1266f020004aMartijn Coenen * on the device.
4935bf6288527b177a04100585321a1266f020004aMartijn Coenen */
5052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenpublic final class CardEmulation {
5152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    static final String TAG = "CardEmulation";
5252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
5352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
5452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Activity action: ask the user to change the default
5552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * card emulation service for a certain category. This will
5652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * show a dialog that asks the user whether he wants to
5752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * replace the current default service with the service
5852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * identified with the ComponentName specified in
5952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * {@link #EXTRA_SERVICE_COMPONENT}, for the category
6052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * specified in {@link #EXTRA_CATEGORY}
6152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
6252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
6352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String ACTION_CHANGE_DEFAULT =
6452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
6552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
6652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
6735bf6288527b177a04100585321a1266f020004aMartijn Coenen     * The category extra for {@link #ACTION_CHANGE_DEFAULT}.
6852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
6952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @see #ACTION_CHANGE_DEFAULT
7052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
7152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String EXTRA_CATEGORY = "category";
7252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
7352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
7435bf6288527b177a04100585321a1266f020004aMartijn Coenen     * The service {@link ComponentName} object passed in as an
7535bf6288527b177a04100585321a1266f020004aMartijn Coenen     * extra for {@link #ACTION_CHANGE_DEFAULT}.
7652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
7752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @see #ACTION_CHANGE_DEFAULT
7852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
7952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String EXTRA_SERVICE_COMPONENT = "component";
8052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
8152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
8235bf6288527b177a04100585321a1266f020004aMartijn Coenen     * Category used for NFC payment services.
8352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
8452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String CATEGORY_PAYMENT = "payment";
8552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
8652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
8735bf6288527b177a04100585321a1266f020004aMartijn Coenen     * Category that can be used for all other card emulation
8835bf6288527b177a04100585321a1266f020004aMartijn Coenen     * services.
8952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
9052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String CATEGORY_OTHER = "other";
9152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
9252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
9352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Return value for {@link #getSelectionModeForCategory(String)}.
9452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
9552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>In this mode, the user has set a default service for this
9635bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    category.
9735bf6288527b177a04100585321a1266f020004aMartijn Coenen     *
9835bf6288527b177a04100585321a1266f020004aMartijn Coenen     * <p>When using ISO-DEP card emulation with {@link HostApduService}
9935bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    or {@link OffHostApduService}, if a remote NFC device selects
10035bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    any of the Application IDs (AIDs)
10152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    that the default service has registered in this category,
10252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    that service will automatically be bound to to handle
10352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    the transaction.
10452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
10552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
10652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
10752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
10852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Return value for {@link #getSelectionModeForCategory(String)}.
10952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
11035bf6288527b177a04100585321a1266f020004aMartijn Coenen     * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService}
11135bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    or {@link OffHostApduService}, whenever an Application ID (AID) of this category
11235bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    is selected, the user is asked which service he wants to use to handle
11352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    the transaction, even if there is only one matching service.
11452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
11552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final int SELECTION_MODE_ALWAYS_ASK = 1;
11652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
11752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
11852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Return value for {@link #getSelectionModeForCategory(String)}.
11952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
12035bf6288527b177a04100585321a1266f020004aMartijn Coenen     * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService}
12135bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    or {@link OffHostApduService}, the user will only be asked to select a service
12235bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    if the Application ID (AID) selected by the reader has been registered by multiple
12335bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    services. If there is only one service that has registered for the AID,
12435bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    that service will be invoked directly.
12552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
12652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
12752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
12852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    static boolean sIsInitialized = false;
12935bf6288527b177a04100585321a1266f020004aMartijn Coenen    static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
13052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    static INfcCardEmulation sService;
13152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
13252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    final Context mContext;
13352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
13452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    private CardEmulation(Context context, INfcCardEmulation service) {
13552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        mContext = context.getApplicationContext();
13652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        sService = service;
13752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
13852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
13935bf6288527b177a04100585321a1266f020004aMartijn Coenen    /**
14035bf6288527b177a04100585321a1266f020004aMartijn Coenen     * Helper to get an instance of this class.
14135bf6288527b177a04100585321a1266f020004aMartijn Coenen     *
14235bf6288527b177a04100585321a1266f020004aMartijn Coenen     * @param adapter A reference to an NfcAdapter object.
14335bf6288527b177a04100585321a1266f020004aMartijn Coenen     * @return
14435bf6288527b177a04100585321a1266f020004aMartijn Coenen     */
14552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static synchronized CardEmulation getInstance(NfcAdapter adapter) {
14652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (adapter == null) throw new NullPointerException("NfcAdapter is null");
14752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        Context context = adapter.getContext();
14852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (context == null) {
14952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            Log.e(TAG, "NfcAdapter context is null.");
15052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            throw new UnsupportedOperationException();
15152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
15252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (!sIsInitialized) {
15352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            IPackageManager pm = ActivityThread.getPackageManager();
15452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (pm == null) {
15552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Cannot get PackageManager");
15652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                throw new UnsupportedOperationException();
15752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
15852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
159115d2c189a46f535778d9dd0923f703ff2f888feJeff Sharkey                if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) {
16052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                    Log.e(TAG, "This device does not support card emulation");
16152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                    throw new UnsupportedOperationException();
16252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                }
16352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException e) {
16452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "PackageManager query failed.");
16552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                throw new UnsupportedOperationException();
16652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
16752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            sIsInitialized = true;
16852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
16952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        CardEmulation manager = sCardEmus.get(context);
17052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (manager == null) {
17152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Get card emu service
17252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            INfcCardEmulation service = adapter.getCardEmulationService();
173aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            if (service == null) {
174aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                Log.e(TAG, "This device does not implement the INfcCardEmulation interface.");
175aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                throw new UnsupportedOperationException();
176aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
17752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            manager = new CardEmulation(context, service);
17852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            sCardEmus.put(context, manager);
17952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
18052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        return manager;
18152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
18252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
18352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
18452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Allows an application to query whether a service is currently
18552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * the default service to handle a card emulation category.
18652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
18752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>Note that if {@link #getSelectionModeForCategory(String)}
18835bf6288527b177a04100585321a1266f020004aMartijn Coenen     * returns {@link #SELECTION_MODE_ALWAYS_ASK} or {@link #SELECTION_MODE_ASK_IF_CONFLICT},
18935bf6288527b177a04100585321a1266f020004aMartijn Coenen     * this method will always return false. That is because in these
19035bf6288527b177a04100585321a1266f020004aMartijn Coenen     * selection modes a default can't be set at the category level. For categories where
19135bf6288527b177a04100585321a1266f020004aMartijn Coenen     * the selection mode is {@link #SELECTION_MODE_ALWAYS_ASK} or
19235bf6288527b177a04100585321a1266f020004aMartijn Coenen     * {@link #SELECTION_MODE_ASK_IF_CONFLICT}, use
19335bf6288527b177a04100585321a1266f020004aMartijn Coenen     * {@link #isDefaultServiceForAid(ComponentName, String)} to determine whether a service
19435bf6288527b177a04100585321a1266f020004aMartijn Coenen     * is the default for a specific AID.
19552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
19652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param service The ComponentName of the service
19752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param category The category
19852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @return whether service is currently the default service for the category.
19935bf6288527b177a04100585321a1266f020004aMartijn Coenen     *
20035bf6288527b177a04100585321a1266f020004aMartijn Coenen     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
20152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
20252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public boolean isDefaultServiceForCategory(ComponentName service, String category) {
20352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
20452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, category);
20552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
20652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
20752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
20852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
20952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
21052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
21152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
21252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
21352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service,
21452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                        category);
21552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
21652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
21752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
21852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
21952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
22052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
22152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
22252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
22352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
22452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Allows an application to query whether a service is currently
22552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * the default handler for a specified ISO7816-4 Application ID.
22652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
22752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param service The ComponentName of the service
22852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param aid The ISO7816-4 Application ID
22935bf6288527b177a04100585321a1266f020004aMartijn Coenen     * @return whether the service is the default handler for the specified AID
23035bf6288527b177a04100585321a1266f020004aMartijn Coenen     *
23135bf6288527b177a04100585321a1266f020004aMartijn Coenen     * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
23252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
23352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public boolean isDefaultServiceForAid(ComponentName service, String aid) {
23452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
23552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
23652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
23752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
23852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
23952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
24052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
24152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
24252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
24352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
24452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
24552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
24652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
24752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
24852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
24952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
25052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
25152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
25252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
2532f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * Returns whether the user has allowed AIDs registered in the
2542f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * specified category to be handled by a service that is preferred
2552f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * by the foreground application, instead of by a pre-configured default.
2562f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
2572f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * Foreground applications can set such preferences using the
2582f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * {@link #setPreferredService(Activity, ComponentName)} method.
2592f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
2602f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * @param category The category, e.g. {@link #CATEGORY_PAYMENT}
2612f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * @return whether AIDs in the category can be handled by a service
2622f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *         specified by the foreground app.
2632f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     */
2642f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    public boolean categoryAllowsForegroundPreference(String category) {
2652f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        if (CATEGORY_PAYMENT.equals(category)) {
2662f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            boolean preferForeground = false;
2672f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            try {
2682f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                preferForeground = Settings.Secure.getInt(mContext.getContentResolver(),
2692f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                        Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
2702f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            } catch (SettingNotFoundException e) {
2712f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            }
2722f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            return preferForeground;
2732f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        } else {
2742f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            // Allowed for all other categories
2752f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            return true;
2762f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        }
2772f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    }
2782f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen
2792f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    /**
28035bf6288527b177a04100585321a1266f020004aMartijn Coenen     * Returns the service selection mode for the passed in category.
28152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Valid return values are:
28252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
28335bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    service for this category, which will be preferred.
28452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
28535bf6288527b177a04100585321a1266f020004aMartijn Coenen     *    every time what service he would like to use in this category.
28652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
28752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    to pick a service if there is a conflict.
28852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param category The category, for example {@link #CATEGORY_PAYMENT}
28935bf6288527b177a04100585321a1266f020004aMartijn Coenen     * @return the selection mode for the passed in category
29052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
29152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public int getSelectionModeForCategory(String category) {
29252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (CATEGORY_PAYMENT.equals(category)) {
29352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(),
29452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                    Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
29552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (defaultComponent != null) {
29652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return SELECTION_MODE_PREFER_DEFAULT;
29752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } else {
29852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return SELECTION_MODE_ALWAYS_ASK;
29952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
30052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } else {
30152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return SELECTION_MODE_ASK_IF_CONFLICT;
30252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
30352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
30452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
30552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
306df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * Registers a list of AIDs for a specific category for the
307df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * specified service.
308aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     *
309df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * <p>If a list of AIDs for that category was previously
310aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * registered for this service (either statically
311aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * through the manifest, or dynamically by using this API),
312df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * that list of AIDs will be replaced with this one.
313aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     *
314aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * <p>Note that you can only register AIDs for a service that
3152f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * is running under the same UID as the caller of this API. Typically
316aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * this means you need to call this from the same
317aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * package as the service itself, though UIDs can also
318aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * be shared between packages using shared UIDs.
319aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     *
320aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * @param service The component name of the service
321df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * @param category The category of AIDs to be registered
322df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * @param aids A list containing the AIDs to be registered
323aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * @return whether the registration was successful.
324aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     */
325df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen    public boolean registerAidsForService(ComponentName service, String category,
326df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen            List<String> aids) {
327df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen        AidGroup aidGroup = new AidGroup(aids, category);
328aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        try {
329aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            return sService.registerAidGroupForService(UserHandle.myUserId(), service, aidGroup);
330aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        } catch (RemoteException e) {
331aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            // Try one more time
332aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            recoverService();
333aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            if (sService == null) {
334aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
335aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                return false;
336aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
337aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            try {
338aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                return sService.registerAidGroupForService(UserHandle.myUserId(), service,
339aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                        aidGroup);
340aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            } catch (RemoteException ee) {
341aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
342aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                return false;
343aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
344aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
345aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
346aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
347aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    /**
348df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * Retrieves the currently registered AIDs for the specified
349aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * category for a service.
350aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     *
351df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * <p>Note that this will only return AIDs that were dynamically
352df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * registered using {@link #registerAidsForService(ComponentName, String, List)}
353df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * method. It will *not* return AIDs that were statically registered
354aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * in the manifest.
355aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     *
356aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * @param service The component name of the service
357df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * @param category The category for which the AIDs were registered,
358df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     *                 e.g. {@link #CATEGORY_PAYMENT}
359df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * @return The list of AIDs registered for this category, or null if it couldn't be found.
360aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     */
361df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen    public List<String> getAidsForService(ComponentName service, String category) {
362aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        try {
363df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen            AidGroup group =  sService.getAidGroupForService(UserHandle.myUserId(), service,
364df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen                    category);
365df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen            return (group != null ? group.getAids() : null);
366aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        } catch (RemoteException e) {
367aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            recoverService();
368aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            if (sService == null) {
369aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
370aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                return null;
371aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
372aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            try {
373df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen                AidGroup group = sService.getAidGroupForService(UserHandle.myUserId(), service,
374df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen                        category);
375df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen                return (group != null ? group.getAids() : null);
376aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            } catch (RemoteException ee) {
377aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
378aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                return null;
379aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
380aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
381aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
382aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
383aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    /**
384df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * Removes a previously registered list of AIDs for the specified category for the
385aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * service provided.
386aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     *
387df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * <p>Note that this will only remove AIDs that were dynamically
388df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * registered using the {@link #registerAidsForService(ComponentName, String, List)}
389df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * method. It will *not* remove AIDs that were statically registered in
390df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * the manifest. If dynamically registered AIDs are removed using
391aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * this method, and a statically registered AID group for the same category
3922f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * exists in the manifest, the static AID group will become active again.
393aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     *
394aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * @param service The component name of the service
395df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen     * @param category The category of the AIDs to be removed, e.g. {@link #CATEGORY_PAYMENT}
396aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * @return whether the group was successfully removed.
397aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     */
398df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen    public boolean removeAidsForService(ComponentName service, String category) {
399aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        try {
400aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            return sService.removeAidGroupForService(UserHandle.myUserId(), service, category);
401aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        } catch (RemoteException e) {
402aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            // Try one more time
403aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            recoverService();
404aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            if (sService == null) {
405aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
406aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                return false;
407aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
408aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            try {
409aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                return sService.removeAidGroupForService(UserHandle.myUserId(), service, category);
410aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            } catch (RemoteException ee) {
411aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
412aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                return false;
413aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
414aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
415aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
416aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
417aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    /**
4182f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * Allows a foreground application to specify which card emulation service
4192f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * should be preferred while a specific Activity is in the foreground.
4202f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
4212f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * <p>The specified Activity must currently be in resumed state. A good
4222f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * paradigm is to call this method in your {@link Activity#onResume}, and to call
4232f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}.
4242f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
4252f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * <p>This method call will fail in two specific scenarios:
4262f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * <ul>
4272f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT}
4282f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * category, but the user has indicated that foreground apps are not allowed
4292f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * to override the default payment service.
4302f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER}
4312f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * category that are also handled by the default payment service, and the
4322f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * user has indicated that foreground apps are not allowed to override the
4332f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * default payment service.
4342f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * </ul>
4352f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
4362f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine
4372f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * whether foreground apps can override the default payment service.
4382f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
4392f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * <p>Note that this preference is not persisted by the OS, and hence must be
4402f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * called every time the Activity is resumed.
4412f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
4422f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * @param activity The activity which prefers this service to be invoked
4432f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * @param service The service to be preferred while this activity is in the foreground
4442f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * @return whether the registration was successful
4452f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     */
4462f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    public boolean setPreferredService(Activity activity, ComponentName service) {
4472f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        // Verify the activity is in the foreground before calling into NfcService
4482f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        if (activity == null || service == null) {
4492f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            throw new NullPointerException("activity or service or category is null");
4502f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        }
4512f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        if (!activity.isResumed()) {
4522f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            throw new IllegalArgumentException("Activity must be resumed.");
4532f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        }
4542f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        try {
4552f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            return sService.setPreferredService(service);
4562f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        } catch (RemoteException e) {
4572f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            // Try one more time
4582f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            recoverService();
4592f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            if (sService == null) {
4602f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
4612f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                return false;
4622f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            }
4632f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            try {
4642f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                return sService.setPreferredService(service);
4652f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            } catch (RemoteException ee) {
4662f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
4672f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                return false;
4682f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            }
4692f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        }
4702f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    }
4712f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen
4722f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    /**
4732f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * Unsets the preferred service for the specified Activity.
4742f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
4752f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * <p>Note that the specified Activity must still be in resumed
4762f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * state at the time of this call. A good place to call this method
4772f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * is in your {@link Activity#onPause} implementation.
4782f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     *
4792f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * @param activity The activity which the service was registered for
4802f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * @return true when successful
4812f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     */
4822f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    public boolean unsetPreferredService(Activity activity) {
4832f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        if (activity == null) {
4842f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            throw new NullPointerException("activity is null");
4852f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        }
4862f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        if (!activity.isResumed()) {
4872f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            throw new IllegalArgumentException("Activity must be resumed.");
4882f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        }
4892f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        try {
4902f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            return sService.unsetPreferredService();
4912f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        } catch (RemoteException e) {
4922f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            // Try one more time
4932f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            recoverService();
4942f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            if (sService == null) {
4952f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
4962f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                return false;
4972f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            }
4982f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            try {
4992f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                return sService.unsetPreferredService();
5002f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            } catch (RemoteException ee) {
5012f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
5022f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen                return false;
5032f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            }
5042f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        }
5052f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    }
5062f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen
5072f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    /**
508d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     * Some devices may allow an application to register all
509d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     * AIDs that starts with a certain prefix, e.g.
510d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     * "A000000004*" to register all MasterCard AIDs.
511d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     *
512d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     * Use this method to determine whether this device
513d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     * supports registering AID prefixes.
514d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     *
515d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     * @return whether AID prefix registering is supported on this device.
516d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen     */
517d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen    public boolean supportsAidPrefixRegistration() {
518826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen        try {
519826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen            return sService.supportsAidPrefixRegistration();
520826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen        } catch (RemoteException e) {
521826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen            recoverService();
522826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen            if (sService == null) {
523826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
524826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen                return false;
525826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen            }
526826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen            try {
527826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen                return sService.supportsAidPrefixRegistration();
528826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen            } catch (RemoteException ee) {
529826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
530826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen                return false;
531826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen            }
532826a73b83b7f05ff92e51a2880fb4a75de08a9d1Martijn Coenen        }
533d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen    }
534d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen
535d92c1689748b4630964f1ecf87e56de4b0aa7396Martijn Coenen    /**
53652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @hide
53752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
53852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public boolean setDefaultServiceForCategory(ComponentName service, String category) {
53952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
54052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, category);
54152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
54252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
54352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
54452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
54552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
54652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
54752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
54852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
54952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service,
55052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                        category);
55152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
55252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
55352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
55452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
55552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
55652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
55752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
55852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
55952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @hide
56052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
56152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public boolean setDefaultForNextTap(ComponentName service) {
56252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
56352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
56452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
56552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
56652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
56752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
56852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
56952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
57052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
57152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
57252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
57352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
57452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
57552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
57652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
57752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
57852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
57935bf6288527b177a04100585321a1266f020004aMartijn Coenen
58052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
58152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @hide
58252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
58352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public List<ApduServiceInfo> getServices(String category) {
58452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
58552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.getServices(UserHandle.myUserId(), category);
58652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
58752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
58852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
58952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
59052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
59152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return null;
59252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
59352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
59452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.getServices(UserHandle.myUserId(), category);
59552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
59652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
59752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return null;
59852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
59952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
60052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
60152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
602b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen    /**
603b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     * A valid AID according to ISO/IEC 7816-4:
604b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     * <ul>
605b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
606b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     * <li>Consist of only hex characters
607b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     * <li>Additionally, we allow an asterisk at the end, to indicate
608b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     *     a prefix
609b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     * </ul>
610b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     *
611b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     * @hide
612b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen     */
613b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen    public static boolean isValidAid(String aid) {
614b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        if (aid == null)
615b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen            return false;
616b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen
617b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        // If a prefix AID, the total length must be odd (even # of AID chars + '*')
618b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        if (aid.endsWith("*") && ((aid.length() % 2) == 0)) {
619b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen            Log.e(TAG, "AID " + aid + " is not a valid AID.");
620b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen            return false;
621b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        }
622b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen
623b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        // If not a prefix AID, the total length must be even (even # of AID chars)
624b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        if (!aid.endsWith("*") && ((aid.length() % 2) != 0)) {
625b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen            Log.e(TAG, "AID " + aid + " is not a valid AID.");
626b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen            return false;
627b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        }
628b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen
629b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        // Verify hex characters
630b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        if (!aid.matches("[0-9A-Fa-f]{10,32}\\*?")) {
631b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen            Log.e(TAG, "AID " + aid + " is not a valid AID.");
632b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen            return false;
633b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        }
634b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen
635b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen        return true;
636b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen    }
637b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen
63852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    void recoverService() {
63952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
64052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        sService = adapter.getCardEmulationService();
64152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
642b51441163fc4c493cddce08f5418021a31d0a719Martijn Coenen
64352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen}
644