Dynamic AID registration APIs for HCE.
Adds a set of APIs that allows applications to dynamically register and unregister AID groups for HCE and Secure Element based services. Change-Id: I08e9423dff405955cb725c87423c953a7dbe5c72
This commit is contained in:
@@ -16813,11 +16813,24 @@ package android.nfc {
|
||||
|
||||
package android.nfc.cardemulation {
|
||||
|
||||
public final class AidGroup implements android.os.Parcelable {
|
||||
ctor public AidGroup(java.util.ArrayList<java.lang.String>, java.lang.String);
|
||||
method public int describeContents();
|
||||
method public java.util.ArrayList<java.lang.String> getAids();
|
||||
method public java.lang.String getCategory();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
field public static final android.os.Parcelable.Creator CREATOR;
|
||||
field public static final int MAX_NUM_AIDS = 256; // 0x100
|
||||
}
|
||||
|
||||
public final class CardEmulation {
|
||||
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);
|
||||
method public boolean isDefaultServiceForAid(android.content.ComponentName, java.lang.String);
|
||||
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);
|
||||
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";
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package android.nfc;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.nfc.cardemulation.AidGroup;
|
||||
import android.nfc.cardemulation.ApduServiceInfo;
|
||||
import android.os.RemoteCallback;
|
||||
|
||||
@@ -29,5 +30,8 @@ interface INfcCardEmulation
|
||||
boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid);
|
||||
boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
|
||||
boolean setDefaultForNextTap(int userHandle, in ComponentName service);
|
||||
boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
|
||||
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);
|
||||
}
|
||||
|
||||
19
core/java/android/nfc/cardemulation/AidGroup.aidl
Normal file
19
core/java/android/nfc/cardemulation/AidGroup.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.nfc.cardemulation;
|
||||
|
||||
parcelable AidGroup;
|
||||
165
core/java/android/nfc/cardemulation/AidGroup.java
Normal file
165
core/java/android/nfc/cardemulation/AidGroup.java
Normal file
@@ -0,0 +1,165 @@
|
||||
package android.nfc.cardemulation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.os.Parcel;
|
||||
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.
|
||||
*/
|
||||
public final class AidGroup implements Parcelable {
|
||||
/**
|
||||
* The maximum number of AIDs that can be present in any one group.
|
||||
*/
|
||||
public static final int MAX_NUM_AIDS = 256;
|
||||
|
||||
static final String TAG = "AidGroup";
|
||||
|
||||
final ArrayList<String> aids;
|
||||
final String category;
|
||||
final String description;
|
||||
|
||||
/**
|
||||
* Creates a new AidGroup object.
|
||||
*
|
||||
* @param aids The list of AIDs present in the group
|
||||
* @param category The category of this group
|
||||
*/
|
||||
public AidGroup(ArrayList<String> aids, String category) {
|
||||
if (aids == null || aids.size() == 0) {
|
||||
throw new IllegalArgumentException("No AIDS in AID group.");
|
||||
}
|
||||
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.");
|
||||
}
|
||||
this.aids = aids;
|
||||
this.category = category;
|
||||
this.description = null;
|
||||
}
|
||||
|
||||
AidGroup(String category, String description) {
|
||||
this.aids = new ArrayList<String>();
|
||||
this.category = category;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the category of this AID group
|
||||
*/
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of AIDs in this group
|
||||
*/
|
||||
public ArrayList<String> getAids() {
|
||||
return aids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder out = new StringBuilder("Category: " + category +
|
||||
", AIDs:");
|
||||
for (String aid : aids) {
|
||||
out.append(aid);
|
||||
out.append(", ");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(category);
|
||||
dest.writeInt(aids.size());
|
||||
if (aids.size() > 0) {
|
||||
dest.writeStringList(aids);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<AidGroup> CREATOR =
|
||||
new Parcelable.Creator<AidGroup>() {
|
||||
|
||||
@Override
|
||||
public AidGroup createFromParcel(Parcel source) {
|
||||
String category = source.readString();
|
||||
int listSize = source.readInt();
|
||||
ArrayList<String> aidList = new ArrayList<String>();
|
||||
if (listSize > 0) {
|
||||
source.readStringList(aidList);
|
||||
}
|
||||
return new AidGroup(aidList, category);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AidGroup[] newArray(int size) {
|
||||
return new AidGroup[size];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Note: description is not serialized, since it's not localized
|
||||
* and resource identifiers don't make sense to persist.
|
||||
*/
|
||||
static public AidGroup createFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
|
||||
String category = parser.getAttributeValue(null, "category");
|
||||
ArrayList<String> aids = new ArrayList<String>();
|
||||
int eventType = parser.getEventType();
|
||||
int minDepth = parser.getDepth();
|
||||
while (eventType != XmlPullParser.END_DOCUMENT && parser.getDepth() >= minDepth) {
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
String tagName = parser.getName();
|
||||
if (tagName.equals("aid")) {
|
||||
String aid = parser.getAttributeValue(null, "value");
|
||||
if (aid != null) {
|
||||
aids.add(aid);
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Ignorning unexpected tag: " + tagName);
|
||||
}
|
||||
}
|
||||
eventType = parser.next();
|
||||
}
|
||||
if (category != null && aids.size() > 0) {
|
||||
return new AidGroup(aids, category);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void writeAsXml(XmlSerializer out) throws IOException {
|
||||
out.attribute(null, "category", category);
|
||||
for (String aid : aids) {
|
||||
out.startTag(null, "aid");
|
||||
out.attribute(null, "value", aid);
|
||||
out.endTag(null, "aid");
|
||||
}
|
||||
}
|
||||
|
||||
boolean isValidCategory(String category) {
|
||||
return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
|
||||
CardEmulation.CATEGORY_OTHER.equals(category);
|
||||
}
|
||||
}
|
||||
@@ -35,9 +35,12 @@ import android.util.Xml;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
@@ -55,25 +58,20 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
*/
|
||||
final String mDescription;
|
||||
|
||||
/**
|
||||
* Convenience AID list
|
||||
*/
|
||||
final ArrayList<String> mAids;
|
||||
|
||||
/**
|
||||
* Whether this service represents AIDs running on the host CPU
|
||||
*/
|
||||
final boolean mOnHost;
|
||||
|
||||
/**
|
||||
* All AID groups this service handles
|
||||
* Mapping from category to static AID group
|
||||
*/
|
||||
final ArrayList<AidGroup> mAidGroups;
|
||||
final HashMap<String, AidGroup> mStaticAidGroups;
|
||||
|
||||
/**
|
||||
* Convenience hashmap
|
||||
* Mapping from category to dynamic AID group
|
||||
*/
|
||||
final HashMap<String, AidGroup> mCategoryToGroup;
|
||||
final HashMap<String, AidGroup> mDynamicAidGroups;
|
||||
|
||||
/**
|
||||
* Whether this service should only be started when the device is unlocked.
|
||||
@@ -85,27 +83,34 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
*/
|
||||
final int mBannerResourceId;
|
||||
|
||||
/**
|
||||
* The uid of the package the service belongs to
|
||||
*/
|
||||
final int mUid;
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
|
||||
ArrayList<AidGroup> aidGroups, boolean requiresUnlock, int bannerResource) {
|
||||
ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
|
||||
boolean requiresUnlock, int bannerResource, int uid) {
|
||||
this.mService = info;
|
||||
this.mDescription = description;
|
||||
this.mAidGroups = aidGroups;
|
||||
this.mAids = new ArrayList<String>();
|
||||
this.mCategoryToGroup = new HashMap<String, AidGroup>();
|
||||
this.mStaticAidGroups = new HashMap<String, AidGroup>();
|
||||
this.mDynamicAidGroups = 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);
|
||||
for (AidGroup aidGroup : staticAidGroups) {
|
||||
this.mStaticAidGroups.put(aidGroup.category, aidGroup);
|
||||
}
|
||||
for (AidGroup aidGroup : dynamicAidGroups) {
|
||||
this.mDynamicAidGroups.put(aidGroup.category, aidGroup);
|
||||
}
|
||||
this.mBannerResourceId = bannerResource;
|
||||
this.mUid = uid;
|
||||
}
|
||||
|
||||
public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost)
|
||||
throws XmlPullParserException, IOException {
|
||||
public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost) throws
|
||||
XmlPullParserException, IOException {
|
||||
ServiceInfo si = info.serviceInfo;
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
@@ -163,10 +168,10 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
sa.recycle();
|
||||
}
|
||||
|
||||
mAidGroups = new ArrayList<AidGroup>();
|
||||
mCategoryToGroup = new HashMap<String, AidGroup>();
|
||||
mAids = new ArrayList<String>();
|
||||
mStaticAidGroups = new HashMap<String, AidGroup>();
|
||||
mDynamicAidGroups = new HashMap<String, AidGroup>();
|
||||
mOnHost = onHost;
|
||||
|
||||
final int depth = parser.getDepth();
|
||||
AidGroup currentGroup = null;
|
||||
|
||||
@@ -179,14 +184,14 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
final TypedArray groupAttrs = res.obtainAttributes(attrs,
|
||||
com.android.internal.R.styleable.AidGroup);
|
||||
// Get category of AID group
|
||||
String groupDescription = groupAttrs.getString(
|
||||
com.android.internal.R.styleable.AidGroup_description);
|
||||
String groupCategory = groupAttrs.getString(
|
||||
com.android.internal.R.styleable.AidGroup_category);
|
||||
String groupDescription = groupAttrs.getString(
|
||||
com.android.internal.R.styleable.AidGroup_description);
|
||||
if (!CardEmulation.CATEGORY_PAYMENT.equals(groupCategory)) {
|
||||
groupCategory = CardEmulation.CATEGORY_OTHER;
|
||||
}
|
||||
currentGroup = mCategoryToGroup.get(groupCategory);
|
||||
currentGroup = mStaticAidGroups.get(groupCategory);
|
||||
if (currentGroup != null) {
|
||||
if (!CardEmulation.CATEGORY_OTHER.equals(groupCategory)) {
|
||||
Log.e(TAG, "Not allowing multiple aid-groups in the " +
|
||||
@@ -200,9 +205,8 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
} else if (eventType == XmlPullParser.END_TAG && "aid-group".equals(tagName) &&
|
||||
currentGroup != null) {
|
||||
if (currentGroup.aids.size() > 0) {
|
||||
if (!mCategoryToGroup.containsKey(currentGroup.category)) {
|
||||
mAidGroups.add(currentGroup);
|
||||
mCategoryToGroup.put(currentGroup.category, currentGroup);
|
||||
if (!mStaticAidGroups.containsKey(currentGroup.category)) {
|
||||
mStaticAidGroups.put(currentGroup.category, currentGroup);
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Not adding <aid-group> with empty or invalid AIDs");
|
||||
@@ -216,7 +220,6 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
toUpperCase();
|
||||
if (isValidAid(aid) && !currentGroup.aids.contains(aid)) {
|
||||
currentGroup.aids.add(aid);
|
||||
mAids.add(aid);
|
||||
} else {
|
||||
Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
|
||||
}
|
||||
@@ -228,6 +231,8 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
// Set uid
|
||||
mUid = si.applicationInfo.uid;
|
||||
}
|
||||
|
||||
public ComponentName getComponent() {
|
||||
@@ -235,16 +240,58 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
mService.serviceInfo.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a consolidated list of AIDs from the AID groups
|
||||
* registered by this service. Note that if a service has both
|
||||
* a static (manifest-based) AID group for a category and a dynamic
|
||||
* AID group, only the dynamically registered AIDs will be returned
|
||||
* for that category.
|
||||
* @return List of AIDs registered by the service
|
||||
*/
|
||||
public ArrayList<String> getAids() {
|
||||
return mAids;
|
||||
final ArrayList<String> aids = new ArrayList<String>();
|
||||
for (AidGroup group : getAidGroups()) {
|
||||
aids.addAll(group.aids);
|
||||
}
|
||||
return aids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registered AID group for this category.
|
||||
*/
|
||||
public AidGroup getDynamicAidGroupForCategory(String category) {
|
||||
return mDynamicAidGroups.get(category);
|
||||
}
|
||||
|
||||
public boolean removeDynamicAidGroupForCategory(String category) {
|
||||
return (mDynamicAidGroups.remove(category) != null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a consolidated list of AID groups
|
||||
* registered by this service. Note that if a service has both
|
||||
* a static (manifest-based) AID group for a category and a dynamic
|
||||
* AID group, only the dynamically registered AID group will be returned
|
||||
* for that category.
|
||||
* @return List of AIDs registered by the service
|
||||
*/
|
||||
public ArrayList<AidGroup> getAidGroups() {
|
||||
return mAidGroups;
|
||||
final ArrayList<AidGroup> groups = new ArrayList<AidGroup>();
|
||||
for (Map.Entry<String, AidGroup> entry : mDynamicAidGroups.entrySet()) {
|
||||
groups.add(entry.getValue());
|
||||
}
|
||||
for (Map.Entry<String, AidGroup> entry : mStaticAidGroups.entrySet()) {
|
||||
if (!mDynamicAidGroups.containsKey(entry.getKey())) {
|
||||
// Consolidate AID groups - don't return static ones
|
||||
// if a dynamic group exists for the category.
|
||||
groups.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
public boolean hasCategory(String category) {
|
||||
return mCategoryToGroup.containsKey(category);
|
||||
return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
|
||||
}
|
||||
|
||||
public boolean isOnHost() {
|
||||
@@ -259,6 +306,14 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
return mDescription;
|
||||
}
|
||||
|
||||
public int getUid() {
|
||||
return mUid;
|
||||
}
|
||||
|
||||
public void setOrReplaceDynamicAidGroup(AidGroup aidGroup) {
|
||||
mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
|
||||
}
|
||||
|
||||
public CharSequence loadLabel(PackageManager pm) {
|
||||
return mService.loadLabel(pm);
|
||||
}
|
||||
@@ -304,8 +359,12 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
StringBuilder out = new StringBuilder("ApduService: ");
|
||||
out.append(getComponent());
|
||||
out.append(", description: " + mDescription);
|
||||
out.append(", AID Groups: ");
|
||||
for (AidGroup aidGroup : mAidGroups) {
|
||||
out.append(", Static AID Groups: ");
|
||||
for (AidGroup aidGroup : mStaticAidGroups.values()) {
|
||||
out.append(aidGroup.toString());
|
||||
}
|
||||
out.append(", Dynamic AID Groups: ");
|
||||
for (AidGroup aidGroup : mDynamicAidGroups.values()) {
|
||||
out.append(aidGroup.toString());
|
||||
}
|
||||
return out.toString();
|
||||
@@ -336,12 +395,17 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
mService.writeToParcel(dest, flags);
|
||||
dest.writeString(mDescription);
|
||||
dest.writeInt(mOnHost ? 1 : 0);
|
||||
dest.writeInt(mAidGroups.size());
|
||||
if (mAidGroups.size() > 0) {
|
||||
dest.writeTypedList(mAidGroups);
|
||||
dest.writeInt(mStaticAidGroups.size());
|
||||
if (mStaticAidGroups.size() > 0) {
|
||||
dest.writeTypedList(new ArrayList<AidGroup>(mStaticAidGroups.values()));
|
||||
}
|
||||
dest.writeInt(mDynamicAidGroups.size());
|
||||
if (mDynamicAidGroups.size() > 0) {
|
||||
dest.writeTypedList(new ArrayList<AidGroup>(mDynamicAidGroups.values()));
|
||||
}
|
||||
dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
|
||||
dest.writeInt(mBannerResourceId);
|
||||
dest.writeInt(mUid);
|
||||
};
|
||||
|
||||
public static final Parcelable.Creator<ApduServiceInfo> CREATOR =
|
||||
@@ -351,14 +415,21 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
|
||||
String description = source.readString();
|
||||
boolean onHost = (source.readInt() != 0) ? true : false;
|
||||
ArrayList<AidGroup> aidGroups = new ArrayList<AidGroup>();
|
||||
int numGroups = source.readInt();
|
||||
if (numGroups > 0) {
|
||||
source.readTypedList(aidGroups, AidGroup.CREATOR);
|
||||
ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
|
||||
int numStaticGroups = source.readInt();
|
||||
if (numStaticGroups > 0) {
|
||||
source.readTypedList(staticAidGroups, AidGroup.CREATOR);
|
||||
}
|
||||
ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>();
|
||||
int numDynamicGroups = source.readInt();
|
||||
if (numDynamicGroups > 0) {
|
||||
source.readTypedList(dynamicAidGroups, AidGroup.CREATOR);
|
||||
}
|
||||
boolean requiresUnlock = (source.readInt() != 0) ? true : false;
|
||||
int bannerResource = source.readInt();
|
||||
return new ApduServiceInfo(info, onHost, description, aidGroups, requiresUnlock, bannerResource);
|
||||
int uid = source.readInt();
|
||||
return new ApduServiceInfo(info, onHost, description, staticAidGroups,
|
||||
dynamicAidGroups, requiresUnlock, bannerResource, uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -367,76 +438,22 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
}
|
||||
};
|
||||
|
||||
public static class AidGroup implements Parcelable {
|
||||
final ArrayList<String> aids;
|
||||
final String category;
|
||||
final String description;
|
||||
|
||||
AidGroup(ArrayList<String> aids, String category, String description) {
|
||||
this.aids = aids;
|
||||
this.category = category;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
AidGroup(String category, String description) {
|
||||
this.aids = new ArrayList<String>();
|
||||
this.category = category;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
public ArrayList<String> getAids() {
|
||||
return aids;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder out = new StringBuilder("Category: " + category +
|
||||
", description: " + description + ", AIDs:");
|
||||
for (String aid : aids) {
|
||||
out.append(aid);
|
||||
out.append(", ");
|
||||
}
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(category);
|
||||
dest.writeString(description);
|
||||
dest.writeInt(aids.size());
|
||||
if (aids.size() > 0) {
|
||||
dest.writeStringList(aids);
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(" " + getComponent() +
|
||||
" (Description: " + getDescription() + ")");
|
||||
pw.println(" Static AID groups:");
|
||||
for (AidGroup group : mStaticAidGroups.values()) {
|
||||
pw.println(" Category: " + group.category);
|
||||
for (String aid : group.aids) {
|
||||
pw.println(" AID: " + aid);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ApduServiceInfo.AidGroup> CREATOR =
|
||||
new Parcelable.Creator<ApduServiceInfo.AidGroup>() {
|
||||
|
||||
@Override
|
||||
public AidGroup createFromParcel(Parcel source) {
|
||||
String category = source.readString();
|
||||
String description = source.readString();
|
||||
int listSize = source.readInt();
|
||||
ArrayList<String> aidList = new ArrayList<String>();
|
||||
if (listSize > 0) {
|
||||
source.readStringList(aidList);
|
||||
}
|
||||
return new AidGroup(aidList, category, description);
|
||||
pw.println(" Dynamic AID groups:");
|
||||
for (AidGroup group : mDynamicAidGroups.values()) {
|
||||
pw.println(" Category: " + group.category);
|
||||
for (String aid : group.aids) {
|
||||
pw.println(" AID: " + aid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AidGroup[] newArray(int size) {
|
||||
return new AidGroup[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +168,10 @@ public final class CardEmulation {
|
||||
if (manager == null) {
|
||||
// Get card emu service
|
||||
INfcCardEmulation service = adapter.getCardEmulationService();
|
||||
if (service == null) {
|
||||
Log.e(TAG, "This device does not implement the INfcCardEmulation interface.");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
manager = new CardEmulation(context, service);
|
||||
sCardEmus.put(context, manager);
|
||||
}
|
||||
@@ -270,6 +274,109 @@ public final class CardEmulation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a group of AIDs for the specified service.
|
||||
*
|
||||
* <p>If an AID group for that category was previously
|
||||
* registered for this service (either statically
|
||||
* through the manifest, or dynamically by using this API),
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @param aidGroup The group of AIDs to be registered
|
||||
* @return whether the registration was successful.
|
||||
*/
|
||||
public boolean registerAidGroupForService(ComponentName service, AidGroup aidGroup) {
|
||||
try {
|
||||
return sService.registerAidGroupForService(UserHandle.myUserId(), service, aidGroup);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.registerAidGroupForService(UserHandle.myUserId(), service,
|
||||
aidGroup);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the currently registered AID group for the specified
|
||||
* category for a service.
|
||||
*
|
||||
* <p>Note that this will only return AID groups that were dynamically
|
||||
* registered using {@link #registerAidGroupForService(ComponentName, AidGroup)}
|
||||
* method. It will *not* return AID groups that were statically registered
|
||||
* in the manifest.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @param category The category of the AID group to be returned, e.g. {@link #CATEGORY_PAYMENT}
|
||||
* @return The AID group, or null if it couldn't be found
|
||||
*/
|
||||
public AidGroup getAidGroupForService(ComponentName service, String category) {
|
||||
try {
|
||||
return sService.getAidGroupForService(UserHandle.myUserId(), service, category);
|
||||
} catch (RemoteException e) {
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return sService.getAidGroupForService(UserHandle.myUserId(), service, category);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a registered AID group for the specified category for the
|
||||
* service provided.
|
||||
*
|
||||
* <p>Note that this will only remove AID groups that were dynamically
|
||||
* registered using the {@link #registerAidGroupForService(ComponentName, AidGroup)}
|
||||
* 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.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @param category The category of the AID group to be removed, e.g. {@link #CATEGORY_PAYMENT}
|
||||
* @return whether the group was successfully removed.
|
||||
*/
|
||||
public boolean removeAidGroupForService(ComponentName service, String category) {
|
||||
try {
|
||||
return sService.removeAidGroupForService(UserHandle.myUserId(), service, category);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.removeAidGroupForService(UserHandle.myUserId(), service, category);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user