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.annotation.Nullable;
21 import android.content.pm.PackageManager;
22 import android.content.pm.PackageManager.Property;
23 import android.content.pm.parsing.ParsingPackage;
24 import android.content.pm.parsing.ParsingPackageUtils;
25 import android.content.pm.parsing.ParsingUtils;
26 import android.content.pm.parsing.result.ParseInput;
27 import android.content.pm.parsing.result.ParseResult;
28 import android.content.res.Resources;
29 import android.content.res.TypedArray;
30 import android.content.res.XmlResourceParser;
31 import android.os.Bundle;
32 import android.text.TextUtils;
33 import android.util.TypedValue;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 
37 /** @hide */
38 class ParsedComponentUtils {
39 
40     @NonNull
41     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
parseComponent( Component component, String tag, ParsingPackage pkg, TypedArray array, boolean useRoundIcon, ParseInput input, int bannerAttr, @Nullable Integer descriptionAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, int roundIconAttr)42     static <Component extends ParsedComponent> ParseResult<Component> parseComponent(
43             Component component, String tag, ParsingPackage pkg, TypedArray array,
44             boolean useRoundIcon, ParseInput input, int bannerAttr,
45             @Nullable Integer descriptionAttr, int iconAttr, int labelAttr, int logoAttr,
46             int nameAttr, int roundIconAttr) {
47         String name = array.getNonConfigurationString(nameAttr, 0);
48         if (TextUtils.isEmpty(name)) {
49             return input.error(tag + " does not specify android:name");
50         }
51 
52         String packageName = pkg.getPackageName();
53         String className = ParsingUtils.buildClassName(packageName, name);
54         if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)) {
55             return input.error(tag + " invalid android:name");
56         }
57 
58         //noinspection ConstantConditions; null check done above with isEmpty
59         component.setName(className);
60         component.setPackageName(packageName);
61 
62         int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0;
63         if (roundIconVal != 0) {
64             component.icon = roundIconVal;
65             component.nonLocalizedLabel = null;
66         } else {
67             int iconVal = array.getResourceId(iconAttr, 0);
68             if (iconVal != 0) {
69                 component.icon = iconVal;
70                 component.nonLocalizedLabel = null;
71             }
72         }
73 
74         int logoVal = array.getResourceId(logoAttr, 0);
75         if (logoVal != 0) {
76             component.logo = logoVal;
77         }
78 
79         int bannerVal = array.getResourceId(bannerAttr, 0);
80         if (bannerVal != 0) {
81             component.banner = bannerVal;
82         }
83 
84         if (descriptionAttr != null) {
85             component.descriptionRes = array.getResourceId(descriptionAttr, 0);
86         }
87 
88         TypedValue v = array.peekValue(labelAttr);
89         if (v != null) {
90             component.labelRes = v.resourceId;
91             if (v.resourceId == 0) {
92                 component.nonLocalizedLabel = v.coerceToString();
93             }
94         }
95 
96         return input.success(component);
97     }
98 
addMetaData(ParsedComponent component, ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input)99     static ParseResult<Bundle> addMetaData(ParsedComponent component, ParsingPackage pkg,
100             Resources resources, XmlResourceParser parser, ParseInput input) {
101         ParseResult<Property> result = ParsingPackageUtils.parseMetaData(pkg, component,
102                 resources, parser, "<meta-data>", input);
103         if (result.isError()) {
104             return input.error(result);
105         }
106         final Property property = result.getResult();
107         if (property != null) {
108             component.metaData = property.toBundle(component.metaData);
109         }
110         return input.success(component.metaData);
111     }
112 
addProperty(ParsedComponent component, ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input)113     static ParseResult<Property> addProperty(ParsedComponent component, ParsingPackage pkg,
114             Resources resources, XmlResourceParser parser, ParseInput input) {
115         ParseResult<Property> result = ParsingPackageUtils.parseMetaData(pkg, component,
116                 resources, parser, "<property>", input);
117         if (result.isError()) {
118             return input.error(result);
119         }
120         final Property property = result.getResult();
121         if (property != null) {
122             component.addProperty(property);
123         }
124         return input.success(property);
125     }
126 }
127