AidGroup.java revision 1bfc3d624925c2b6e0928e26cf0660aee0a05ddf
1aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenpackage android.nfc.cardemulation;
2aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
3aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenimport java.io.IOException;
4aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenimport java.util.ArrayList;
5df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenenimport java.util.List;
6aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
7aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenimport org.xmlpull.v1.XmlPullParser;
8aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenimport org.xmlpull.v1.XmlPullParserException;
9aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenimport org.xmlpull.v1.XmlSerializer;
10aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
11aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenimport android.os.Parcel;
12aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenimport android.os.Parcelable;
13aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenimport android.util.Log;
14aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
15aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen/**
162f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * The AidGroup class represents a group of Application Identifiers (AIDs).
172f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen *
182f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <p>An instance of this object can be used with
191bfc3d624925c2b6e0928e26cf0660aee0a05ddfMartijn Coenen * {@link CardEmulation#registerAidsForService(android.content.ComponentName, String, java.util.List)}
202f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * to tell the OS which AIDs are handled by your HCE- or SE-based service.
212f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen *
222f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class
232f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * requires the AIDs to be input as a hexadecimal string, with an even amount of
242f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen * hexadecimal characters, e.g. "F014811481".
25df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen *
26df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen * @hide
27aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen */
28aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenenpublic final class AidGroup implements Parcelable {
29aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    /**
30aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * The maximum number of AIDs that can be present in any one group.
31aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     */
32aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    public static final int MAX_NUM_AIDS = 256;
33aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
34aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    static final String TAG = "AidGroup";
35aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
36df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen    final List<String> aids;
37aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    final String category;
38aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    final String description;
39aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
40aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    /**
41aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * Creates a new AidGroup object.
42aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     *
43aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * @param aids The list of AIDs present in the group
442f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen     * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
45aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     */
46df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen    public AidGroup(List<String> aids, String category) {
47aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        if (aids == null || aids.size() == 0) {
48aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            throw new IllegalArgumentException("No AIDS in AID group.");
49aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
50aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        if (aids.size() > MAX_NUM_AIDS) {
51aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            throw new IllegalArgumentException("Too many AIDs in AID group.");
52aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
531bfc3d624925c2b6e0928e26cf0660aee0a05ddfMartijn Coenen        for (String aid : aids) {
541bfc3d624925c2b6e0928e26cf0660aee0a05ddfMartijn Coenen            if (!ApduServiceInfo.isValidAid(aid)) {
551bfc3d624925c2b6e0928e26cf0660aee0a05ddfMartijn Coenen                throw new IllegalArgumentException("AID " + aid + " is not a valid AID.");
561bfc3d624925c2b6e0928e26cf0660aee0a05ddfMartijn Coenen            }
571bfc3d624925c2b6e0928e26cf0660aee0a05ddfMartijn Coenen        }
582f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        if (isValidCategory(category)) {
592f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            this.category = category;
602f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen        } else {
612f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen            this.category = CardEmulation.CATEGORY_OTHER;
62aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
63aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        this.aids = aids;
64aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        this.description = null;
65aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
66aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
67aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    AidGroup(String category, String description) {
68aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        this.aids = new ArrayList<String>();
69aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        this.category = category;
70aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        this.description = description;
71aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
72aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
73aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    /**
74aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * @return the category of this AID group
75aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     */
76aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    public String getCategory() {
77aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        return category;
78aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
79aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
80aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    /**
81aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     * @return the list of  AIDs in this group
82aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen     */
83df48db3c7cab1e39ffe16738c070644c1ef66782Martijn Coenen    public List<String> getAids() {
84aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        return aids;
85aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
86aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
87aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    @Override
88aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    public String toString() {
89aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        StringBuilder out = new StringBuilder("Category: " + category +
90aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                  ", AIDs:");
91aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        for (String aid : aids) {
92aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            out.append(aid);
93aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            out.append(", ");
94aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
95aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        return out.toString();
96aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
97aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
98aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    @Override
99aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    public int describeContents() {
100aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        return 0;
101aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
102aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
103aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    @Override
104aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    public void writeToParcel(Parcel dest, int flags) {
105aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        dest.writeString(category);
106aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        dest.writeInt(aids.size());
107aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        if (aids.size() > 0) {
108aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            dest.writeStringList(aids);
109aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
110aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
111aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
112aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    public static final Parcelable.Creator<AidGroup> CREATOR =
113aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            new Parcelable.Creator<AidGroup>() {
114aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
115aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        @Override
116aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        public AidGroup createFromParcel(Parcel source) {
117aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            String category = source.readString();
118aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            int listSize = source.readInt();
119aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            ArrayList<String> aidList = new ArrayList<String>();
120aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            if (listSize > 0) {
121aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                source.readStringList(aidList);
122aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
123aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            return new AidGroup(aidList, category);
124aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
125aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
126aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        @Override
127aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        public AidGroup[] newArray(int size) {
128aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            return new AidGroup[size];
129aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
130aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    };
131aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
132aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    static public AidGroup createFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
133aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        String category = parser.getAttributeValue(null, "category");
134aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        ArrayList<String> aids = new ArrayList<String>();
135aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        int eventType = parser.getEventType();
136aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        int minDepth = parser.getDepth();
137aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        while (eventType != XmlPullParser.END_DOCUMENT && parser.getDepth() >= minDepth) {
138aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            if (eventType == XmlPullParser.START_TAG) {
139aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                String tagName = parser.getName();
140aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                if (tagName.equals("aid")) {
141aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                    String aid = parser.getAttributeValue(null, "value");
142aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                    if (aid != null) {
143aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                        aids.add(aid);
144aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                    }
145aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                } else {
146aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                    Log.d(TAG, "Ignorning unexpected tag: " + tagName);
147aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                }
148aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            }
149aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            eventType = parser.next();
150aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
151aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        if (category != null && aids.size() > 0) {
152aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            return new AidGroup(aids, category);
153aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        } else {
154aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            return null;
155aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
156aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
157aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
158aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    public void writeAsXml(XmlSerializer out) throws IOException {
159aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        out.attribute(null, "category", category);
160aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        for (String aid : aids) {
161aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            out.startTag(null, "aid");
162aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            out.attribute(null, "value", aid);
163aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen            out.endTag(null, "aid");
164aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        }
165aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
166aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen
1672f6f3a0181b008f58b18804b749d5ddf1ba73bc8Martijn Coenen    static boolean isValidCategory(String category) {
168aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen        return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
169aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen                CardEmulation.CATEGORY_OTHER.equals(category);
170aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen    }
171aa1492d1d8c5f80e074faacb83905bd07487975dMartijn Coenen}
172