blob: 1d3f9c2e346e8e5ec3426424d7b2b4fe5698cc4d [file] [log] [blame]
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +09001/*
2 * Copyright (C) 2015 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
19import android.content.ComponentName;
20import android.content.pm.PackageManager;
Love Khannaca26b122017-04-10 17:46:53 +053021import android.content.pm.PackageManager.NameNotFoundException;
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +090022import android.content.pm.ResolveInfo;
23import android.content.pm.ServiceInfo;
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +090024import android.content.res.Resources;
25import android.content.res.TypedArray;
26import android.content.res.XmlResourceParser;
27import android.graphics.drawable.Drawable;
28import android.os.Parcel;
29import android.os.Parcelable;
30import android.util.AttributeSet;
31import android.util.Log;
32import android.util.Xml;
33
34import org.xmlpull.v1.XmlPullParser;
35import org.xmlpull.v1.XmlPullParserException;
36
37import java.io.FileDescriptor;
38import java.io.IOException;
39import java.io.PrintWriter;
40
41/**
42 * @hide
43 */
44public final class NfcFServiceInfo implements Parcelable {
45 static final String TAG = "NfcFServiceInfo";
46
Love Khannaf5d6d5c2017-08-01 18:32:59 +053047 private static final String DEFAULT_T3T_PMM = "FFFFFFFFFFFFFFFF";
48
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +090049 /**
50 * The service that implements this
51 */
52 final ResolveInfo mService;
53
54 /**
55 * Description of the service
56 */
57 final String mDescription;
58
59 /**
60 * System Code of the service
61 */
62 final String mSystemCode;
63
64 /**
65 * System Code of the service registered by API
66 */
67 String mDynamicSystemCode;
68
69 /**
70 * NFCID2 of the service
71 */
72 final String mNfcid2;
73
74 /**
75 * NFCID2 of the service registered by API
76 */
77 String mDynamicNfcid2;
78
79 /**
80 * The uid of the package the service belongs to
81 */
82 final int mUid;
83
84 /**
Love Khannaca26b122017-04-10 17:46:53 +053085 * LF_T3T_PMM of the service
86 */
87 final String mT3tPmm;
88
89 /**
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +090090 * @hide
91 */
92 public NfcFServiceInfo(ResolveInfo info, String description,
93 String systemCode, String dynamicSystemCode, String nfcid2, String dynamicNfcid2,
Love Khannaca26b122017-04-10 17:46:53 +053094 int uid, String t3tPmm) {
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +090095 this.mService = info;
96 this.mDescription = description;
97 this.mSystemCode = systemCode;
98 this.mDynamicSystemCode = dynamicSystemCode;
99 this.mNfcid2 = nfcid2;
100 this.mDynamicNfcid2 = dynamicNfcid2;
101 this.mUid = uid;
Love Khannaca26b122017-04-10 17:46:53 +0530102 this.mT3tPmm = t3tPmm;
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900103 }
104
105 public NfcFServiceInfo(PackageManager pm, ResolveInfo info)
106 throws XmlPullParserException, IOException {
107 ServiceInfo si = info.serviceInfo;
108 XmlResourceParser parser = null;
109 try {
110 parser = si.loadXmlMetaData(pm, HostNfcFService.SERVICE_META_DATA);
111 if (parser == null) {
112 throw new XmlPullParserException("No " + HostNfcFService.SERVICE_META_DATA +
113 " meta-data");
114 }
115
116 int eventType = parser.getEventType();
117 while (eventType != XmlPullParser.START_TAG &&
118 eventType != XmlPullParser.END_DOCUMENT) {
119 eventType = parser.next();
120 }
121
122 String tagName = parser.getName();
123 if (!"host-nfcf-service".equals(tagName)) {
124 throw new XmlPullParserException(
125 "Meta-data does not start with <host-nfcf-service> tag");
126 }
127
128 Resources res = pm.getResourcesForApplication(si.applicationInfo);
129 AttributeSet attrs = Xml.asAttributeSet(parser);
130 TypedArray sa = res.obtainAttributes(attrs,
131 com.android.internal.R.styleable.HostNfcFService);
132 mService = info;
133 mDescription = sa.getString(
134 com.android.internal.R.styleable.HostNfcFService_description);
135 mDynamicSystemCode = null;
136 mDynamicNfcid2 = null;
137 sa.recycle();
138
139 String systemCode = null;
140 String nfcid2 = null;
Love Khannaca26b122017-04-10 17:46:53 +0530141 String t3tPmm = null;
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900142 final int depth = parser.getDepth();
143
144 while (((eventType = parser.next()) != XmlPullParser.END_TAG ||
145 parser.getDepth() > depth) && eventType != XmlPullParser.END_DOCUMENT) {
146 tagName = parser.getName();
147 if (eventType == XmlPullParser.START_TAG &&
148 "system-code-filter".equals(tagName) && systemCode == null) {
149 final TypedArray a = res.obtainAttributes(attrs,
150 com.android.internal.R.styleable.SystemCodeFilter);
151 systemCode = a.getString(
152 com.android.internal.R.styleable.SystemCodeFilter_name).toUpperCase();
153 if (!NfcFCardEmulation.isValidSystemCode(systemCode) &&
154 !systemCode.equalsIgnoreCase("NULL")) {
155 Log.e(TAG, "Invalid System Code: " + systemCode);
156 systemCode = null;
157 }
158 a.recycle();
159 } else if (eventType == XmlPullParser.START_TAG &&
160 "nfcid2-filter".equals(tagName) && nfcid2 == null) {
161 final TypedArray a = res.obtainAttributes(attrs,
162 com.android.internal.R.styleable.Nfcid2Filter);
163 nfcid2 = a.getString(
164 com.android.internal.R.styleable.Nfcid2Filter_name).toUpperCase();
165 if (!nfcid2.equalsIgnoreCase("RANDOM") &&
166 !nfcid2.equalsIgnoreCase("NULL") &&
167 !NfcFCardEmulation.isValidNfcid2(nfcid2)) {
168 Log.e(TAG, "Invalid NFCID2: " + nfcid2);
169 nfcid2 = null;
170 }
171 a.recycle();
Love Khannaca26b122017-04-10 17:46:53 +0530172 } else if (eventType == XmlPullParser.START_TAG && tagName.equals("t3tPmm-filter")
173 && t3tPmm == null) {
174 final TypedArray a = res.obtainAttributes(attrs,
175 com.android.internal.R.styleable.T3tPmmFilter);
176 t3tPmm = a.getString(
177 com.android.internal.R.styleable.T3tPmmFilter_name).toUpperCase();
Love Khannaca26b122017-04-10 17:46:53 +0530178 a.recycle();
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900179 }
180 }
181 mSystemCode = (systemCode == null ? "NULL" : systemCode);
182 mNfcid2 = (nfcid2 == null ? "NULL" : nfcid2);
Love Khannaf5d6d5c2017-08-01 18:32:59 +0530183 mT3tPmm = (t3tPmm == null ? DEFAULT_T3T_PMM : t3tPmm);
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900184 } catch (NameNotFoundException e) {
185 throw new XmlPullParserException("Unable to create context for: " + si.packageName);
186 } finally {
187 if (parser != null) parser.close();
188 }
189 // Set uid
190 mUid = si.applicationInfo.uid;
191 }
192
193 public ComponentName getComponent() {
194 return new ComponentName(mService.serviceInfo.packageName,
195 mService.serviceInfo.name);
196 }
197
198 public String getSystemCode() {
199 return (mDynamicSystemCode == null ? mSystemCode : mDynamicSystemCode);
200 }
201
202 public void setOrReplaceDynamicSystemCode(String systemCode) {
203 mDynamicSystemCode = systemCode;
204 }
205
206 public String getNfcid2() {
207 return (mDynamicNfcid2 == null ? mNfcid2 : mDynamicNfcid2);
208 }
209
210 public void setOrReplaceDynamicNfcid2(String nfcid2) {
211 mDynamicNfcid2 = nfcid2;
212 }
213
214 public String getDescription() {
215 return mDescription;
216 }
217
218 public int getUid() {
219 return mUid;
220 }
221
Love Khannaca26b122017-04-10 17:46:53 +0530222 public String getT3tPmm() {
223 return mT3tPmm;
224 }
225
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900226 public CharSequence loadLabel(PackageManager pm) {
227 return mService.loadLabel(pm);
228 }
229
230 public Drawable loadIcon(PackageManager pm) {
231 return mService.loadIcon(pm);
232 }
233
234 @Override
235 public String toString() {
236 StringBuilder out = new StringBuilder("NfcFService: ");
237 out.append(getComponent());
238 out.append(", description: " + mDescription);
239 out.append(", System Code: " + mSystemCode);
240 if (mDynamicSystemCode != null) {
241 out.append(", dynamic System Code: " + mDynamicSystemCode);
242 }
243 out.append(", NFCID2: " + mNfcid2);
244 if (mDynamicNfcid2 != null) {
245 out.append(", dynamic NFCID2: " + mDynamicNfcid2);
246 }
Love Khannaca26b122017-04-10 17:46:53 +0530247 out.append(", T3T PMM:" + mT3tPmm);
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900248 return out.toString();
249 }
250
251 @Override
252 public boolean equals(Object o) {
253 if (this == o) return true;
254 if (!(o instanceof NfcFServiceInfo)) return false;
255 NfcFServiceInfo thatService = (NfcFServiceInfo) o;
256
257 if (!thatService.getComponent().equals(this.getComponent())) return false;
258 if (!thatService.mSystemCode.equalsIgnoreCase(this.mSystemCode)) return false;
259 if (!thatService.mNfcid2.equalsIgnoreCase(this.mNfcid2)) return false;
Love Khannaca26b122017-04-10 17:46:53 +0530260 if (!thatService.mT3tPmm.equalsIgnoreCase(this.mT3tPmm)) return false;
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900261 return true;
262 }
263
264 @Override
265 public int hashCode() {
266 return getComponent().hashCode();
267 }
268
269 @Override
270 public int describeContents() {
271 return 0;
272 }
273
274 @Override
275 public void writeToParcel(Parcel dest, int flags) {
276 mService.writeToParcel(dest, flags);
277 dest.writeString(mDescription);
278 dest.writeString(mSystemCode);
279 dest.writeInt(mDynamicSystemCode != null ? 1 : 0);
280 if (mDynamicSystemCode != null) {
281 dest.writeString(mDynamicSystemCode);
282 }
283 dest.writeString(mNfcid2);
284 dest.writeInt(mDynamicNfcid2 != null ? 1 : 0);
285 if (mDynamicNfcid2 != null) {
286 dest.writeString(mDynamicNfcid2);
287 }
288 dest.writeInt(mUid);
Love Khannaca26b122017-04-10 17:46:53 +0530289 dest.writeString(mT3tPmm);
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900290 };
291
292 public static final Parcelable.Creator<NfcFServiceInfo> CREATOR =
293 new Parcelable.Creator<NfcFServiceInfo>() {
294 @Override
295 public NfcFServiceInfo createFromParcel(Parcel source) {
296 ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
297 String description = source.readString();
298 String systemCode = source.readString();
299 String dynamicSystemCode = null;
300 if (source.readInt() != 0) {
301 dynamicSystemCode = source.readString();
302 }
303 String nfcid2 = source.readString();
304 String dynamicNfcid2 = null;
305 if (source.readInt() != 0) {
306 dynamicNfcid2 = source.readString();
307 }
308 int uid = source.readInt();
Love Khannaca26b122017-04-10 17:46:53 +0530309 String t3tPmm = source.readString();
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900310 NfcFServiceInfo service = new NfcFServiceInfo(info, description,
Love Khannaca26b122017-04-10 17:46:53 +0530311 systemCode, dynamicSystemCode, nfcid2, dynamicNfcid2, uid, t3tPmm);
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900312 return service;
313 }
314
315 @Override
316 public NfcFServiceInfo[] newArray(int size) {
317 return new NfcFServiceInfo[size];
318 }
319 };
320
321 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
322 pw.println(" " + getComponent() +
323 " (Description: " + getDescription() + ")");
324 pw.println(" System Code: " + getSystemCode());
325 pw.println(" NFCID2: " + getNfcid2());
Love Khannaca26b122017-04-10 17:46:53 +0530326 pw.println(" T3tPmm: " + getT3tPmm());
Yoshinobu Itoc52adfe2016-01-22 18:14:18 +0900327 }
328}
329