Home | History | Annotate | Download | only in cardemulation
      1 package android.nfc.cardemulation;
      2 
      3 import java.io.IOException;
      4 import java.util.ArrayList;
      5 import java.util.List;
      6 
      7 import org.xmlpull.v1.XmlPullParser;
      8 import org.xmlpull.v1.XmlPullParserException;
      9 import org.xmlpull.v1.XmlSerializer;
     10 
     11 import android.os.Parcel;
     12 import android.os.Parcelable;
     13 import android.util.Log;
     14 
     15 /**
     16  * The AidGroup class represents a group of Application Identifiers (AIDs).
     17  *
     18  * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class
     19  * requires the AIDs to be input as a hexadecimal string, with an even amount of
     20  * hexadecimal characters, e.g. "F014811481".
     21  *
     22  * @hide
     23  */
     24 public final class AidGroup implements Parcelable {
     25     /**
     26      * The maximum number of AIDs that can be present in any one group.
     27      */
     28     public static final int MAX_NUM_AIDS = 256;
     29 
     30     static final String TAG = "AidGroup";
     31 
     32     final List<String> aids;
     33     final String category;
     34     final String description;
     35 
     36     /**
     37      * Creates a new AidGroup object.
     38      *
     39      * @param aids The list of AIDs present in the group
     40      * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT}
     41      */
     42     public AidGroup(List<String> aids, String category) {
     43         if (aids == null || aids.size() == 0) {
     44             throw new IllegalArgumentException("No AIDS in AID group.");
     45         }
     46         if (aids.size() > MAX_NUM_AIDS) {
     47             throw new IllegalArgumentException("Too many AIDs in AID group.");
     48         }
     49         for (String aid : aids) {
     50             if (!CardEmulation.isValidAid(aid)) {
     51                 throw new IllegalArgumentException("AID " + aid + " is not a valid AID.");
     52             }
     53         }
     54         if (isValidCategory(category)) {
     55             this.category = category;
     56         } else {
     57             this.category = CardEmulation.CATEGORY_OTHER;
     58         }
     59         this.aids = new ArrayList<String>(aids.size());
     60         for (String aid : aids) {
     61             this.aids.add(aid.toUpperCase());
     62         }
     63         this.description = null;
     64     }
     65 
     66     AidGroup(String category, String description) {
     67         this.aids = new ArrayList<String>();
     68         this.category = category;
     69         this.description = description;
     70     }
     71 
     72     /**
     73      * @return the category of this AID group
     74      */
     75     public String getCategory() {
     76         return category;
     77     }
     78 
     79     /**
     80      * @return the list of AIDs in this group
     81      */
     82     public List<String> getAids() {
     83         return aids;
     84     }
     85 
     86     @Override
     87     public String toString() {
     88         StringBuilder out = new StringBuilder("Category: " + category +
     89                   ", AIDs:");
     90         for (String aid : aids) {
     91             out.append(aid);
     92             out.append(", ");
     93         }
     94         return out.toString();
     95     }
     96 
     97     @Override
     98     public int describeContents() {
     99         return 0;
    100     }
    101 
    102     @Override
    103     public void writeToParcel(Parcel dest, int flags) {
    104         dest.writeString(category);
    105         dest.writeInt(aids.size());
    106         if (aids.size() > 0) {
    107             dest.writeStringList(aids);
    108         }
    109     }
    110 
    111     public static final Parcelable.Creator<AidGroup> CREATOR =
    112             new Parcelable.Creator<AidGroup>() {
    113 
    114         @Override
    115         public AidGroup createFromParcel(Parcel source) {
    116             String category = source.readString();
    117             int listSize = source.readInt();
    118             ArrayList<String> aidList = new ArrayList<String>();
    119             if (listSize > 0) {
    120                 source.readStringList(aidList);
    121             }
    122             return new AidGroup(aidList, category);
    123         }
    124 
    125         @Override
    126         public AidGroup[] newArray(int size) {
    127             return new AidGroup[size];
    128         }
    129     };
    130 
    131     static public AidGroup createFromXml(XmlPullParser parser) throws XmlPullParserException, IOException {
    132         String category = null;
    133         ArrayList<String> aids = new ArrayList<String>();
    134         AidGroup group = null;
    135         boolean inGroup = false;
    136 
    137         int eventType = parser.getEventType();
    138         int minDepth = parser.getDepth();
    139         while (eventType != XmlPullParser.END_DOCUMENT && parser.getDepth() >= minDepth) {
    140             String tagName = parser.getName();
    141             if (eventType == XmlPullParser.START_TAG) {
    142                 if (tagName.equals("aid")) {
    143                     if (inGroup) {
    144                         String aid = parser.getAttributeValue(null, "value");
    145                         if (aid != null) {
    146                             aids.add(aid.toUpperCase());
    147                         }
    148                     } else {
    149                         Log.d(TAG, "Ignoring <aid> tag while not in group");
    150                     }
    151                 } else if (tagName.equals("aid-group")) {
    152                     category = parser.getAttributeValue(null, "category");
    153                     if (category == null) {
    154                         Log.e(TAG, "<aid-group> tag without valid category");
    155                         return null;
    156                     }
    157                     inGroup = true;
    158                 } else {
    159                     Log.d(TAG, "Ignoring unexpected tag: " + tagName);
    160                 }
    161             } else if (eventType == XmlPullParser.END_TAG) {
    162                 if (tagName.equals("aid-group") && inGroup && aids.size() > 0) {
    163                     group = new AidGroup(aids, category);
    164                     break;
    165                 }
    166             }
    167             eventType = parser.next();
    168         }
    169         return group;
    170     }
    171 
    172     public void writeAsXml(XmlSerializer out) throws IOException {
    173         out.startTag(null, "aid-group");
    174         out.attribute(null, "category", category);
    175         for (String aid : aids) {
    176             out.startTag(null, "aid");
    177             out.attribute(null, "value", aid);
    178             out.endTag(null, "aid");
    179         }
    180         out.endTag(null, "aid-group");
    181     }
    182 
    183     static boolean isValidCategory(String category) {
    184         return CardEmulation.CATEGORY_PAYMENT.equals(category) ||
    185                 CardEmulation.CATEGORY_OTHER.equals(category);
    186     }
    187 }
    188