diff options
author | Jaewan Kim <jaewan@google.com> | 2014-08-02 09:50:04 +0900 |
---|---|---|
committer | Jaewan Kim <jaewan@google.com> | 2014-08-05 16:42:13 +0900 |
commit | c26ffd6d4c714fd7af5cf14a154d0ed52bc0089e (patch) | |
tree | bd1087497d73efa3700c2d24d4488cd0b13d842c /src | |
parent | bd61574966d9bda08f8f82bfee24155fa43a82e2 (diff) | |
download | TV-c26ffd6d4c714fd7af5cf14a154d0ed52bc0089e.tar.gz |
Initial commit of content rating XML parser
Bug: 16113341
Change-Id: I6194a499eae626df77300370df47de6079f36d5e
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/tv/parental/ContentRatingSystem.java | 428 | ||||
-rw-r--r-- | src/com/android/tv/parental/ContentRatingsManager.java | 52 | ||||
-rw-r--r-- | src/com/android/tv/parental/ContentRatingsParser.java | 333 |
3 files changed, 813 insertions, 0 deletions
diff --git a/src/com/android/tv/parental/ContentRatingSystem.java b/src/com/android/tv/parental/ContentRatingSystem.java new file mode 100644 index 00000000..7985adf5 --- /dev/null +++ b/src/com/android/tv/parental/ContentRatingSystem.java @@ -0,0 +1,428 @@ +/* + * Copyright (C) 2014 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 com.android.tv.parental; + +import android.net.Uri; +import android.text.TextUtils; + +import java.util.ArrayList; +import java.util.List; + +public class ContentRatingSystem { + private final static String TAG = "ContentRatingSystem"; + + // Id of this content rating system. It should be unique in an XML file. + private String mId; + + // Domain of this content rating system. It's package name now. + private String mDomain; + + // Display name of this content rating system. (e.g. TV-PG) + private String mDisplayName; + + // Description of this content rating system. + private String mDescription; + + // Country code of this content rating system. + private String mCountry; + + // Ordered list of main content ratings. UX should respect the order. + private List<Rating> mRatings; + + // Ordered list of sub content ratings. UX should respect the order. + private List<SubRating> mSubRatings; + + // List of orders. This describes the automatic lock/unlock relationship between ratings. + // For example, let say we have following order. + // <order> + // <rating id="US_TVPG_Y" /> + // <rating id="US_TVPG_Y7" /> + // </order> + // This means that locking US_TVPG_Y7 automatically locks US_TVPG_Y and + // unlocking US_TVPG_Y automatically unlocks US_TVPG_Y7 from the UX. + // An user can still unlock US_TVPG_Y while US_TVPG_Y7 is locked by manually. + private List<Order> mOrders; + + public String getId(){ + return mId; + } + + public String getDomain() { + return mDomain; + } + + public String getDisplayName(){ + return mDisplayName; + } + + public String getDescription(){ + return mDescription; + } + + public String getCountry(){ + return mCountry; + } + + public List<Rating> getRatings(){ + return mRatings; + } + + public List<SubRating> getSubRatings(){ + return mSubRatings; + } + + public List<Order> getOrders(){ + return mOrders; + } + + private ContentRatingSystem( + String id, String domain, String displayName, String description, String country, + List<Rating> ratings, List<SubRating> subRatings, List<Order> orders) { + mId = id; + mDomain = domain; + mDisplayName = displayName; + mDescription = description; + mCountry = country; + mRatings = ratings; + mSubRatings = subRatings; + mOrders = orders; + } + + public static class Builder { + private String mId; + private String mDomain; + private String mDisplayName; + private String mDescription; + private String mCountry; + private List<Rating.Builder> mRatingBuilders = new ArrayList<Rating.Builder>(); + private List<SubRating.Builder> mSubRatingBuilders = new ArrayList<SubRating.Builder>(); + private List<Order.Builder> mOrderBuilders = new ArrayList<Order.Builder>(); + + public void setId(String id) { + mId = id; + } + + public void setDomain(String domain) { + mDomain = domain; + } + + public void setDisplayName(String displayName) { + mDisplayName = displayName; + } + + public void setDescription(String description) { + mDescription = description; + } + + public void setCountry(String country) { + mCountry = country; + } + + public void addRatingBuilder(Rating.Builder ratingBuilder) { + // To provide easy access to the SubRatings in it, + // Rating has reference to SubRating, not Id of it. + // (Note that Rating/SubRating is ordered list so we cannot use Map) + // To do so, we need to have list of all SubRatings which might not be available + // at this moment. Keep builders here and build it with SubRatings later. + mRatingBuilders.add(ratingBuilder); + } + + public void addSubRatingBuilder(SubRating.Builder subRatingBuilder) { + // SubRatings would be built rather to keep consistency with other fields. + mSubRatingBuilders.add(subRatingBuilder); + } + + public void addOrderBuilder(Order.Builder orderBuilder) { + // To provide easy access to the Ratings in it, + // Order has reference to Rating, not Id of it. + // (Note that Rating/SubRating is ordered list so we cannot use Map) + // To do so, we need to have list of all Rating which might not be available + // at this moment. Keep builders here and build it with Ratings later. + mOrderBuilders.add(orderBuilder); + } + + public ContentRatingSystem build() { + if (TextUtils.isEmpty(mId)) { + throw new IllegalArgumentException("Id cannot be empty"); + } + if (TextUtils.isEmpty(mDomain)) { + throw new IllegalArgumentException("Domain cannot be empty"); + } + + List<SubRating> subRatings = new ArrayList<SubRating>(); + if (mSubRatingBuilders != null) { + for (SubRating.Builder builder : mSubRatingBuilders) { + subRatings.add(builder.build()); + } + } + + if (mRatingBuilders.size() <= 0) { + throw new IllegalArgumentException("Rating isn't available."); + } + List<Rating> ratings = new ArrayList<Rating>(); + if (mRatingBuilders != null) { + // Map string ID to object. + for (Rating.Builder builder : mRatingBuilders) { + ratings.add(builder.build(subRatings)); + } + + // Sanity check. + for (SubRating subRating : subRatings) { + boolean used = false; + for (Rating rating : ratings) { + if (rating.getSubRatings().contains(subRating)) { + used = true; + break; + } + } + if (!used) { + throw new IllegalArgumentException("Subrating " + subRating.getId() + + " isn't used by any rating"); + } + } + } + + List<Order> orders = new ArrayList<Order>(); + if (mOrderBuilders != null) { + for (Order.Builder builder : mOrderBuilders) { + orders.add(builder.build(ratings)); + } + } + + return new ContentRatingSystem(mId, mDomain, mDisplayName, mDescription, mCountry, + ratings, subRatings, orders); + } + } + + public static class Rating { + private String mId; + private String mDisplayName; + private String mDescription; + private Uri mIconUri; + private int mAgeHint; + private List<SubRating> mSubRatings; + + public String getId() { + return mId; + } + + public String getDisplayName() { + return mDisplayName; + } + + public String getDescription() { + return mDescription; + } + + public Uri getIconUri() { + return mIconUri; + } + + public int getAgeHint() { + return mAgeHint; + } + + public List<SubRating> getSubRatings() { + return mSubRatings; + } + + private Rating(String id, String displayName, String description, Uri iconUri, + int ageHint, List<SubRating> subRatings) { + mId = id; + mDisplayName = displayName; + mDescription = description; + mIconUri = iconUri; + mAgeHint = ageHint; + mSubRatings = subRatings; + } + + public static class Builder { + private String mId; + private String mDisplayName; + private String mDescription; + private Uri mIconUri; + private Integer mAgeHint; + private List<String> mSubRatingIds = new ArrayList<String>(); + + public Builder() { + } + + public void setId(String id) { + mId = id; + } + + public void setDisplayName(String displayName) { + mDisplayName = displayName; + } + + public void setDescription(String description) { + mDescription = description; + } + + public void setIconUri(Uri iconUri) { + mIconUri = iconUri; + } + + public void setAgeHint(int ageHint) { + mAgeHint = (mAgeHint == null) ? new Integer(ageHint) : (Integer) ageHint; + } + + public void addSubRatingId(String subRatingId) { + mSubRatingIds.add(subRatingId); + } + + private Rating build(List<SubRating> allDefinedSubRatings) { + if (TextUtils.isEmpty(mId)) { + throw new IllegalArgumentException("A rating should have non-empty id"); + } + if (allDefinedSubRatings == null && mSubRatingIds.size() > 0) { + throw new IllegalArgumentException("Invalid subrating for rating " + + mId); + } + if (mAgeHint == null || mAgeHint < 0) { + throw new IllegalArgumentException("Rating " + mId + " should define " + + "non-negative ageHint"); + } + + List<SubRating> subRatings = new ArrayList<SubRating>(); + for (String subRatingId : mSubRatingIds) { + boolean found = false; + for (SubRating subRating : allDefinedSubRatings) { + if (subRatingId.equals(subRating.getId())) { + found = true; + subRatings.add(subRating); + break; + } + } + if (!found) { + throw new IllegalArgumentException("Unknown subrating Id " + subRatingId + + " in rating " + mId); + } + } + return new Rating( + mId, mDisplayName, mDescription, mIconUri, (int) mAgeHint, subRatings); + } + } + } + + public static class SubRating { + private String mId; + private String mDisplayName; + private String mDescription; + private Uri mIconUri; + + public String getId() { + return mId; + } + + public String getDisplayName() { + return mDisplayName; + } + + public String getDescription() { + return mDescription; + } + + public Uri getIconUri() { + return mIconUri; + } + + private SubRating(String id, String displayName, String description, Uri iconUri) { + mId = id; + mDisplayName = displayName; + mDescription = description; + mIconUri = iconUri; + } + + public static class Builder { + private String mId; + private String mDisplayName; + private String mDescription; + private Uri mIconUri; + + public Builder() { + } + + public void setId(String id) { + mId = id; + } + + public void setDisplayName(String displayName) { + mDisplayName = displayName; + } + + public void setDescription(String description) { + mDescription = description; + } + + public void setIconUri(Uri iconUri) { + mIconUri = iconUri; + } + + private SubRating build() { + if (TextUtils.isEmpty(mId)) { + throw new IllegalArgumentException("A subrating should have non-empty id"); + } + return new SubRating(mId, mDisplayName, mDescription, mIconUri); + } + } + } + + public static class Order { + private List<Rating> mRatingOrder; + + public List<Rating> getRatingOrder() { + return mRatingOrder; + } + + private Order(List<Rating> ratingOrder) { + mRatingOrder = ratingOrder; + } + + public static class Builder { + private final List<String> mRatingIds = new ArrayList<String>(); + + public Builder() { + } + + private Order build(List<Rating> ratings) { + List<Rating> ratingOrder = new ArrayList<Rating>(); + for (String ratingId : mRatingIds) { + boolean found = false; + for (Rating rating : ratings) { + if (ratingId.equals(rating.getId())) { + found = true; + ratingOrder.add(rating); + break; + } + } + + if (!found) { + throw new IllegalArgumentException("Unknown rating " + ratingId + + " in order tag"); + } + } + + return new Order(ratingOrder); + } + + public void addRatingId(String ratingId) { + mRatingIds.add(ratingId); + } + } + } +} diff --git a/src/com/android/tv/parental/ContentRatingsManager.java b/src/com/android/tv/parental/ContentRatingsManager.java new file mode 100644 index 00000000..acc33e51 --- /dev/null +++ b/src/com/android/tv/parental/ContentRatingsManager.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2014 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 com.android.tv.parental; + +import android.content.Context; +import android.media.tv.TvInputManager; +import android.net.Uri; + +import java.util.ArrayList; +import java.util.List; + +public class ContentRatingsManager { + private final List<ContentRatingSystem> mContenRatings = new ArrayList<ContentRatingSystem>(); + + private Context mContext; + + public ContentRatingsManager(Context context) { + mContext = context; + } + + public void update() { + mContenRatings.clear(); + + TvInputManager manager = + (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE); + List<Uri> uris = manager.getTvContentRatingSystemXmls(); + for (Uri uri : uris) { + List<ContentRatingSystem> list = ContentRatingsParser.parse(mContext, uri); + if (list != null) { + mContenRatings.addAll(list); + } + } + } + + public List<ContentRatingSystem> getContentRatingSystems() { + return mContenRatings; + } +} diff --git a/src/com/android/tv/parental/ContentRatingsParser.java b/src/com/android/tv/parental/ContentRatingsParser.java new file mode 100644 index 00000000..b999f938 --- /dev/null +++ b/src/com/android/tv/parental/ContentRatingsParser.java @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2014 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 com.android.tv.parental; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.content.Context; +import android.content.pm.PackageManager; +import android.content.res.XmlResourceParser; +import android.net.Uri; +import android.util.Log; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import com.android.tv.parental.ContentRatingSystem.Rating; +import com.android.tv.parental.ContentRatingSystem.SubRating; +import com.android.tv.parental.ContentRatingSystem.Order; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +public class ContentRatingsParser { + private final static String TAG = "ContentRatingsParser"; + + private final static String TAG_RATING_SYSTEM_DEFINITIONS = "rating-system-definitions"; + private final static String TAG_RATING_SYSTEM_DEFINITION = "rating-system-definition"; + private final static String TAG_SUB_RATING_DEFINITION = "sub-rating-definition"; + private final static String TAG_RATING_DEFINITION = "rating-definition"; + private final static String TAG_SUB_RATING = "sub-rating"; + private final static String TAG_ORDER = "order"; + private final static String TAG_RATING = "rating"; + + private final static String ATTR_ID = "id"; + private final static String ATTR_DISPLAY_NAME = "displayName"; + private final static String ATTR_COUNTRY = "country"; + private final static String ATTR_ICON = "icon"; + private final static String ATTR_DESCRIPTION = "description"; + private final static String ATTR_AGE_HINT = "ageHint"; + + private ContentRatingsParser() { + // Prevent instantiation. + } + + public static List<ContentRatingSystem> parse(Context context, Uri uri) { + List<ContentRatingSystem> ratingSystems = null; + XmlResourceParser parser = null; + try { + if (!uri.getScheme().equals(ContentResolver.SCHEME_ANDROID_RESOURCE)) { + throw new IllegalArgumentException("Invalid URI scheme " + uri); + } + String packageName = uri.getAuthority(); + int resId = (int) ContentUris.parseId(uri); + parser = context.getPackageManager().getXml(packageName, resId, null); + if (parser == null) { + throw new IllegalArgumentException("Cannot get XML with URI " + uri); + } + ratingSystems = parse(parser, packageName); + } catch (Exception e) { + // Catching all exceptions and print which URI is malformed XML with description + // and stack trace here. + // TODO: We may want to print message to stdout. see b/16803331 + Log.w(TAG, "Error parsing XML " + uri, e); + } finally { + if (parser != null) { + parser.close(); + } + } + + return ratingSystems; + } + + private static void assertEquals(int a, int b, String msg) throws XmlPullParserException { + if (a != b) { + throw new XmlPullParserException(msg); + } + } + + private static void assertEquals(String a, String b, String msg) throws XmlPullParserException { + if (!b.equals(a)) { + throw new XmlPullParserException(msg); + } + } + + private static List<ContentRatingSystem> parse(XmlResourceParser parser, String domain) + throws XmlPullParserException, IOException { + // Consume all START_DOCUMENT which can appear more than once. + while (parser.next() == XmlPullParser.START_DOCUMENT); + + int eventType = parser.getEventType(); + assertEquals(eventType, XmlPullParser.START_TAG, "Malformed XML: Not a valid XML file"); + assertEquals(parser.getName(), TAG_RATING_SYSTEM_DEFINITIONS, + "Malformed XML: Should start with tag " + TAG_RATING_SYSTEM_DEFINITIONS); + + List<ContentRatingSystem> ratingSystems = new ArrayList<ContentRatingSystem>(); + while (true) { + eventType = parser.nextTag(); + + switch (eventType) { + case XmlPullParser.START_TAG: + assertEquals(parser.getName(), TAG_RATING_SYSTEM_DEFINITION, + "Malformed XML: Should contains " + + TAG_RATING_SYSTEM_DEFINITION); + ratingSystems.add(parseRatingSystem(parser, domain)); + break; + case XmlPullParser.END_TAG: + assertEquals(parser.getName(), TAG_RATING_SYSTEM_DEFINITIONS, + "Malformed XML: Should end with tag " + + TAG_RATING_SYSTEM_DEFINITIONS); + eventType = parser.next(); + assertEquals(eventType, XmlPullParser.END_DOCUMENT, + "Malformed XML: Should end with tag " + + TAG_RATING_SYSTEM_DEFINITIONS); + return ratingSystems; + default: + throw new XmlPullParserException("Malformed XML: Error in " + + TAG_RATING_SYSTEM_DEFINITIONS); + } + } + } + + private static ContentRatingSystem parseRatingSystem(XmlResourceParser parser, String domain) + throws XmlPullParserException, IOException { + ContentRatingSystem.Builder builder = new ContentRatingSystem.Builder(); + + builder.setDomain(domain); + for (int i = 0; i < parser.getAttributeCount(); i++) { + String attr = parser.getAttributeName(i); + switch (attr) { + case ATTR_ID: + builder.setId(parser.getAttributeValue(i)); + break; + case ATTR_COUNTRY: + builder.setCountry(parser.getAttributeValue(i)); + break; + case ATTR_DISPLAY_NAME: + builder.setDisplayName(parser.getAttributeValue(i)); + break; + case ATTR_DESCRIPTION: + builder.setDisplayName(parser.getAttributeValue(i)); + break; + default: + throw new XmlPullParserException("Malformed XML: Unknown attribute " + attr + + " in " + TAG_RATING_SYSTEM_DEFINITIONS); + } + } + + while (true) { + int eventType = parser.nextTag(); + switch (eventType) { + case XmlPullParser.START_TAG: + String tag = parser.getName(); + switch (tag) { + case TAG_RATING_DEFINITION: + builder.addRatingBuilder(parseRating(parser)); + break; + case TAG_SUB_RATING_DEFINITION: + builder.addSubRatingBuilder(parseSubRating(parser)); + break; + case TAG_ORDER: + builder.addOrderBuilder(parseOrder(parser)); + break; + default: + throw new XmlPullParserException("Malformed XML: Unknown tag " + tag + + " in " + TAG_RATING_SYSTEM_DEFINITION); + } + break; + case XmlPullParser.END_TAG: + assertEquals(parser.getName(), TAG_RATING_SYSTEM_DEFINITION, + "Malformed XML: Tag mismatch for " + TAG_RATING_SYSTEM_DEFINITION); + return builder.build(); + default: + throw new XmlPullParserException("Malformed XML: Tag is expected in " + + TAG_RATING_SYSTEM_DEFINITION); + } + } + } + + private static Rating.Builder parseRating(XmlResourceParser parser) + throws XmlPullParserException, IOException { + Rating.Builder builder = new Rating.Builder(); + + for (int i = 0; i < parser.getAttributeCount(); i++) { + String attr = parser.getAttributeName(i); + switch (attr) { + case ATTR_ID: + builder.setId(parser.getAttributeValue(i)); + break; + case ATTR_DISPLAY_NAME: + builder.setDisplayName(parser.getAttributeValue(i)); + break; + case ATTR_DESCRIPTION: + builder.setDisplayName(parser.getAttributeValue(i)); + break; + case ATTR_ICON: + builder.setIconUri(Uri.parse(parser.getAttributeValue(i))); + break; + case ATTR_AGE_HINT: + int ageHint = -1; + try { + ageHint = Integer.parseInt(parser.getAttributeValue(i)); + } catch (NumberFormatException e) { + } + + if (ageHint < 0) { + throw new XmlPullParserException("Malformed XML: " + ATTR_AGE_HINT + + " should be a non-negative number"); + } + builder.setAgeHint(ageHint); + break; + default: + throw new XmlPullParserException("Malformed XML: Unknown attribute " + attr + + " in " + TAG_RATING_DEFINITION); + } + } + + while (true) { + int eventType = parser.nextTag(); + switch (eventType) { + case XmlPullParser.START_TAG: + assertEquals(parser.getName(), TAG_SUB_RATING, + "Malformed XML: Only " + TAG_SUB_RATING + " is allowed in " + + TAG_RATING_DEFINITION); + if (parser.getAttributeCount() != 1 || + !ATTR_ID.equals(parser.getAttributeName(0))) { + throw new XmlPullParserException("Malformed XML: " + TAG_SUB_RATING + + " should only contain " + ATTR_ID); + } + builder.addSubRatingId(parser.getAttributeValue(0)); + eventType = parser.nextTag(); + if (eventType != XmlPullParser.END_TAG || + !TAG_SUB_RATING.equals(parser.getName())) { + throw new XmlPullParserException("Malformed XML: " + TAG_SUB_RATING + + " has child"); + } + break; + case XmlPullParser.END_TAG: + assertEquals(parser.getName(), TAG_RATING_DEFINITION, + "Malformed XML: Tag mismatch for " + TAG_RATING_DEFINITION); + return builder; + + default: + throw new XmlPullParserException("Malformed XML: Error in " + + TAG_RATING_DEFINITION); + } + } + } + + private static SubRating.Builder parseSubRating(XmlResourceParser parser) + throws XmlPullParserException, IOException { + SubRating.Builder builder = new SubRating.Builder(); + + for (int i = 0; i < parser.getAttributeCount(); i++) { + String attr = parser.getAttributeName(i); + switch (attr) { + case ATTR_ID: + builder.setId(parser.getAttributeValue(i)); + break; + case ATTR_DISPLAY_NAME: + builder.setDisplayName(parser.getAttributeValue(i)); + break; + case ATTR_DESCRIPTION: + builder.setDisplayName(parser.getAttributeValue(i)); + break; + case ATTR_ICON: + builder.setIconUri(Uri.parse(parser.getAttributeValue(i))); + break; + default: + throw new XmlPullParserException("Malformed XML: Unknown attribute " + attr + + " in " + TAG_SUB_RATING_DEFINITION); + } + } + + assertEquals(parser.nextTag(), XmlPullParser.END_TAG, + "Malformed XML: " + TAG_SUB_RATING_DEFINITION + " has child"); + assertEquals(parser.getName(), TAG_SUB_RATING_DEFINITION, + "Malformed XML: " + TAG_SUB_RATING_DEFINITION + " isn't closed"); + + return builder; + } + + private static Order.Builder parseOrder(XmlResourceParser parser) + throws XmlPullParserException, IOException { + Order.Builder builder = new Order.Builder(); + + assertEquals(parser.getAttributeCount(), 0, + "Malformed XML: Attribute isn't allowed in " + TAG_ORDER); + + while (true) { + int eventType = parser.nextTag(); + switch (eventType) { + case XmlPullParser.START_TAG: + assertEquals(parser.getName(), TAG_RATING, + "Malformed XML: Only " + TAG_RATING + " is allowed in " + + TAG_ORDER); + if (parser.getAttributeCount() != 1 || + !ATTR_ID.equals(parser.getAttributeName(0))) { + throw new XmlPullParserException("Malformed XML: " + TAG_ORDER + + " should only contain " + ATTR_ID); + } + builder.addRatingId(parser.getAttributeValue(0)); + eventType = parser.nextTag(); + if (eventType != XmlPullParser.END_TAG || + !TAG_RATING.equals(parser.getName())) { + throw new XmlPullParserException("Malformed XML: " + TAG_RATING + + " has child"); + } + break; + case XmlPullParser.END_TAG: + assertEquals(parser.getName(), TAG_ORDER, + "Malformed XML: Tag mismatch for " + TAG_ORDER); + return builder; + default: + throw new XmlPullParserException("Malformed XML: Error in " + TAG_ORDER); + } + } + } +} |