Add NFC APIs for dynamic resources.
For new Tap & Pay settings UX.
Change-Id: I55ff4e4d4a4b6d26c3c88d96431c4f14d0963323
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index f10e530..3d065e3 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.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 @@
* 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<AidGroup> staticAidGroups, ArrayList<AidGroup> 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<String, AidGroup>();
@@ -108,6 +122,8 @@
}
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 @@
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 @@
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 @@
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 @@
return null;
}
}
+ public boolean hasDynamicResources() {
+ return mHasDynamicResources;
+ }
+
+ public String getSettingsActivityName() { return mSettingsActivityName; }
@Override
public String toString() {
@@ -430,6 +468,8 @@
dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
dest.writeInt(mBannerResourceId);
dest.writeInt(mUid);
+ dest.writeInt(mHasDynamicResources ? 1 : 0);
+ dest.writeString(mSettingsActivityName);
};
public static final Parcelable.Creator<ApduServiceInfo> CREATOR =
@@ -452,8 +492,11 @@
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 @@
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 64c2bc2..b94d4a6 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -90,6 +90,37 @@
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)}.
*
* <p>In this mode, the user has set a default service for this
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1f529ca..fa5e4ad 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -227,6 +227,8 @@
<protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
<protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+
+ <protected-broadcast android:name="android.nfc.cardemulation.action.REQUEST_SERVICE_RESOURCES" />
<protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
<protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index ef438ab..551c083 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3191,6 +3191,11 @@
<!-- A drawable that can be rendered in Android's system UI for representing
the service. -->
<attr name="apduServiceBanner" format="reference"/>
+ <!-- Allows the app to update the description and service banner at run-time -->
+ <attr name="dynamicResources" format="boolean"/>
+ <!-- Component name of an activity that allows the user to modify
+ the settings for this service. -->
+ <attr name="settingsActivity"/>
</declare-styleable>
<!-- Use <code>offhost-apdu-service</code> as the root tag of the XML resource that
@@ -3204,6 +3209,11 @@
<!-- A drawable that can be rendered in Android's system UI for representing
the service. -->
<attr name="apduServiceBanner"/>
+ <!-- Allows the app to update the description and service banner at run-time -->
+ <attr name="dynamicResources"/>
+ <!-- Component name of an activity that allows the user to modify
+ the settings for this service. -->
+ <attr name="settingsActivity"/>
</declare-styleable>
<!-- Specify one or more <code>aid-group</code> elements inside a
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index c157d4c..7252584 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2672,4 +2672,6 @@
<public type="attr" name="rightIndents" />
<public type="attr" name="showForAllUsers" />
+ <!-- NFC CardEmulation: dynamically load service resources -->
+ <public type="attr" name="dynamicResources" />
</resources>