diff --git a/api/current.txt b/api/current.txt index 1d2d96b67ae69..22e4dba755e34 100644 --- a/api/current.txt +++ b/api/current.txt @@ -505,6 +505,7 @@ package android { field public static final int duplicateParentState = 16842985; // 0x10100e9 field public static final int duration = 16843160; // 0x1010198 field public static final int durationScaleHint = 16844014; // 0x10104ee + field public static final int dynamicResources = 16844019; // 0x10104f3 field public static final int editTextBackground = 16843602; // 0x1010352 field public static final int editTextColor = 16843601; // 0x1010351 field public static final int editTextPreferenceStyle = 16842898; // 0x1010092 @@ -19752,9 +19753,12 @@ package android.nfc.cardemulation { method public boolean supportsAidPrefixRegistration(); 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 ACTION_REQUEST_SERVICE_RESOURCES = "android.nfc.cardemulation.action.REQUEST_SERVICE_RESOURCES"; field public static final java.lang.String CATEGORY_OTHER = "other"; field public static final java.lang.String CATEGORY_PAYMENT = "payment"; + field public static final java.lang.String EXTRA_BANNER_RES_ID = "android.nfc.cardemulation.extra.BANNER_RES_ID"; field public static final java.lang.String EXTRA_CATEGORY = "category"; + field public static final java.lang.String EXTRA_DESCRIPTION = "android.nfc.cardemulation.extra.DESCRIPTION"; 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 diff --git a/api/system-current.txt b/api/system-current.txt index 17e438c5beaf2..2eae860b71739 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -578,6 +578,7 @@ package android { field public static final int duplicateParentState = 16842985; // 0x10100e9 field public static final int duration = 16843160; // 0x1010198 field public static final int durationScaleHint = 16844014; // 0x10104ee + field public static final int dynamicResources = 16844019; // 0x10104f3 field public static final int editTextBackground = 16843602; // 0x1010352 field public static final int editTextColor = 16843601; // 0x1010351 field public static final int editTextPreferenceStyle = 16842898; // 0x1010092 @@ -21640,9 +21641,12 @@ package android.nfc.cardemulation { method public boolean supportsAidPrefixRegistration(); 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 ACTION_REQUEST_SERVICE_RESOURCES = "android.nfc.cardemulation.action.REQUEST_SERVICE_RESOURCES"; field public static final java.lang.String CATEGORY_OTHER = "other"; field public static final java.lang.String CATEGORY_PAYMENT = "payment"; + field public static final java.lang.String EXTRA_BANNER_RES_ID = "android.nfc.cardemulation.extra.BANNER_RES_ID"; field public static final java.lang.String EXTRA_CATEGORY = "category"; + field public static final java.lang.String EXTRA_DESCRIPTION = "android.nfc.cardemulation.extra.DESCRIPTION"; 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 diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java index f10e530d20308..3d065e3a31c7c 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -17,6 +17,7 @@ package android.nfc.cardemulation; import android.content.ComponentName; +import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; @@ -28,6 +29,7 @@ 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; @@ -88,12 +90,24 @@ public final class ApduServiceInfo implements Parcelable { * The uid of the package the service belongs to */ final int mUid; + + /** + * Whether this service has dynamic resources + */ + final boolean mHasDynamicResources; + + /** + * Settings Activity for this service + */ + final String mSettingsActivityName; + /** * @hide */ public ApduServiceInfo(ResolveInfo info, boolean onHost, String description, ArrayList staticAidGroups, ArrayList dynamicAidGroups, - boolean requiresUnlock, int bannerResource, int uid) { + boolean requiresUnlock, int bannerResource, int uid, boolean hasDynamicResources, + String settingsActivityName) { this.mService = info; this.mDescription = description; this.mStaticAidGroups = new HashMap(); @@ -108,6 +122,8 @@ public final class ApduServiceInfo implements Parcelable { } this.mBannerResourceId = bannerResource; this.mUid = uid; + this.mHasDynamicResources = hasDynamicResources; + this.mSettingsActivityName = settingsActivityName; } public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost) throws @@ -156,6 +172,10 @@ public final class ApduServiceInfo implements Parcelable { false); mBannerResourceId = sa.getResourceId( com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1); + mHasDynamicResources = sa.getBoolean( + com.android.internal.R.styleable.HostApduService_dynamicResources, false); + mSettingsActivityName = sa.getString( + com.android.internal.R.styleable.HostApduService_settingsActivity); sa.recycle(); } else { TypedArray sa = res.obtainAttributes(attrs, @@ -166,6 +186,10 @@ public final class ApduServiceInfo implements Parcelable { mRequiresDeviceUnlock = false; mBannerResourceId = sa.getResourceId( com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1); + mHasDynamicResources = sa.getBoolean( + com.android.internal.R.styleable.OffHostApduService_dynamicResources, false); + mSettingsActivityName = sa.getString( + com.android.internal.R.styleable.HostApduService_settingsActivity); sa.recycle(); } @@ -359,6 +383,15 @@ public final class ApduServiceInfo implements Parcelable { return mService.loadLabel(pm); } + public CharSequence loadAppLabel(PackageManager pm) { + try { + return pm.getApplicationLabel(pm.getApplicationInfo( + mService.resolvePackageName, PackageManager.GET_META_DATA)); + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } + public Drawable loadIcon(PackageManager pm) { return mService.loadIcon(pm); } @@ -377,6 +410,11 @@ public final class ApduServiceInfo implements Parcelable { return null; } } + public boolean hasDynamicResources() { + return mHasDynamicResources; + } + + public String getSettingsActivityName() { return mSettingsActivityName; } @Override public String toString() { @@ -430,6 +468,8 @@ public final class ApduServiceInfo implements Parcelable { dest.writeInt(mRequiresDeviceUnlock ? 1 : 0); dest.writeInt(mBannerResourceId); dest.writeInt(mUid); + dest.writeInt(mHasDynamicResources ? 1 : 0); + dest.writeString(mSettingsActivityName); }; public static final Parcelable.Creator CREATOR = @@ -452,8 +492,11 @@ public final class ApduServiceInfo implements Parcelable { boolean requiresUnlock = source.readInt() != 0; int bannerResource = source.readInt(); int uid = source.readInt(); + boolean dynamicResources = source.readInt() != 0; + String settingsActivityName = source.readString(); return new ApduServiceInfo(info, onHost, description, staticAidGroups, - dynamicAidGroups, requiresUnlock, bannerResource, uid); + dynamicAidGroups, requiresUnlock, bannerResource, uid, dynamicResources, + settingsActivityName); } @Override @@ -479,5 +522,6 @@ public final class ApduServiceInfo implements Parcelable { pw.println(" AID: " + aid); } } + pw.println(" Settings Activity: " + mSettingsActivityName); } } diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 64c2bc2bb9769..b94d4a6911a86 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -89,6 +89,37 @@ public final class CardEmulation { */ public static final String CATEGORY_OTHER = "other"; + /** + * Ordered broadcast that can be sent to your app to + * request a description and banner to be shown in + * Android Settings UI. + * When sent to you, this broadcast will contain the + * {@link #EXTRA_SERVICE_COMPONENT} extra to identify + * the service. + * + * Note that this broadcast will only be sent to your + * app, if a card emulation service in your app has requested + * its resources to be loaded dynamically. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_REQUEST_SERVICE_RESOURCES = + "android.nfc.cardemulation.action.REQUEST_SERVICE_RESOURCES"; + + /** + * The description of the service. Note that this must + * be localized by your app, as the String will be shown + * as is. + */ + public static final String EXTRA_DESCRIPTION = + "android.nfc.cardemulation.extra.DESCRIPTION"; + + /** + * The resource ID of the service banner to be shown + * for this service. + */ + public static final String EXTRA_BANNER_RES_ID = + "android.nfc.cardemulation.extra.BANNER_RES_ID"; + /** * Return value for {@link #getSelectionModeForCategory(String)}. * diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1f529cac7560f..fa5e4ad930443 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -227,6 +227,8 @@ + + diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index ef438ab8487c6..551c0831e312d 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -3191,6 +3191,11 @@ + + + + + + + + +