blob: e8d801c525e9381ced96029e9e38ca57f34f9eec [file] [log] [blame]
Martijn Coenena7397882013-07-30 20:07:47 -07001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.nfc.cardemulation;
18
Mathew Inwood57069dc2018-07-31 15:33:20 +010019import android.annotation.UnsupportedAppUsage;
Martijn Coenena7397882013-07-30 20:07:47 -070020import android.content.ComponentName;
Martijn Coenen8abf6802015-04-20 13:44:58 +020021import android.content.Context;
Martijn Coenena7397882013-07-30 20:07:47 -070022import android.content.pm.PackageManager;
23import android.content.pm.ResolveInfo;
24import android.content.pm.ServiceInfo;
25import android.content.pm.PackageManager.NameNotFoundException;
26import android.content.res.Resources;
Martijn Coenen58d20652013-09-05 21:05:53 -070027import android.content.res.Resources.NotFoundException;
Martijn Coenena7397882013-07-30 20:07:47 -070028import android.content.res.TypedArray;
29import android.content.res.XmlResourceParser;
30import android.graphics.drawable.Drawable;
31import android.os.Parcel;
32import android.os.Parcelable;
Martijn Coenen8abf6802015-04-20 13:44:58 +020033import android.os.ResultReceiver;
Martijn Coenena7397882013-07-30 20:07:47 -070034import android.util.AttributeSet;
35import android.util.Log;
36import android.util.Xml;
37
38import org.xmlpull.v1.XmlPullParser;
39import org.xmlpull.v1.XmlPullParserException;
40
Martijn Coenenaa1492d2014-04-11 12:54:22 -070041import java.io.FileDescriptor;
Martijn Coenena7397882013-07-30 20:07:47 -070042import java.io.IOException;
Martijn Coenenaa1492d2014-04-11 12:54:22 -070043import java.io.PrintWriter;
Martijn Coenena7397882013-07-30 20:07:47 -070044import java.util.ArrayList;
45import java.util.HashMap;
Martijn Coenened3a29e2015-01-23 11:29:54 -080046import java.util.List;
Martijn Coenenaa1492d2014-04-11 12:54:22 -070047import java.util.Map;
Martijn Coenena7397882013-07-30 20:07:47 -070048
49/**
50 * @hide
51 */
52public final class ApduServiceInfo implements Parcelable {
53 static final String TAG = "ApduServiceInfo";
54
55 /**
56 * The service that implements this
57 */
Mathew Inwood57069dc2018-07-31 15:33:20 +010058 @UnsupportedAppUsage
Martijn Coenena7397882013-07-30 20:07:47 -070059 final ResolveInfo mService;
60
61 /**
62 * Description of the service
63 */
64 final String mDescription;
65
66 /**
Martijn Coenen38d3bb72013-08-07 20:03:03 -070067 * Whether this service represents AIDs running on the host CPU
Martijn Coenena7397882013-07-30 20:07:47 -070068 */
69 final boolean mOnHost;
70
71 /**
Martijn Coenenaa1492d2014-04-11 12:54:22 -070072 * Mapping from category to static AID group
Martijn Coenena7397882013-07-30 20:07:47 -070073 */
Mathew Inwood57069dc2018-07-31 15:33:20 +010074 @UnsupportedAppUsage
Martijn Coenenaa1492d2014-04-11 12:54:22 -070075 final HashMap<String, AidGroup> mStaticAidGroups;
Martijn Coenena7397882013-07-30 20:07:47 -070076
77 /**
Martijn Coenenaa1492d2014-04-11 12:54:22 -070078 * Mapping from category to dynamic AID group
Martijn Coenena7397882013-07-30 20:07:47 -070079 */
Mathew Inwood57069dc2018-07-31 15:33:20 +010080 @UnsupportedAppUsage
Martijn Coenenaa1492d2014-04-11 12:54:22 -070081 final HashMap<String, AidGroup> mDynamicAidGroups;
Martijn Coenena7397882013-07-30 20:07:47 -070082
83 /**
Martijn Coenenc3f00442013-08-28 19:23:41 -070084 * Whether this service should only be started when the device is unlocked.
85 */
86 final boolean mRequiresDeviceUnlock;
87
88 /**
Martijn Coenen58d20652013-09-05 21:05:53 -070089 * The id of the service banner specified in XML.
90 */
91 final int mBannerResourceId;
92
93 /**
Martijn Coenenaa1492d2014-04-11 12:54:22 -070094 * The uid of the package the service belongs to
95 */
96 final int mUid;
Martijn Coenen8abf6802015-04-20 13:44:58 +020097
98 /**
Martijn Coenen8abf6802015-04-20 13:44:58 +020099 * Settings Activity for this service
100 */
101 final String mSettingsActivityName;
102
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700103 /**
Martijn Coenena7397882013-07-30 20:07:47 -0700104 * @hide
105 */
Mathew Inwood57069dc2018-07-31 15:33:20 +0100106 @UnsupportedAppUsage
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700107 public ApduServiceInfo(ResolveInfo info, boolean onHost, String description,
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700108 ArrayList<AidGroup> staticAidGroups, ArrayList<AidGroup> dynamicAidGroups,
Martijn Coenena2344ea2015-06-05 10:45:50 +0200109 boolean requiresUnlock, int bannerResource, int uid,
Martijn Coenen8abf6802015-04-20 13:44:58 +0200110 String settingsActivityName) {
Martijn Coenena7397882013-07-30 20:07:47 -0700111 this.mService = info;
112 this.mDescription = description;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700113 this.mStaticAidGroups = new HashMap<String, AidGroup>();
114 this.mDynamicAidGroups = new HashMap<String, AidGroup>();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700115 this.mOnHost = onHost;
Martijn Coenenc3f00442013-08-28 19:23:41 -0700116 this.mRequiresDeviceUnlock = requiresUnlock;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700117 for (AidGroup aidGroup : staticAidGroups) {
118 this.mStaticAidGroups.put(aidGroup.category, aidGroup);
119 }
120 for (AidGroup aidGroup : dynamicAidGroups) {
121 this.mDynamicAidGroups.put(aidGroup.category, aidGroup);
Martijn Coenena7397882013-07-30 20:07:47 -0700122 }
Martijn Coenen58d20652013-09-05 21:05:53 -0700123 this.mBannerResourceId = bannerResource;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700124 this.mUid = uid;
Martijn Coenen8abf6802015-04-20 13:44:58 +0200125 this.mSettingsActivityName = settingsActivityName;
Martijn Coenena7397882013-07-30 20:07:47 -0700126 }
127
Mathew Inwood57069dc2018-07-31 15:33:20 +0100128 @UnsupportedAppUsage
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700129 public ApduServiceInfo(PackageManager pm, ResolveInfo info, boolean onHost) throws
130 XmlPullParserException, IOException {
Martijn Coenena7397882013-07-30 20:07:47 -0700131 ServiceInfo si = info.serviceInfo;
Martijn Coenena7397882013-07-30 20:07:47 -0700132 XmlResourceParser parser = null;
133 try {
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700134 if (onHost) {
135 parser = si.loadXmlMetaData(pm, HostApduService.SERVICE_META_DATA);
136 if (parser == null) {
Martijn Coenen51b63222013-09-04 14:49:46 -0700137 throw new XmlPullParserException("No " + HostApduService.SERVICE_META_DATA +
138 " meta-data");
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700139 }
140 } else {
141 parser = si.loadXmlMetaData(pm, OffHostApduService.SERVICE_META_DATA);
142 if (parser == null) {
143 throw new XmlPullParserException("No " + OffHostApduService.SERVICE_META_DATA +
144 " meta-data");
145 }
Martijn Coenena7397882013-07-30 20:07:47 -0700146 }
147
148 int eventType = parser.getEventType();
149 while (eventType != XmlPullParser.START_TAG && eventType != XmlPullParser.END_DOCUMENT) {
150 eventType = parser.next();
151 }
152
153 String tagName = parser.getName();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700154 if (onHost && !"host-apdu-service".equals(tagName)) {
Martijn Coenena7397882013-07-30 20:07:47 -0700155 throw new XmlPullParserException(
156 "Meta-data does not start with <host-apdu-service> tag");
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700157 } else if (!onHost && !"offhost-apdu-service".equals(tagName)) {
158 throw new XmlPullParserException(
159 "Meta-data does not start with <offhost-apdu-service> tag");
Martijn Coenena7397882013-07-30 20:07:47 -0700160 }
161
162 Resources res = pm.getResourcesForApplication(si.applicationInfo);
163 AttributeSet attrs = Xml.asAttributeSet(parser);
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700164 if (onHost) {
165 TypedArray sa = res.obtainAttributes(attrs,
166 com.android.internal.R.styleable.HostApduService);
167 mService = info;
168 mDescription = sa.getString(
169 com.android.internal.R.styleable.HostApduService_description);
Martijn Coenenc3f00442013-08-28 19:23:41 -0700170 mRequiresDeviceUnlock = sa.getBoolean(
171 com.android.internal.R.styleable.HostApduService_requireDeviceUnlock,
172 false);
Martijn Coenen58d20652013-09-05 21:05:53 -0700173 mBannerResourceId = sa.getResourceId(
174 com.android.internal.R.styleable.HostApduService_apduServiceBanner, -1);
Martijn Coenen8abf6802015-04-20 13:44:58 +0200175 mSettingsActivityName = sa.getString(
176 com.android.internal.R.styleable.HostApduService_settingsActivity);
Martijn Coenen58d20652013-09-05 21:05:53 -0700177 sa.recycle();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700178 } else {
179 TypedArray sa = res.obtainAttributes(attrs,
180 com.android.internal.R.styleable.OffHostApduService);
181 mService = info;
182 mDescription = sa.getString(
183 com.android.internal.R.styleable.OffHostApduService_description);
Martijn Coenenc3f00442013-08-28 19:23:41 -0700184 mRequiresDeviceUnlock = false;
Martijn Coenen58d20652013-09-05 21:05:53 -0700185 mBannerResourceId = sa.getResourceId(
Martijn Coeneneed43392013-09-26 11:20:37 -0700186 com.android.internal.R.styleable.OffHostApduService_apduServiceBanner, -1);
Martijn Coenen8abf6802015-04-20 13:44:58 +0200187 mSettingsActivityName = sa.getString(
188 com.android.internal.R.styleable.HostApduService_settingsActivity);
Martijn Coenen58d20652013-09-05 21:05:53 -0700189 sa.recycle();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700190 }
191
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700192 mStaticAidGroups = new HashMap<String, AidGroup>();
193 mDynamicAidGroups = new HashMap<String, AidGroup>();
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700194 mOnHost = onHost;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700195
Martijn Coenena7397882013-07-30 20:07:47 -0700196 final int depth = parser.getDepth();
197 AidGroup currentGroup = null;
198
199 // Parsed values for the current AID group
200 while (((eventType = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth)
201 && eventType != XmlPullParser.END_DOCUMENT) {
202 tagName = parser.getName();
203 if (eventType == XmlPullParser.START_TAG && "aid-group".equals(tagName) &&
204 currentGroup == null) {
205 final TypedArray groupAttrs = res.obtainAttributes(attrs,
206 com.android.internal.R.styleable.AidGroup);
207 // Get category of AID group
Martijn Coenena7397882013-07-30 20:07:47 -0700208 String groupCategory = groupAttrs.getString(
209 com.android.internal.R.styleable.AidGroup_category);
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700210 String groupDescription = groupAttrs.getString(
211 com.android.internal.R.styleable.AidGroup_description);
Martijn Coenen52246082013-08-30 11:14:46 -0700212 if (!CardEmulation.CATEGORY_PAYMENT.equals(groupCategory)) {
213 groupCategory = CardEmulation.CATEGORY_OTHER;
Martijn Coenena7397882013-07-30 20:07:47 -0700214 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700215 currentGroup = mStaticAidGroups.get(groupCategory);
Martijn Coenena7397882013-07-30 20:07:47 -0700216 if (currentGroup != null) {
Martijn Coenen52246082013-08-30 11:14:46 -0700217 if (!CardEmulation.CATEGORY_OTHER.equals(groupCategory)) {
Martijn Coenena7397882013-07-30 20:07:47 -0700218 Log.e(TAG, "Not allowing multiple aid-groups in the " +
219 groupCategory + " category");
220 currentGroup = null;
221 }
222 } else {
223 currentGroup = new AidGroup(groupCategory, groupDescription);
224 }
Martijn Coenen58d20652013-09-05 21:05:53 -0700225 groupAttrs.recycle();
Martijn Coenena7397882013-07-30 20:07:47 -0700226 } else if (eventType == XmlPullParser.END_TAG && "aid-group".equals(tagName) &&
227 currentGroup != null) {
228 if (currentGroup.aids.size() > 0) {
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700229 if (!mStaticAidGroups.containsKey(currentGroup.category)) {
230 mStaticAidGroups.put(currentGroup.category, currentGroup);
Martijn Coenena7397882013-07-30 20:07:47 -0700231 }
232 } else {
233 Log.e(TAG, "Not adding <aid-group> with empty or invalid AIDs");
234 }
235 currentGroup = null;
236 } else if (eventType == XmlPullParser.START_TAG && "aid-filter".equals(tagName) &&
237 currentGroup != null) {
238 final TypedArray a = res.obtainAttributes(attrs,
239 com.android.internal.R.styleable.AidFilter);
Martijn Coenen62c196a2013-08-09 13:43:34 -0700240 String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
241 toUpperCase();
Martijn Coenenb5144112014-07-02 12:44:33 -0700242 if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
Martijn Coenena7397882013-07-30 20:07:47 -0700243 currentGroup.aids.add(aid);
Martijn Coenena7397882013-07-30 20:07:47 -0700244 } else {
245 Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
246 }
Martijn Coenen58d20652013-09-05 21:05:53 -0700247 a.recycle();
Martijn Coenen826a73b2014-08-05 07:51:58 -0700248 } else if (eventType == XmlPullParser.START_TAG &&
249 "aid-prefix-filter".equals(tagName) && currentGroup != null) {
250 final TypedArray a = res.obtainAttributes(attrs,
251 com.android.internal.R.styleable.AidFilter);
252 String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
253 toUpperCase();
254 // Add wildcard char to indicate prefix
Martijn Coenen0985fb62014-09-16 10:09:12 -0700255 aid = aid.concat("*");
Martijn Coenen826a73b2014-08-05 07:51:58 -0700256 if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
257 currentGroup.aids.add(aid);
258 } else {
259 Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
260 }
261 a.recycle();
Love Khannae910e8b2017-05-12 13:53:42 +0530262 } else if (eventType == XmlPullParser.START_TAG &&
263 tagName.equals("aid-suffix-filter") && currentGroup != null) {
264 final TypedArray a = res.obtainAttributes(attrs,
265 com.android.internal.R.styleable.AidFilter);
266 String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
267 toUpperCase();
268 // Add wildcard char to indicate suffix
269 aid = aid.concat("#");
270 if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
271 currentGroup.aids.add(aid);
272 } else {
273 Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
274 }
275 a.recycle();
Martijn Coenena7397882013-07-30 20:07:47 -0700276 }
277 }
278 } catch (NameNotFoundException e) {
279 throw new XmlPullParserException("Unable to create context for: " + si.packageName);
280 } finally {
281 if (parser != null) parser.close();
282 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700283 // Set uid
284 mUid = si.applicationInfo.uid;
Martijn Coenena7397882013-07-30 20:07:47 -0700285 }
286
287 public ComponentName getComponent() {
288 return new ComponentName(mService.serviceInfo.packageName,
289 mService.serviceInfo.name);
290 }
291
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700292 /**
293 * Returns a consolidated list of AIDs from the AID groups
294 * registered by this service. Note that if a service has both
295 * a static (manifest-based) AID group for a category and a dynamic
296 * AID group, only the dynamically registered AIDs will be returned
297 * for that category.
298 * @return List of AIDs registered by the service
299 */
Martijn Coenened3a29e2015-01-23 11:29:54 -0800300 public List<String> getAids() {
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700301 final ArrayList<String> aids = new ArrayList<String>();
302 for (AidGroup group : getAidGroups()) {
303 aids.addAll(group.aids);
304 }
305 return aids;
Martijn Coenena7397882013-07-30 20:07:47 -0700306 }
307
Martijn Coenened3a29e2015-01-23 11:29:54 -0800308 public List<String> getPrefixAids() {
309 final ArrayList<String> prefixAids = new ArrayList<String>();
310 for (AidGroup group : getAidGroups()) {
311 for (String aid : group.aids) {
312 if (aid.endsWith("*")) {
313 prefixAids.add(aid);
314 }
315 }
316 }
317 return prefixAids;
318 }
319
Love Khannae910e8b2017-05-12 13:53:42 +0530320 public List<String> getSubsetAids() {
321 final ArrayList<String> subsetAids = new ArrayList<String>();
322 for (AidGroup group : getAidGroups()) {
323 for (String aid : group.aids) {
324 if (aid.endsWith("#")) {
325 subsetAids.add(aid);
326 }
327 }
328 }
329 return subsetAids;
330 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700331 /**
332 * Returns the registered AID group for this category.
333 */
334 public AidGroup getDynamicAidGroupForCategory(String category) {
335 return mDynamicAidGroups.get(category);
336 }
337
338 public boolean removeDynamicAidGroupForCategory(String category) {
339 return (mDynamicAidGroups.remove(category) != null);
340 }
341
342 /**
343 * Returns a consolidated list of AID groups
344 * registered by this service. Note that if a service has both
345 * a static (manifest-based) AID group for a category and a dynamic
346 * AID group, only the dynamically registered AID group will be returned
347 * for that category.
348 * @return List of AIDs registered by the service
349 */
Martijn Coenena7397882013-07-30 20:07:47 -0700350 public ArrayList<AidGroup> getAidGroups() {
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700351 final ArrayList<AidGroup> groups = new ArrayList<AidGroup>();
352 for (Map.Entry<String, AidGroup> entry : mDynamicAidGroups.entrySet()) {
353 groups.add(entry.getValue());
354 }
355 for (Map.Entry<String, AidGroup> entry : mStaticAidGroups.entrySet()) {
356 if (!mDynamicAidGroups.containsKey(entry.getKey())) {
357 // Consolidate AID groups - don't return static ones
358 // if a dynamic group exists for the category.
359 groups.add(entry.getValue());
360 }
361 }
362 return groups;
Martijn Coenena7397882013-07-30 20:07:47 -0700363 }
364
Martijn Coenen2f6f3a012014-04-25 17:00:21 -0700365 /**
366 * Returns the category to which this service has attributed the AID that is passed in,
367 * or null if we don't know this AID.
368 */
369 public String getCategoryForAid(String aid) {
370 ArrayList<AidGroup> groups = getAidGroups();
371 for (AidGroup group : groups) {
Martijn Coenen5e991a12014-09-16 16:03:28 -0700372 if (group.aids.contains(aid.toUpperCase())) {
Martijn Coenen2f6f3a012014-04-25 17:00:21 -0700373 return group.category;
374 }
375 }
376 return null;
377 }
378
Martijn Coenena7397882013-07-30 20:07:47 -0700379 public boolean hasCategory(String category) {
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700380 return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category));
Martijn Coenena7397882013-07-30 20:07:47 -0700381 }
382
Mathew Inwood57069dc2018-07-31 15:33:20 +0100383 @UnsupportedAppUsage
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700384 public boolean isOnHost() {
385 return mOnHost;
386 }
387
Mathew Inwood57069dc2018-07-31 15:33:20 +0100388 @UnsupportedAppUsage
Martijn Coenenc3f00442013-08-28 19:23:41 -0700389 public boolean requiresUnlock() {
390 return mRequiresDeviceUnlock;
391 }
392
Mathew Inwood57069dc2018-07-31 15:33:20 +0100393 @UnsupportedAppUsage
Martijn Coenenfca357872013-09-18 17:26:18 +0200394 public String getDescription() {
395 return mDescription;
396 }
397
Mathew Inwood57069dc2018-07-31 15:33:20 +0100398 @UnsupportedAppUsage
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700399 public int getUid() {
400 return mUid;
401 }
402
403 public void setOrReplaceDynamicAidGroup(AidGroup aidGroup) {
404 mDynamicAidGroups.put(aidGroup.getCategory(), aidGroup);
405 }
406
Martijn Coenena7397882013-07-30 20:07:47 -0700407 public CharSequence loadLabel(PackageManager pm) {
408 return mService.loadLabel(pm);
409 }
410
Martijn Coenen8abf6802015-04-20 13:44:58 +0200411 public CharSequence loadAppLabel(PackageManager pm) {
412 try {
413 return pm.getApplicationLabel(pm.getApplicationInfo(
414 mService.resolvePackageName, PackageManager.GET_META_DATA));
415 } catch (PackageManager.NameNotFoundException e) {
416 return null;
417 }
418 }
419
Martijn Coenena7397882013-07-30 20:07:47 -0700420 public Drawable loadIcon(PackageManager pm) {
421 return mService.loadIcon(pm);
422 }
423
Mathew Inwood57069dc2018-07-31 15:33:20 +0100424 @UnsupportedAppUsage
Martijn Coenen58d20652013-09-05 21:05:53 -0700425 public Drawable loadBanner(PackageManager pm) {
426 Resources res;
427 try {
428 res = pm.getResourcesForApplication(mService.serviceInfo.packageName);
429 Drawable banner = res.getDrawable(mBannerResourceId);
430 return banner;
431 } catch (NotFoundException e) {
432 Log.e(TAG, "Could not load banner.");
433 return null;
434 } catch (NameNotFoundException e) {
435 Log.e(TAG, "Could not load banner.");
436 return null;
437 }
438 }
Martijn Coenen8abf6802015-04-20 13:44:58 +0200439
Mathew Inwood57069dc2018-07-31 15:33:20 +0100440 @UnsupportedAppUsage
Martijn Coenen8abf6802015-04-20 13:44:58 +0200441 public String getSettingsActivityName() { return mSettingsActivityName; }
Martijn Coenen58d20652013-09-05 21:05:53 -0700442
Martijn Coenena7397882013-07-30 20:07:47 -0700443 @Override
444 public String toString() {
445 StringBuilder out = new StringBuilder("ApduService: ");
446 out.append(getComponent());
447 out.append(", description: " + mDescription);
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700448 out.append(", Static AID Groups: ");
449 for (AidGroup aidGroup : mStaticAidGroups.values()) {
450 out.append(aidGroup.toString());
451 }
452 out.append(", Dynamic AID Groups: ");
453 for (AidGroup aidGroup : mDynamicAidGroups.values()) {
Martijn Coenena7397882013-07-30 20:07:47 -0700454 out.append(aidGroup.toString());
455 }
456 return out.toString();
457 }
458
459 @Override
460 public boolean equals(Object o) {
461 if (this == o) return true;
462 if (!(o instanceof ApduServiceInfo)) return false;
463 ApduServiceInfo thatService = (ApduServiceInfo) o;
464
465 return thatService.getComponent().equals(this.getComponent());
466 }
467
468 @Override
469 public int hashCode() {
470 return getComponent().hashCode();
471 }
472
473
474 @Override
475 public int describeContents() {
476 return 0;
477 }
478
479 @Override
480 public void writeToParcel(Parcel dest, int flags) {
481 mService.writeToParcel(dest, flags);
482 dest.writeString(mDescription);
Martijn Coenen38d3bb72013-08-07 20:03:03 -0700483 dest.writeInt(mOnHost ? 1 : 0);
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700484 dest.writeInt(mStaticAidGroups.size());
485 if (mStaticAidGroups.size() > 0) {
486 dest.writeTypedList(new ArrayList<AidGroup>(mStaticAidGroups.values()));
487 }
488 dest.writeInt(mDynamicAidGroups.size());
489 if (mDynamicAidGroups.size() > 0) {
490 dest.writeTypedList(new ArrayList<AidGroup>(mDynamicAidGroups.values()));
Martijn Coenena7397882013-07-30 20:07:47 -0700491 }
Martijn Coenenc3f00442013-08-28 19:23:41 -0700492 dest.writeInt(mRequiresDeviceUnlock ? 1 : 0);
Martijn Coenen58d20652013-09-05 21:05:53 -0700493 dest.writeInt(mBannerResourceId);
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700494 dest.writeInt(mUid);
Martijn Coenen8abf6802015-04-20 13:44:58 +0200495 dest.writeString(mSettingsActivityName);
Martijn Coenena7397882013-07-30 20:07:47 -0700496 };
497
Mathew Inwood57069dc2018-07-31 15:33:20 +0100498 @UnsupportedAppUsage
Martijn Coenena7397882013-07-30 20:07:47 -0700499 public static final Parcelable.Creator<ApduServiceInfo> CREATOR =
500 new Parcelable.Creator<ApduServiceInfo>() {
501 @Override
502 public ApduServiceInfo createFromParcel(Parcel source) {
503 ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
504 String description = source.readString();
Martijn Coenen5e991a12014-09-16 16:03:28 -0700505 boolean onHost = source.readInt() != 0;
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700506 ArrayList<AidGroup> staticAidGroups = new ArrayList<AidGroup>();
507 int numStaticGroups = source.readInt();
508 if (numStaticGroups > 0) {
509 source.readTypedList(staticAidGroups, AidGroup.CREATOR);
510 }
511 ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>();
512 int numDynamicGroups = source.readInt();
513 if (numDynamicGroups > 0) {
514 source.readTypedList(dynamicAidGroups, AidGroup.CREATOR);
Martijn Coenena7397882013-07-30 20:07:47 -0700515 }
Martijn Coenen5e991a12014-09-16 16:03:28 -0700516 boolean requiresUnlock = source.readInt() != 0;
Martijn Coenen58d20652013-09-05 21:05:53 -0700517 int bannerResource = source.readInt();
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700518 int uid = source.readInt();
Martijn Coenen8abf6802015-04-20 13:44:58 +0200519 String settingsActivityName = source.readString();
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700520 return new ApduServiceInfo(info, onHost, description, staticAidGroups,
Martijn Coenena2344ea2015-06-05 10:45:50 +0200521 dynamicAidGroups, requiresUnlock, bannerResource, uid,
Martijn Coenen8abf6802015-04-20 13:44:58 +0200522 settingsActivityName);
Martijn Coenena7397882013-07-30 20:07:47 -0700523 }
524
525 @Override
526 public ApduServiceInfo[] newArray(int size) {
527 return new ApduServiceInfo[size];
528 }
529 };
530
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700531 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
532 pw.println(" " + getComponent() +
533 " (Description: " + getDescription() + ")");
534 pw.println(" Static AID groups:");
535 for (AidGroup group : mStaticAidGroups.values()) {
536 pw.println(" Category: " + group.category);
537 for (String aid : group.aids) {
538 pw.println(" AID: " + aid);
Martijn Coenena7397882013-07-30 20:07:47 -0700539 }
540 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700541 pw.println(" Dynamic AID groups:");
542 for (AidGroup group : mDynamicAidGroups.values()) {
543 pw.println(" Category: " + group.category);
544 for (String aid : group.aids) {
545 pw.println(" AID: " + aid);
Martijn Coenena7397882013-07-30 20:07:47 -0700546 }
Martijn Coenenaa1492d2014-04-11 12:54:22 -0700547 }
Martijn Coenen8abf6802015-04-20 13:44:58 +0200548 pw.println(" Settings Activity: " + mSettingsActivityName);
Martijn Coenena7397882013-07-30 20:07:47 -0700549 }
550}