Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a6dcf1a2 authored by Martijn Coenen's avatar Martijn Coenen Committed by Android (Google) Code Review
Browse files

Merge "Add an API for querying HCE service selection mode." into klp-dev

parents c9c5d57e c3f0044a
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -15261,6 +15261,7 @@ package android.nfc.cardemulation {
  public final class CardEmulationManager {
    method public static synchronized android.nfc.cardemulation.CardEmulationManager getInstance(android.nfc.NfcAdapter);
    method public int getSelectionModeForCategory(java.lang.String);
    method public boolean isDefaultServiceForAid(android.content.ComponentName, java.lang.String);
    method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
    field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.ACTION_CHANGE_DEFAULT";
@@ -15268,6 +15269,9 @@ package android.nfc.cardemulation {
    field public static final java.lang.String CATEGORY_PAYMENT = "payment";
    field public static final java.lang.String EXTRA_CATEGORY = "category";
    field public static final java.lang.String EXTRA_SERVICE_COMPONENT = "component";
    field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1
    field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2
    field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0
  }
  public abstract class HostApduService extends android.app.Service {
+18 −2
Original line number Diff line number Diff line
@@ -74,17 +74,23 @@ public final class ApduServiceInfo implements Parcelable {
     */
    final HashMap<String, AidGroup> mCategoryToGroup;

    /**
     * Whether this service should only be started when the device is unlocked.
     */
    final boolean mRequiresDeviceUnlock;

    /**
     * @hide
     */
    public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
            ArrayList<AidGroup> aidGroups) {
            ArrayList<AidGroup> aidGroups, boolean requiresUnlock) {
        this.mService = info;
        this.mDescription = description;
        this.mAidGroups = aidGroups;
        this.mAids = new ArrayList<String>();
        this.mCategoryToGroup = new HashMap<String, AidGroup>();
        this.mOnHost = onHost;
        this.mRequiresDeviceUnlock = requiresUnlock;
        for (AidGroup aidGroup : aidGroups) {
            this.mCategoryToGroup.put(aidGroup.category, aidGroup);
            this.mAids.addAll(aidGroup.aids);
@@ -132,12 +138,16 @@ public final class ApduServiceInfo implements Parcelable {
                mService = info;
                mDescription = sa.getString(
                        com.android.internal.R.styleable.HostApduService_description);
                mRequiresDeviceUnlock = sa.getBoolean(
                        com.android.internal.R.styleable.HostApduService_requireDeviceUnlock,
                        false);
            } else {
                TypedArray sa = res.obtainAttributes(attrs,
                        com.android.internal.R.styleable.OffHostApduService);
                mService = info;
                mDescription = sa.getString(
                        com.android.internal.R.styleable.OffHostApduService_description);
                mRequiresDeviceUnlock = false;
            }

            mAidGroups = new ArrayList<AidGroup>();
@@ -226,6 +236,10 @@ public final class ApduServiceInfo implements Parcelable {
        return mOnHost;
    }

    public boolean requiresUnlock() {
        return mRequiresDeviceUnlock;
    }

    public CharSequence loadLabel(PackageManager pm) {
        return mService.loadLabel(pm);
    }
@@ -287,6 +301,7 @@ public final class ApduServiceInfo implements Parcelable {
        if (mAidGroups.size() > 0) {
            dest.writeTypedList(mAidGroups);
        }
        dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
    };

    public static final Parcelable.Creator<ApduServiceInfo> CREATOR =
@@ -301,7 +316,8 @@ public final class ApduServiceInfo implements Parcelable {
            if (numGroups > 0) {
                source.readTypedList(aidGroups, AidGroup.CREATOR);
            }
            return new ApduServiceInfo(info, onHost, description, aidGroups);
            boolean requiresUnlock = (source.readInt() != 0) ? true : false;
            return new ApduServiceInfo(info, onHost, description, aidGroups, requiresUnlock);
        }

        @Override
+93 −8
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.nfc.INfcCardEmulation;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;

import java.util.HashMap;
@@ -78,19 +79,68 @@ public final class CardEmulationManager {
     */
    public static final String CATEGORY_OTHER = "other";

    static boolean sIsInitialized = false;
    static HashMap<Context, CardEmulationManager> sCardEmuManagers = new HashMap();
    static INfcCardEmulation sService;
    /**
     * Return value for {@link #getSelectionModeForCategory(String)}.
     *
     * <p>In this mode, the user has set a default service for this
     *    AID category. If a remote reader selects any of the AIDs
     *    that the default service has registered in this category,
     *    that service will automatically be bound to to handle
     *    the transaction.
     *
     * <p>There are still cases where a service that is
     *    not the default for a category can selected:
     *    <p>
     *    If a remote reader selects an AID in this category
     *    that is not handled by the default service, and there is a set
     *    of other services {S} that do handle this AID, the
     *    user is asked if he wants to use any of the services in
     *    {S} instead.
     *    <p>
     *    As a special case, if the size of {S} is one, containing a single service X,
     *    and all AIDs X has registered in this category are not
     *    registered by any other service, then X will be
     *    selected automatically without asking the user.
     *    <p>Example:
     *    <ul>
     *    <li>Service A registers AIDs "1", "2" and "3" in the category
     *    <li>Service B registers AIDs "3" and "4" in the category
     *    <li>Service C registers AIDs "5" and "6" in the category
     *    </ul>
     *    In this case, the following will happen when service A
     *    is the default:
     *    <ul>
     *    <li>Reader selects AID "1", "2" or "3": service A is invoked automatically
     *    <li>Reader selects AID "4": the user is asked to confirm he
     *        wants to use service B, because its AIDs overlap with service A.
     *    <li>Reader selects AID "5" or "6": service C is invoked automatically,
     *        because all AIDs it has asked for are only registered by C,
     *        and there is no overlap.
     *    </ul>
     *
     */
    public static final int SELECTION_MODE_PREFER_DEFAULT = 0;

    /**
     * @hide
     * Return value for {@link #getSelectionModeForCategory(String)}.
     *
     * <p>In this mode, whenever an AID of this category is selected,
     *    the user is asked which service he wants to use to handle
     *    the transaction, even if there is only one matching service.
     */
    public static final String PAYMENT_MODE_AUTO = "auto";
    public static final int SELECTION_MODE_ALWAYS_ASK = 1;

    /**
     * @hide
     * Return value for {@link #getSelectionModeForCategory(String)}.
     *
     * <p>In this mode, the user will only be asked to select a service
     *    if the selected AID has been registered by multiple applications.
     */
    public static final String PAYMENT_MODE_MANUAL = "manual";
    public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;

    static boolean sIsInitialized = false;
    static HashMap<Context, CardEmulationManager> sCardEmuManagers = new HashMap();
    static INfcCardEmulation sService;

    final Context mContext;

@@ -113,7 +163,7 @@ public final class CardEmulationManager {
                throw new UnsupportedOperationException();
            }
            try {
                if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HCE)) {
                if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
                    Log.e(TAG, "This device does not support card emulation");
                    throw new UnsupportedOperationException();
                }
@@ -137,6 +187,10 @@ public final class CardEmulationManager {
     * Allows an application to query whether a service is currently
     * the default service to handle a card emulation category.
     *
     * <p>Note that if {@link #getSelectionModeForCategory(String)}
     * returns {@link #SELECTION_MODE_ALWAYS_ASK}, this method will always
     * return false.
     *
     * @param service The ComponentName of the service
     * @param category The category
     * @return whether service is currently the default service for the category.
@@ -147,6 +201,10 @@ public final class CardEmulationManager {
        } catch (RemoteException e) {
            // Try one more time
            recoverService();
            if (sService == null) {
                Log.e(TAG, "Failed to recover CardEmulationService.");
                return false;
            }
            try {
                return sService.isDefaultServiceForCategory(UserHandle.myUserId(), service,
                        category);
@@ -185,6 +243,33 @@ public final class CardEmulationManager {
        }
    }

    /**
     * Returns the application selection mode for the passed in category.
     * Valid return values are:
     * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
     *    application for this category, which will be preferred.
     * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
     *    every time what app he would like to use in this category.
     * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
     *    to pick a service if there is a conflict.
     * @param category The category, for example {@link #CATEGORY_PAYMENT}
     * @return
     */
    public int getSelectionModeForCategory(String category) {
        if (CATEGORY_PAYMENT.equals(category)) {
            String defaultComponent = Settings.Secure.getString(mContext.getContentResolver(),
                    Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
            if (defaultComponent != null) {
                return SELECTION_MODE_PREFER_DEFAULT;
            } else {
                return SELECTION_MODE_ALWAYS_ASK;
            }
        } else {
            // All other categories are in "only ask if conflict" mode
            return SELECTION_MODE_ASK_IF_CONFLICT;
        }
    }

    /**
     * @hide
     */
+0 −2
Original line number Diff line number Diff line
@@ -4,13 +4,11 @@ import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

+0 −6
Original line number Diff line number Diff line
@@ -4284,12 +4284,6 @@ public final class Settings {
         */
        public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";

        /**
         * Whether to automatically invoke NFC payment app or manually select on tap.
         * @hide
         */
        public static final String NFC_PAYMENT_MODE = "nfc_payment_mode";

        /**
         * Name of a package that the current user has explicitly allowed to see all of that
         * user's notifications.