summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartijn Coenen <maco@google.com>2014-05-08 23:33:50 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-05-08 23:33:51 +0000
commit781a83878ab8f6ba3fa725084a9d1de5a08b5da9 (patch)
tree1db81cb699d7d2c90af72d4d959a6b060e6868aa
parent82af2b9e51aac359b4b251cc622659a1a5537e35 (diff)
parent2f6f3a0181b008f58b18804b749d5ddf1ba73bc8 (diff)
downloadframeworks_base-781a83878ab8f6ba3fa725084a9d1de5a08b5da9.zip
frameworks_base-781a83878ab8f6ba3fa725084a9d1de5a08b5da9.tar.gz
frameworks_base-781a83878ab8f6ba3fa725084a9d1de5a08b5da9.tar.bz2
Merge "HCE/SE foreground support."
-rw-r--r--api/current.txt3
-rw-r--r--core/java/android/nfc/INfcCardEmulation.aidl2
-rw-r--r--core/java/android/nfc/cardemulation/AidGroup.java24
-rw-r--r--core/java/android/nfc/cardemulation/ApduServiceInfo.java14
-rw-r--r--core/java/android/nfc/cardemulation/CardEmulation.java124
-rw-r--r--core/java/android/provider/Settings.java6
6 files changed, 161 insertions, 12 deletions
diff --git a/api/current.txt b/api/current.txt
index 5ca1f59..c664223 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17136,6 +17136,7 @@ package android.nfc.cardemulation {
}
public final class CardEmulation {
+ method public boolean categoryAllowsForegroundPreference(java.lang.String);
method public android.nfc.cardemulation.AidGroup getAidGroupForService(android.content.ComponentName, java.lang.String);
method public static synchronized android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
method public int getSelectionModeForCategory(java.lang.String);
@@ -17143,6 +17144,8 @@ package android.nfc.cardemulation {
method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
method public boolean registerAidGroupForService(android.content.ComponentName, android.nfc.cardemulation.AidGroup);
method public boolean removeAidGroupForService(android.content.ComponentName, java.lang.String);
+ method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
+ method public boolean unsetPreferredService(android.app.Activity);
field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
field public static final java.lang.String CATEGORY_OTHER = "other";
field public static final java.lang.String CATEGORY_PAYMENT = "payment";
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl
index ae9796b..521f4fd 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/core/java/android/nfc/INfcCardEmulation.aidl
@@ -34,4 +34,6 @@ interface INfcCardEmulation
AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
List<ApduServiceInfo> getServices(int userHandle, in String category);
+ boolean setPreferredService(in ComponentName service);
+ boolean unsetPreferredService();
}
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 2820f40..b0449224 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -12,10 +12,15 @@ import android.os.Parcelable;
import android.util.Log;
/**
- * The AidGroup class represents a group of ISO/IEC 7816-4
- * Application Identifiers (AIDs) for a specific application
- * category, along with a description resource describing
- * the group.
+ * The AidGroup class represents a group of Application Identifiers (AIDs).
+ *
+ * <p>An instance of this object can be used with
+ * {@link CardEmulation#registerAidGroupForService(android.content.ComponentName, AidGroup)}
+ * to tell the OS which AIDs are handled by your HCE- or SE-based service.
+ *
+ * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class
+ * requires the AIDs to be input as a hexadecimal string, with an even amount of
+ * hexadecimal characters, e.g. "F014811481".
*/
public final class AidGroup implements Parcelable {
/**
@@ -33,7 +38,7 @@ public final class AidGroup implements Parcelable {
* Creates a new AidGroup object.
*
* @param aids The list of AIDs present in the group
- * @param category The category of this group
+ * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
*/
public AidGroup(ArrayList<String> aids, String category) {
if (aids == null || aids.size() == 0) {
@@ -42,11 +47,12 @@ public final class AidGroup implements Parcelable {
if (aids.size() > MAX_NUM_AIDS) {
throw new IllegalArgumentException("Too many AIDs in AID group.");
}
- if (!isValidCategory(category)) {
- throw new IllegalArgumentException("Category specified is not valid.");
+ if (isValidCategory(category)) {
+ this.category = category;
+ } else {
+ this.category = CardEmulation.CATEGORY_OTHER;
}
this.aids = aids;
- this.category = category;
this.description = null;
}
@@ -158,7 +164,7 @@ public final class AidGroup implements Parcelable {
}
}
- boolean isValidCategory(String category) {
+ static boolean isValidCategory(String category) {
return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
CardEmulation.CATEGORY_OTHER.equals(category);
}
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 94f35ed..f379ee8 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -290,6 +290,20 @@ public final class ApduServiceInfo implements Parcelable {
return groups;
}
+ /**
+ * Returns the category to which this service has attributed the AID that is passed in,
+ * or null if we don't know this AID.
+ */
+ public String getCategoryForAid(String aid) {
+ ArrayList<AidGroup> groups = getAidGroups();
+ for (AidGroup group : groups) {
+ if (group.aids.contains(aid)) {
+ return group.category;
+ }
+ }
+ return null;
+ }
+
public boolean hasCategory(String category) {
return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
}
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 41f039c..e24a22a 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -18,6 +18,7 @@ package android.nfc.cardemulation;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Activity;
import android.app.ActivityThread;
import android.content.ComponentName;
import android.content.Context;
@@ -28,6 +29,7 @@ import android.nfc.NfcAdapter;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
+import android.provider.Settings.SettingNotFoundException;
import android.util.Log;
import java.util.HashMap;
@@ -248,6 +250,33 @@ public final class CardEmulation {
}
/**
+ * Returns whether the user has allowed AIDs registered in the
+ * specified category to be handled by a service that is preferred
+ * by the foreground application, instead of by a pre-configured default.
+ *
+ * Foreground applications can set such preferences using the
+ * {@link #setPreferredService(Activity, ComponentName)} method.
+ *
+ * @param category The category, e.g. {@link #CATEGORY_PAYMENT}
+ * @return whether AIDs in the category can be handled by a service
+ * specified by the foreground app.
+ */
+ public boolean categoryAllowsForegroundPreference(String category) {
+ if (CATEGORY_PAYMENT.equals(category)) {
+ boolean preferForeground = false;
+ try {
+ preferForeground = Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
+ } catch (SettingNotFoundException e) {
+ }
+ return preferForeground;
+ } else {
+ // Allowed for all other categories
+ return true;
+ }
+ }
+
+ /**
* Returns the service selection mode for the passed in category.
* Valid return values are:
* <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
@@ -269,7 +298,6 @@ public final class CardEmulation {
return SELECTION_MODE_ALWAYS_ASK;
}
} else {
- // All other categories are in "only ask if conflict" mode
return SELECTION_MODE_ASK_IF_CONFLICT;
}
}
@@ -283,7 +311,7 @@ public final class CardEmulation {
* that AID group will be replaced with this one.
*
* <p>Note that you can only register AIDs for a service that
- * is running under the same UID as you are. Typically
+ * is running under the same UID as the caller of this API. Typically
* this means you need to call this from the same
* package as the service itself, though UIDs can also
* be shared between packages using shared UIDs.
@@ -352,7 +380,7 @@ public final class CardEmulation {
* method. It will *not* remove AID groups that were statically registered in
* the manifest. If a dynamically registered AID group is removed using
* this method, and a statically registered AID group for the same category
- * exists in the manifest, that AID group will become active again.
+ * exists in the manifest, the static AID group will become active again.
*
* @param service The component name of the service
* @param category The category of the AID group to be removed, e.g. {@link #CATEGORY_PAYMENT}
@@ -378,6 +406,96 @@ public final class CardEmulation {
}
/**
+ * Allows a foreground application to specify which card emulation service
+ * should be preferred while a specific Activity is in the foreground.
+ *
+ * <p>The specified Activity must currently be in resumed state. A good
+ * paradigm is to call this method in your {@link Activity#onResume}, and to call
+ * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}.
+ *
+ * <p>This method call will fail in two specific scenarios:
+ * <ul>
+ * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT}
+ * category, but the user has indicated that foreground apps are not allowed
+ * to override the default payment service.
+ * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER}
+ * category that are also handled by the default payment service, and the
+ * user has indicated that foreground apps are not allowed to override the
+ * default payment service.
+ * </ul>
+ *
+ * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine
+ * whether foreground apps can override the default payment service.
+ *
+ * <p>Note that this preference is not persisted by the OS, and hence must be
+ * called every time the Activity is resumed.
+ *
+ * @param activity The activity which prefers this service to be invoked
+ * @param service The service to be preferred while this activity is in the foreground
+ * @return whether the registration was successful
+ */
+ public boolean setPreferredService(Activity activity, ComponentName service) {
+ // Verify the activity is in the foreground before calling into NfcService
+ if (activity == null || service == null) {
+ throw new NullPointerException("activity or service or category is null");
+ }
+ if (!activity.isResumed()) {
+ throw new IllegalArgumentException("Activity must be resumed.");
+ }
+ try {
+ return sService.setPreferredService(service);
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.setPreferredService(service);
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Unsets the preferred service for the specified Activity.
+ *
+ * <p>Note that the specified Activity must still be in resumed
+ * state at the time of this call. A good place to call this method
+ * is in your {@link Activity#onPause} implementation.
+ *
+ * @param activity The activity which the service was registered for
+ * @return true when successful
+ */
+ public boolean unsetPreferredService(Activity activity) {
+ if (activity == null) {
+ throw new NullPointerException("activity is null");
+ }
+ if (!activity.isResumed()) {
+ throw new IllegalArgumentException("Activity must be resumed.");
+ }
+ try {
+ return sService.unsetPreferredService();
+ } catch (RemoteException e) {
+ // Try one more time
+ recoverService();
+ if (sService == null) {
+ Log.e(TAG, "Failed to recover CardEmulationService.");
+ return false;
+ }
+ try {
+ return sService.unsetPreferredService();
+ } catch (RemoteException ee) {
+ Log.e(TAG, "Failed to reach CardEmulationService.");
+ return false;
+ }
+ }
+ }
+
+ /**
* @hide
*/
public boolean setDefaultServiceForCategory(ComponentName service, String category) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dc618c8..1847b55 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4529,6 +4529,12 @@ public final class Settings {
public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
/**
+ * Whether NFC payment is handled by the foreground application or a default.
+ * @hide
+ */
+ public static final String NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground";
+
+ /**
* Specifies the package name currently configured to be the primary sms application
* @hide
*/