CardEmulation.java revision 52246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7
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;
2152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.app.ActivityThread;
2252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.ComponentName;
2352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.Context;
2452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.pm.IPackageManager;
2552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.content.pm.PackageManager;
2652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.nfc.INfcCardEmulation;
2752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.nfc.NfcAdapter;
2852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.os.RemoteException;
2952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.os.UserHandle;
3052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.provider.Settings;
3152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport android.util.Log;
3252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
3352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport java.util.HashMap;
3452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenimport java.util.List;
3552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
3652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenenpublic final class CardEmulation {
3752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    static final String TAG = "CardEmulation";
3852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
3952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
4052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Activity action: ask the user to change the default
4152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * card emulation service for a certain category. This will
4252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * show a dialog that asks the user whether he wants to
4352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * replace the current default service with the service
4452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * identified with the ComponentName specified in
4552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * {@link #EXTRA_SERVICE_COMPONENT}, for the category
4652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * specified in {@link #EXTRA_CATEGORY}
4752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
4852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
4952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String ACTION_CHANGE_DEFAULT =
5052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
5152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
5252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
5352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * The category extra for {@link #ACTION_CHANGE_DEFAULT}
5452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
5552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @see #ACTION_CHANGE_DEFAULT
5652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
5752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String EXTRA_CATEGORY = "category";
5852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
5952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
6052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * The ComponentName object passed in as a parcelable
6152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * extra for {@link #ACTION_CHANGE_DEFAULT}
6252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
6352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @see #ACTION_CHANGE_DEFAULT
6452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
6552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String EXTRA_SERVICE_COMPONENT = "component";
6652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
6752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
6852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * The payment category can be used to indicate that an AID
6952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * represents a payment application.
7052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
7152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String CATEGORY_PAYMENT = "payment";
7252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
7352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
7452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * If an AID group does not contain a category, or the
7552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * specified category is not defined by the platform version
7652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * that is parsing the AID group, all AIDs in the group will
7752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * automatically be categorized under the {@link #CATEGORY_OTHER}
7852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * category.
7952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
8052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final String CATEGORY_OTHER = "other";
8152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
8252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
8352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Return value for {@link #getSelectionModeForCategory(String)}.
8452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
8552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>In this mode, the user has set a default service for this
8652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    AID category. If a remote reader selects any of the AIDs
8752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    that the default service has registered in this category,
8852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    that service will automatically be bound to to handle
8952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    the transaction.
9052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
9152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>There are still cases where a service that is
9252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    not the default for a category can selected:
9352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <p>
9452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    If a remote reader selects an AID in this category
9552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    that is not handled by the default service, and there is a set
9652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    of other services {S} that do handle this AID, the
9752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    user is asked if he wants to use any of the services in
9852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    {S} instead.
9952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <p>
10052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    As a special case, if the size of {S} is one, containing a single service X,
10152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    and all AIDs X has registered in this category are not
10252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    registered by any other service, then X will be
10352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    selected automatically without asking the user.
10452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <p>Example:
10552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <ul>
10652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <li>Service A registers AIDs "1", "2" and "3" in the category
10752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <li>Service B registers AIDs "3" and "4" in the category
10852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <li>Service C registers AIDs "5" and "6" in the category
10952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    </ul>
11052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    In this case, the following will happen when service A
11152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    is the default:
11252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <ul>
11352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <li>Reader selects AID "1", "2" or "3": service A is invoked automatically
11452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <li>Reader selects AID "4": the user is asked to confirm he
11552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *        wants to use service B, because its AIDs overlap with service A.
11652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    <li>Reader selects AID "5" or "6": service C is invoked automatically,
11752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *        because all AIDs it has asked for are only registered by C,
11852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *        and there is no overlap.
11952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    </ul>
12052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
12152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
12252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
12352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
12452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
12552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Return value for {@link #getSelectionModeForCategory(String)}.
12652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
12752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>In this mode, whenever an AID of this category is selected,
12852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    the user is asked which service he wants to use to handle
12952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    the transaction, even if there is only one matching service.
13052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
13152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final int SELECTION_MODE_ALWAYS_ASK = 1;
13252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
13352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
13452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Return value for {@link #getSelectionModeForCategory(String)}.
13552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
13652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>In this mode, the user will only be asked to select a service
13752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    if the selected AID has been registered by multiple applications.
13852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
13952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
14052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
14152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    static boolean sIsInitialized = false;
14252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    static HashMap<Context, CardEmulation> sCardEmus = new HashMap();
14352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    static INfcCardEmulation sService;
14452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
14552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    final Context mContext;
14652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
14752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    private CardEmulation(Context context, INfcCardEmulation service) {
14852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        mContext = context.getApplicationContext();
14952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        sService = service;
15052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
15152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
15252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public static synchronized CardEmulation getInstance(NfcAdapter adapter) {
15352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (adapter == null) throw new NullPointerException("NfcAdapter is null");
15452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        Context context = adapter.getContext();
15552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (context == null) {
15652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            Log.e(TAG, "NfcAdapter context is null.");
15752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            throw new UnsupportedOperationException();
15852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
15952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (!sIsInitialized) {
16052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            IPackageManager pm = ActivityThread.getPackageManager();
16152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (pm == null) {
16252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Cannot get PackageManager");
16352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                throw new UnsupportedOperationException();
16452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
16552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
16652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
16752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                    Log.e(TAG, "This device does not support card emulation");
16852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                    throw new UnsupportedOperationException();
16952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                }
17052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException e) {
17152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "PackageManager query failed.");
17252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                throw new UnsupportedOperationException();
17352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
17452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            sIsInitialized = true;
17552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
17652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        CardEmulation manager = sCardEmus.get(context);
17752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (manager == null) {
17852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Get card emu service
17952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            INfcCardEmulation service = adapter.getCardEmulationService();
18052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            manager = new CardEmulation(context, service);
18152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            sCardEmus.put(context, manager);
18252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
18352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        return manager;
18452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
18552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
18652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
18752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Allows an application to query whether a service is currently
18852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * the default service to handle a card emulation category.
18952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
19052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>Note that if {@link #getSelectionModeForCategory(String)}
19152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always
19252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * return false.
19352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
19452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param service The ComponentName of the service
19552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param category The category
19652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @return whether service is currently the default service for the category.
19752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
19852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public boolean isDefaultServiceForCategory(ComponentName service, String category) {
19952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
20052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service, category);
20152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
20252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
20352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
20452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
20552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
20652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
20752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
20852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
20952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service,
21052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                        category);
21152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
21252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
21352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
21452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
21552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
21652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
21752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
21852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
21952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
22052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Allows an application to query whether a service is currently
22152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * the default handler for a specified ISO7816-4 Application ID.
22252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *
22352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param service The ComponentName of the service
22452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param aid The ISO7816-4 Application ID
22552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @return
22652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
22752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public boolean isDefaultServiceForAid(ComponentName service, String aid) {
22852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
22952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
23052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
23152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
23252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
23352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
23452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
23552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
23652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
23752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
23852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.isDefaultServiceForAid(UserHandle.myUserId(), service, aid);
23952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
24052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
24152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
24252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
24352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
24452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
24552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
24652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
24752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Returns the application selection mode for the passed in category.
24852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * Valid return values are:
24952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
25052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    application for this category, which will be preferred.
25152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
25252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    every time what app he would like to use in this category.
25352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
25452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     *    to pick a service if there is a conflict.
25552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @param category The category, for example {@link #CATEGORY_PAYMENT}
25652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @return
25752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
25852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public int getSelectionModeForCategory(String category) {
25952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        if (CATEGORY_PAYMENT.equals(category)) {
26052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(),
26152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                    Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
26252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (defaultComponent != null) {
26352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return SELECTION_MODE_PREFER_DEFAULT;
26452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } else {
26552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return SELECTION_MODE_ALWAYS_ASK;
26652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
26752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } else {
26852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // All other categories are in "only ask if conflict" mode
26952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return SELECTION_MODE_ASK_IF_CONFLICT;
27052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
27152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
27252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
27352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
27452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @hide
27552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
27652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public boolean setDefaultServiceForCategory(ComponentName service, String category) {
27752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
27852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service, category);
27952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
28052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
28152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
28252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
28352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
28452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
28552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
28652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
28752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.setDefaultServiceForCategory(UserHandle.myUserId(), service,
28852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                        category);
28952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
29052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
29152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
29252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
29352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
29452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
29552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
29652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
29752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @hide
29852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
29952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public boolean setDefaultForNextTap(ComponentName service) {
30052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
30152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
30252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
30352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
30452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
30552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
30652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
30752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
30852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
30952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
31052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.setDefaultForNextTap(UserHandle.myUserId(), service);
31152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
31252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
31352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return false;
31452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
31552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
31652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
31752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    /**
31852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     * @hide
31952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen     */
32052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    public List<ApduServiceInfo> getServices(String category) {
32152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        try {
32252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            return sService.getServices(UserHandle.myUserId(), category);
32352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        } catch (RemoteException e) {
32452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            // Try one more time
32552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            recoverService();
32652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            if (sService == null) {
32752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to recover CardEmulationService.");
32852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return null;
32952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
33052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            try {
33152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return sService.getServices(UserHandle.myUserId(), category);
33252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            } catch (RemoteException ee) {
33352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                Log.e(TAG, "Failed to reach CardEmulationService.");
33452246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen                return null;
33552246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen            }
33652246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        }
33752246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
33852246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen
33952246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    void recoverService() {
34052246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
34152246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen        sService = adapter.getCardEmulationService();
34252246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen    }
34352246087f4e2b5ad62b9cd6ea8c2cb58f624d4e7Martijn Coenen}
344