Merge changes from topic "multi-se-support"
* changes: Add a mechanism to register AIDs to specific off-host SE Add Off-Host Card Emulation Features
This commit is contained in:
@@ -11317,6 +11317,8 @@ package android.content.pm {
|
||||
field public static final java.lang.String FEATURE_NFC = "android.hardware.nfc";
|
||||
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION = "android.hardware.nfc.hce";
|
||||
field public static final java.lang.String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
|
||||
field public static final java.lang.String FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE = "android.hardware.nfc.ese";
|
||||
field public static final java.lang.String FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC = "android.hardware.nfc.uicc";
|
||||
field public static final java.lang.String FEATURE_OPENGLES_EXTENSION_PACK = "android.hardware.opengles.aep";
|
||||
field public static final java.lang.String FEATURE_PC = "android.hardware.type.pc";
|
||||
field public static final java.lang.String FEATURE_PICTURE_IN_PICTURE = "android.software.picture_in_picture";
|
||||
@@ -29165,6 +29167,7 @@ package android.nfc {
|
||||
method public deprecated void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
|
||||
method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
|
||||
method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
|
||||
method public java.util.List<java.lang.String> getSupportedOffHostSecureElements();
|
||||
method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
|
||||
method public boolean invokeBeam(android.app.Activity);
|
||||
method public boolean isEnabled();
|
||||
@@ -29256,8 +29259,10 @@ package android.nfc.cardemulation {
|
||||
method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String);
|
||||
method public boolean registerAidsForService(android.content.ComponentName, java.lang.String, java.util.List<java.lang.String>);
|
||||
method public boolean removeAidsForService(android.content.ComponentName, java.lang.String);
|
||||
method public boolean setOffHostForService(android.content.ComponentName, java.lang.String);
|
||||
method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
|
||||
method public boolean supportsAidPrefixRegistration();
|
||||
method public boolean unsetOffHostForService(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";
|
||||
|
||||
@@ -1912,6 +1912,23 @@ public abstract class PackageManager {
|
||||
@SdkConstant(SdkConstantType.FEATURE)
|
||||
public static final String FEATURE_NFC_HOST_CARD_EMULATION_NFCF = "android.hardware.nfc.hcef";
|
||||
|
||||
/**
|
||||
* Feature for {@link #getSystemAvailableFeatures} and
|
||||
* {@link #hasSystemFeature}: The device supports uicc-
|
||||
* based NFC card emulation.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.FEATURE)
|
||||
public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC =
|
||||
"android.hardware.nfc.uicc";
|
||||
|
||||
/**
|
||||
* Feature for {@link #getSystemAvailableFeatures} and
|
||||
* {@link #hasSystemFeature}: The device supports eSE-
|
||||
* based NFC card emulation.
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.FEATURE)
|
||||
public static final String FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE = "android.hardware.nfc.ese";
|
||||
|
||||
/**
|
||||
* Feature for {@link #getSystemAvailableFeatures} and
|
||||
* {@link #hasSystemFeature}: The device supports any
|
||||
|
||||
@@ -31,6 +31,8 @@ interface INfcCardEmulation
|
||||
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);
|
||||
boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
|
||||
boolean unsetOffHostForService(int userHandle, in ComponentName service);
|
||||
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);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package android.nfc;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.RequiresPermission;
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
@@ -42,7 +43,9 @@ import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents the local NFC adapter.
|
||||
@@ -487,6 +490,35 @@ public final class NfcAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of Secure Elements which support off host card emulation.
|
||||
*
|
||||
* @return List<String> containing secure elements on the device which supports
|
||||
* off host card emulation. eSE for Embedded secure element,
|
||||
* SIM for UICC and so on.
|
||||
*/
|
||||
public @NonNull List<String> getSupportedOffHostSecureElements() {
|
||||
List<String> offHostSE = new ArrayList<String>();
|
||||
IPackageManager pm = ActivityThread.getPackageManager();
|
||||
if (pm == null) {
|
||||
Log.e(TAG, "Cannot get package manager, assuming no off-host CE feature");
|
||||
return offHostSE;
|
||||
}
|
||||
try {
|
||||
if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC, 0)) {
|
||||
offHostSE.add("SIM");
|
||||
}
|
||||
if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE, 0)) {
|
||||
offHostSE.add("eSE");
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Package manager query failed, assuming no off-host CE feature", e);
|
||||
offHostSE.clear();
|
||||
return offHostSE;
|
||||
}
|
||||
return offHostSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the NfcAdapter for application context,
|
||||
* or throws if NFC is not available.
|
||||
|
||||
@@ -18,11 +18,10 @@ package android.nfc.cardemulation;
|
||||
|
||||
import android.annotation.UnsupportedAppUsage;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.content.res.TypedArray;
|
||||
@@ -30,7 +29,6 @@ import android.content.res.XmlResourceParser;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.ResultReceiver;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.Xml;
|
||||
@@ -68,6 +66,18 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
*/
|
||||
final boolean mOnHost;
|
||||
|
||||
/**
|
||||
* Offhost reader name.
|
||||
* eg: SIM, eSE etc
|
||||
*/
|
||||
String mOffHostName;
|
||||
|
||||
/**
|
||||
* Offhost reader name from manifest file.
|
||||
* Used for unsetOffHostSecureElement()
|
||||
*/
|
||||
final String mStaticOffHostName;
|
||||
|
||||
/**
|
||||
* Mapping from category to static AID group
|
||||
*/
|
||||
@@ -104,15 +114,17 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
* @hide
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
|
||||
public ApduServiceInfo(ResolveInfo info, String description,
|
||||
ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
|
||||
boolean requiresUnlock, int bannerResource, int uid,
|
||||
String settingsActivityName) {
|
||||
String settingsActivityName, String offHost, String staticOffHost) {
|
||||
this.mService = info;
|
||||
this.mDescription = description;
|
||||
this.mStaticAidGroups = new HashMap<String, AidGroup>();
|
||||
this.mDynamicAidGroups = new HashMap<String, AidGroup>();
|
||||
this.mOnHost = onHost;
|
||||
this.mOffHostName = offHost;
|
||||
this.mStaticOffHostName = staticOffHost;
|
||||
this.mOnHost = (offHost == null);
|
||||
this.mRequiresDeviceUnlock = requiresUnlock;
|
||||
for (AidGroup aidGroup : staticAidGroups) {
|
||||
this.mStaticAidGroups.put(aidGroup.category, aidGroup);
|
||||
@@ -174,6 +186,8 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
|
||||
mSettingsActivityName = sa.getString(
|
||||
com.android.internal.R.styleable.HostApduService_settingsActivity);
|
||||
mOffHostName = null;
|
||||
mStaticOffHostName = mOffHostName;
|
||||
sa.recycle();
|
||||
} else {
|
||||
TypedArray sa = res.obtainAttributes(attrs,
|
||||
@@ -186,6 +200,16 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
|
||||
mSettingsActivityName = sa.getString(
|
||||
com.android.internal.R.styleable.HostApduService_settingsActivity);
|
||||
mOffHostName = sa.getString(
|
||||
com.android.internal.R.styleable.OffHostApduService_secureElementName);
|
||||
if (mOffHostName != null) {
|
||||
if (mOffHostName.equals("eSE")) {
|
||||
mOffHostName = "eSE1";
|
||||
} else if (mOffHostName.equals("SIM")) {
|
||||
mOffHostName = "SIM1";
|
||||
}
|
||||
}
|
||||
mStaticOffHostName = mOffHostName;
|
||||
sa.recycle();
|
||||
}
|
||||
|
||||
@@ -289,6 +313,10 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
mService.serviceInfo.name);
|
||||
}
|
||||
|
||||
public String getOffHostSecureElement() {
|
||||
return mOffHostName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a consolidated list of AIDs from the AID groups
|
||||
* registered by this service. Note that if a service has both
|
||||
@@ -404,6 +432,20 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
|
||||
}
|
||||
|
||||
@UnsupportedAppUsage
|
||||
public void setOffHostSecureElement(String offHost) {
|
||||
mOffHostName = offHost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the off host Secure Element to statically defined
|
||||
* by the service in the manifest file.
|
||||
*/
|
||||
@UnsupportedAppUsage
|
||||
public void unsetOffHostSecureElement() {
|
||||
mOffHostName = mStaticOffHostName;
|
||||
}
|
||||
|
||||
public CharSequence loadLabel(PackageManager pm) {
|
||||
return mService.loadLabel(pm);
|
||||
}
|
||||
@@ -481,6 +523,8 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
mService.writeToParcel(dest, flags);
|
||||
dest.writeString(mDescription);
|
||||
dest.writeInt(mOnHost ? 1 : 0);
|
||||
dest.writeString(mOffHostName);
|
||||
dest.writeString(mStaticOffHostName);
|
||||
dest.writeInt(mStaticAidGroups.size());
|
||||
if (mStaticAidGroups.size() > 0) {
|
||||
dest.writeTypedList(new ArrayList<AidGroup>(mStaticAidGroups.values()));
|
||||
@@ -503,6 +547,8 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
|
||||
String description = source.readString();
|
||||
boolean onHost = source.readInt() != 0;
|
||||
String offHostName = source.readString();
|
||||
String staticOffHostName = source.readString();
|
||||
ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
|
||||
int numStaticGroups = source.readInt();
|
||||
if (numStaticGroups > 0) {
|
||||
@@ -517,9 +563,9 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
int bannerResource = source.readInt();
|
||||
int uid = source.readInt();
|
||||
String settingsActivityName = source.readString();
|
||||
return new ApduServiceInfo(info, onHost, description, staticAidGroups,
|
||||
return new ApduServiceInfo(info, description, staticAidGroups,
|
||||
dynamicAidGroups, requiresUnlock, bannerResource, uid,
|
||||
settingsActivityName);
|
||||
settingsActivityName, offHostName, staticOffHostName);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -531,6 +577,14 @@ public final class ApduServiceInfo implements Parcelable {
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(" " + getComponent() +
|
||||
" (Description: " + getDescription() + ")");
|
||||
if (mOnHost) {
|
||||
pw.println(" On Host Service");
|
||||
} else {
|
||||
pw.println(" Off-host Service");
|
||||
pw.println(" " + "Current off-host SE" + mOffHostName
|
||||
+ " static off-host: " + mOffHostName);
|
||||
}
|
||||
pw.println(" Static off-host Secure Element:");
|
||||
pw.println(" Static AID groups:");
|
||||
for (AidGroup group : mStaticAidGroups.values()) {
|
||||
pw.println(" Category: " + group.category);
|
||||
|
||||
@@ -27,7 +27,6 @@ import android.content.pm.PackageManager;
|
||||
import android.nfc.INfcCardEmulation;
|
||||
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;
|
||||
@@ -344,6 +343,108 @@ public final class CardEmulation {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsets the off-host Secure Element for the given service.
|
||||
*
|
||||
* <p>Note that this will only remove Secure Element that was dynamically
|
||||
* set using the {@link #setOffHostForService(ComponentName, String)}
|
||||
* and resets it to a value that was statically assigned using manifest.
|
||||
*
|
||||
* <p>Note that you can only unset off-host SE for a service that
|
||||
* 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.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @return whether the registration was successful.
|
||||
*/
|
||||
public boolean unsetOffHostForService(ComponentName service) {
|
||||
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
|
||||
if (adapter == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return sService.unsetOffHostForService(mContext.getUserId(), service);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.unsetOffHostForService(mContext.getUserId(), service);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the off-host Secure Element for the given service.
|
||||
*
|
||||
* <p>If off-host SE was initially set (either statically
|
||||
* through the manifest, or dynamically by using this API),
|
||||
* it will be replaced with this one. All AIDs registered by
|
||||
* this service will be re-routed to this Secure Element if
|
||||
* successful.
|
||||
*
|
||||
* <p>Note that you can only set off-host SE for a service that
|
||||
* 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.
|
||||
*
|
||||
* <p>Registeration will be successful only if the Secure Element
|
||||
* exists on the device.
|
||||
*
|
||||
* @param service The component name of the service
|
||||
* @param offHostSecureElement Secure Element to register the AID to
|
||||
* @return whether the registration was successful.
|
||||
*/
|
||||
public boolean setOffHostForService(ComponentName service, String offHostSecureElement) {
|
||||
boolean validSecureElement = false;
|
||||
|
||||
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
|
||||
if (adapter == null || offHostSecureElement == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
List<String> validSE = adapter.getSupportedOffHostSecureElements();
|
||||
if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE"))
|
||||
|| (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (offHostSecureElement.equals("eSE")) {
|
||||
offHostSecureElement = "eSE1";
|
||||
} else if (offHostSecureElement.equals("SIM")) {
|
||||
offHostSecureElement = "SIM1";
|
||||
}
|
||||
|
||||
try {
|
||||
return sService.setOffHostForService(mContext.getUserId(), service,
|
||||
offHostSecureElement);
|
||||
} catch (RemoteException e) {
|
||||
// Try one more time
|
||||
recoverService();
|
||||
if (sService == null) {
|
||||
Log.e(TAG, "Failed to recover CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return sService.setOffHostForService(mContext.getUserId(), service,
|
||||
offHostSecureElement);
|
||||
} catch (RemoteException ee) {
|
||||
Log.e(TAG, "Failed to reach CardEmulationService.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the currently registered AIDs for the specified
|
||||
* category for a service.
|
||||
|
||||
@@ -3690,6 +3690,8 @@
|
||||
<!-- Component name of an activity that allows the user to modify
|
||||
the settings for this service. -->
|
||||
<attr name="settingsActivity"/>
|
||||
<!-- Secure Element which the AIDs should be routed to -->
|
||||
<attr name="secureElementName"/>
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Specify one or more <code>aid-group</code> elements inside a
|
||||
|
||||
Reference in New Issue
Block a user