1 /*
2  * Copyright (C) 2020 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 
17 package android.content.pm.parsing.component;
18 
19 import android.annotation.NonNull;
20 import android.content.pm.parsing.result.ParseInput;
21 import android.content.pm.parsing.result.ParseResult;
22 import android.content.res.Resources;
23 import android.content.res.TypedArray;
24 import android.content.res.XmlResourceParser;
25 
26 import com.android.internal.R;
27 
28 import org.xmlpull.v1.XmlPullParser;
29 import org.xmlpull.v1.XmlPullParserException;
30 
31 import java.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Collections;
34 import java.util.List;
35 
36 /** @hide */
37 public class ParsedAttributionUtils {
38 
39     @NonNull
parseAttribution(Resources res, XmlResourceParser parser, ParseInput input)40     public static ParseResult<ParsedAttribution> parseAttribution(Resources res,
41             XmlResourceParser parser, ParseInput input)
42             throws IOException, XmlPullParserException {
43         String attributionTag;
44         int label;
45         List<String> inheritFrom = null;
46 
47         TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestAttribution);
48         if (sa == null) {
49             return input.error("<attribution> could not be parsed");
50         }
51 
52         try {
53             attributionTag = sa.getNonConfigurationString(
54                     R.styleable.AndroidManifestAttribution_tag, 0);
55             if (attributionTag == null) {
56                 return input.error("<attribution> does not specify android:tag");
57             }
58             if (attributionTag.length() > ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN) {
59                 return input.error("android:tag is too long. Max length is "
60                         + ParsedAttribution.MAX_ATTRIBUTION_TAG_LEN);
61             }
62 
63             label = sa.getResourceId(R.styleable.AndroidManifestAttribution_label, 0);
64             if (label == Resources.ID_NULL) {
65                 return input.error("<attribution> does not specify android:label");
66             }
67         } finally {
68             sa.recycle();
69         }
70 
71         int type;
72         final int innerDepth = parser.getDepth();
73         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
74                 && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
75             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
76                 continue;
77             }
78 
79             String tagName = parser.getName();
80             if (tagName.equals("inherit-from")) {
81                 sa = res.obtainAttributes(parser,
82                         R.styleable.AndroidManifestAttributionInheritFrom);
83                 if (sa == null) {
84                     return input.error("<inherit-from> could not be parsed");
85                 }
86 
87                 try {
88                     String inheritFromId = sa.getNonConfigurationString(
89                             R.styleable.AndroidManifestAttributionInheritFrom_tag, 0);
90 
91                     if (inheritFrom == null) {
92                         inheritFrom = new ArrayList<>();
93                     }
94                     inheritFrom.add(inheritFromId);
95                 } finally {
96                     sa.recycle();
97                 }
98             } else {
99                 return input.error("Bad element under <attribution>: " + tagName);
100             }
101         }
102 
103         if (inheritFrom == null) {
104             inheritFrom = Collections.emptyList();
105         } else {
106             ((ArrayList) inheritFrom).trimToSize();
107         }
108 
109         return input.success(new ParsedAttribution(attributionTag, label, inheritFrom));
110     }
111 }
112