blob: bda14299019af1ef7434a27e67aa43cac22325dc [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.nfc.cardemulation;
import android.content.ComponentName;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @hide
*/
public final class NfcFServiceInfo implements Parcelable {
static final String TAG = "NfcFServiceInfo";
private static final String DEFAULT_T3T_PMM = "FFFFFFFFFFFFFFFF";
/**
* The service that implements this
*/
final ResolveInfo mService;
/**
* Description of the service
*/
final String mDescription;
/**
* System Code of the service
*/
final String mSystemCode;
/**
* System Code of the service registered by API
*/
String mDynamicSystemCode;
/**
* NFCID2 of the service
*/
final String mNfcid2;
/**
* NFCID2 of the service registered by API
*/
String mDynamicNfcid2;
/**
* The uid of the package the service belongs to
*/
final int mUid;
/**
* LF_T3T_PMM of the service
*/
final String mT3tPmm;
/**
* @hide
*/
public NfcFServiceInfo(ResolveInfo info, String description,
String systemCode, String dynamicSystemCode, String nfcid2, String dynamicNfcid2,
int uid, String t3tPmm) {
this.mService = info;
this.mDescription = description;
this.mSystemCode = systemCode;
this.mDynamicSystemCode = dynamicSystemCode;
this.mNfcid2 = nfcid2;
this.mDynamicNfcid2 = dynamicNfcid2;
this.mUid = uid;
this.mT3tPmm = t3tPmm;
}
public NfcFServiceInfo(PackageManager pm, ResolveInfo info)
throws XmlPullParserException, IOException {
ServiceInfo si = info.serviceInfo;
XmlResourceParser parser = null;
try {
parser = si.loadXmlMetaData(pm, HostNfcFService.SERVICE_META_DATA);
if (parser == null) {
throw new XmlPullParserException("No " + HostNfcFService.SERVICE_META_DATA +
" meta-data");
}
int eventType = parser.getEventType();
while (eventType != XmlPullParser.START_TAG &&
eventType != XmlPullParser.END_DOCUMENT) {
eventType = parser.next();
}
String tagName = parser.getName();
if (!"host-nfcf-service".equals(tagName)) {
throw new XmlPullParserException(
"Meta-data does not start with <host-nfcf-service> tag");
}
Resources res = pm.getResourcesForApplication(si.applicationInfo);
AttributeSet attrs = Xml.asAttributeSet(parser);
TypedArray sa = res.obtainAttributes(attrs,
com.android.internal.R.styleable.HostNfcFService);
mService = info;
mDescription = sa.getString(
com.android.internal.R.styleable.HostNfcFService_description);
mDynamicSystemCode = null;
mDynamicNfcid2 = null;
sa.recycle();
String systemCode = null;
String nfcid2 = null;
String t3tPmm = null;
final int depth = parser.getDepth();
while (((eventType = parser.next()) != XmlPullParser.END_TAG ||
parser.getDepth() > depth) && eventType != XmlPullParser.END_DOCUMENT) {
tagName = parser.getName();
if (eventType == XmlPullParser.START_TAG &&
"system-code-filter".equals(tagName) && systemCode == null) {
final TypedArray a = res.obtainAttributes(attrs,
com.android.internal.R.styleable.SystemCodeFilter);
systemCode = a.getString(
com.android.internal.R.styleable.SystemCodeFilter_name).toUpperCase();
if (!NfcFCardEmulation.isValidSystemCode(systemCode) &&
!systemCode.equalsIgnoreCase("NULL")) {
Log.e(TAG, "Invalid System Code: " + systemCode);
systemCode = null;
}
a.recycle();
} else if (eventType == XmlPullParser.START_TAG &&
"nfcid2-filter".equals(tagName) && nfcid2 == null) {
final TypedArray a = res.obtainAttributes(attrs,
com.android.internal.R.styleable.Nfcid2Filter);
nfcid2 = a.getString(
com.android.internal.R.styleable.Nfcid2Filter_name).toUpperCase();
if (!nfcid2.equalsIgnoreCase("RANDOM") &&
!nfcid2.equalsIgnoreCase("NULL") &&
!NfcFCardEmulation.isValidNfcid2(nfcid2)) {
Log.e(TAG, "Invalid NFCID2: " + nfcid2);
nfcid2 = null;
}
a.recycle();
} else if (eventType == XmlPullParser.START_TAG && tagName.equals("t3tPmm-filter")
&& t3tPmm == null) {
final TypedArray a = res.obtainAttributes(attrs,
com.android.internal.R.styleable.T3tPmmFilter);
t3tPmm = a.getString(
com.android.internal.R.styleable.T3tPmmFilter_name).toUpperCase();
a.recycle();
}
}
mSystemCode = (systemCode == null ? "NULL" : systemCode);
mNfcid2 = (nfcid2 == null ? "NULL" : nfcid2);
mT3tPmm = (t3tPmm == null ? DEFAULT_T3T_PMM : t3tPmm);
} catch (NameNotFoundException e) {
throw new XmlPullParserException("Unable to create context for: " + si.packageName);
} finally {
if (parser != null) parser.close();
}
// Set uid
mUid = si.applicationInfo.uid;
}
public ComponentName getComponent() {
return new ComponentName(mService.serviceInfo.packageName,
mService.serviceInfo.name);
}
public String getSystemCode() {
return (mDynamicSystemCode == null ? mSystemCode : mDynamicSystemCode);
}
public void setOrReplaceDynamicSystemCode(String systemCode) {
mDynamicSystemCode = systemCode;
}
public String getNfcid2() {
return (mDynamicNfcid2 == null ? mNfcid2 : mDynamicNfcid2);
}
public void setOrReplaceDynamicNfcid2(String nfcid2) {
mDynamicNfcid2 = nfcid2;
}
public String getDescription() {
return mDescription;
}
public int getUid() {
return mUid;
}
public String getT3tPmm() {
return mT3tPmm;
}
public CharSequence loadLabel(PackageManager pm) {
return mService.loadLabel(pm);
}
public Drawable loadIcon(PackageManager pm) {
return mService.loadIcon(pm);
}
@Override
public String toString() {
StringBuilder out = new StringBuilder("NfcFService: ");
out.append(getComponent());
out.append(", description: " + mDescription);
out.append(", System Code: " + mSystemCode);
if (mDynamicSystemCode != null) {
out.append(", dynamic System Code: " + mDynamicSystemCode);
}
out.append(", NFCID2: " + mNfcid2);
if (mDynamicNfcid2 != null) {
out.append(", dynamic NFCID2: " + mDynamicNfcid2);
}
out.append(", T3T PMM:" + mT3tPmm);
return out.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof NfcFServiceInfo)) return false;
NfcFServiceInfo thatService = (NfcFServiceInfo) o;
if (!thatService.getComponent().equals(this.getComponent())) return false;
if (!thatService.mSystemCode.equalsIgnoreCase(this.mSystemCode)) return false;
if (!thatService.mNfcid2.equalsIgnoreCase(this.mNfcid2)) return false;
if (!thatService.mT3tPmm.equalsIgnoreCase(this.mT3tPmm)) return false;
return true;
}
@Override
public int hashCode() {
return getComponent().hashCode();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
mService.writeToParcel(dest, flags);
dest.writeString(mDescription);
dest.writeString(mSystemCode);
dest.writeInt(mDynamicSystemCode != null ? 1 : 0);
if (mDynamicSystemCode != null) {
dest.writeString(mDynamicSystemCode);
}
dest.writeString(mNfcid2);
dest.writeInt(mDynamicNfcid2 != null ? 1 : 0);
if (mDynamicNfcid2 != null) {
dest.writeString(mDynamicNfcid2);
}
dest.writeInt(mUid);
dest.writeString(mT3tPmm);
};
public static final @android.annotation.NonNull Parcelable.Creator<NfcFServiceInfo> CREATOR =
new Parcelable.Creator<NfcFServiceInfo>() {
@Override
public NfcFServiceInfo createFromParcel(Parcel source) {
ResolveInfo info = ResolveInfo.CREATOR.createFromParcel(source);
String description = source.readString();
String systemCode = source.readString();
String dynamicSystemCode = null;
if (source.readInt() != 0) {
dynamicSystemCode = source.readString();
}
String nfcid2 = source.readString();
String dynamicNfcid2 = null;
if (source.readInt() != 0) {
dynamicNfcid2 = source.readString();
}
int uid = source.readInt();
String t3tPmm = source.readString();
NfcFServiceInfo service = new NfcFServiceInfo(info, description,
systemCode, dynamicSystemCode, nfcid2, dynamicNfcid2, uid, t3tPmm);
return service;
}
@Override
public NfcFServiceInfo[] newArray(int size) {
return new NfcFServiceInfo[size];
}
};
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println(" " + getComponent() +
" (Description: " + getDescription() + ")");
pw.println(" System Code: " + getSystemCode());
pw.println(" NFCID2: " + getNfcid2());
pw.println(" T3tPmm: " + getT3tPmm());
}
}