1 /*
2  * Copyright (C) 2022 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 com.android.internal.pm.pkg.component;
18 
19 import static com.android.internal.pm.pkg.parsing.ParsingUtils.NOT_SET;
20 
21 import android.annotation.NonNull;
22 import android.content.pm.PackageManager;
23 import android.content.pm.PackageManager.Property;
24 import android.content.pm.parsing.result.ParseInput;
25 import android.content.pm.parsing.result.ParseResult;
26 import android.content.res.Resources;
27 import android.content.res.TypedArray;
28 import android.content.res.XmlResourceParser;
29 import android.os.Bundle;
30 import android.text.TextUtils;
31 import android.util.TypedValue;
32 
33 import com.android.internal.annotations.VisibleForTesting;
34 import com.android.internal.pm.pkg.parsing.ParsingPackage;
35 import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
36 import com.android.internal.pm.pkg.parsing.ParsingUtils;
37 
38 /** @hide */
39 class ParsedComponentUtils {
40 
41     @NonNull
42     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
parseComponent( Component component, String tag, ParsingPackage pkg, TypedArray array, boolean useRoundIcon, ParseInput input, int bannerAttr, int descriptionAttr, int iconAttr, int labelAttr, int logoAttr, int nameAttr, int roundIconAttr)43     static <Component extends ParsedComponentImpl> ParseResult<Component> parseComponent(
44             Component component, String tag, ParsingPackage pkg, TypedArray array,
45             boolean useRoundIcon, ParseInput input, int bannerAttr, int descriptionAttr,
46             int iconAttr, int labelAttr, int logoAttr, 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                 .setPackageName(packageName);
61 
62         int roundIconVal = useRoundIcon ? array.getResourceId(roundIconAttr, 0) : 0;
63         if (roundIconVal != 0) {
64             component.setIcon(roundIconVal)
65                     .setNonLocalizedLabel(null);
66         } else {
67             int iconVal = array.getResourceId(iconAttr, 0);
68             if (iconVal != 0) {
69                 component.setIcon(iconVal);
70                 component.setNonLocalizedLabel(null);
71             }
72         }
73 
74         int logoVal = array.getResourceId(logoAttr, 0);
75         if (logoVal != 0) {
76             component.setLogo(logoVal);
77         }
78 
79         int bannerVal = array.getResourceId(bannerAttr, 0);
80         if (bannerVal != 0) {
81             component.setBanner(bannerVal);
82         }
83 
84         if (descriptionAttr != NOT_SET) {
85             component.setDescriptionRes(array.getResourceId(descriptionAttr, 0));
86         }
87 
88         TypedValue v = array.peekValue(labelAttr);
89         if (v != null) {
90             component.setLabelRes(v.resourceId);
91             if (v.resourceId == 0) {
92                 component.setNonLocalizedLabel(v.coerceToString());
93             }
94         }
95 
96         return input.success(component);
97     }
98 
addMetaData(ParsedComponentImpl component, ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input)99     static ParseResult<Bundle> addMetaData(ParsedComponentImpl 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.setMetaData(property.toBundle(component.getMetaData()));
109         }
110         return input.success(component.getMetaData());
111     }
112 
addProperty(ParsedComponentImpl component, ParsingPackage pkg, Resources resources, XmlResourceParser parser, ParseInput input)113     static ParseResult<Property> addProperty(ParsedComponentImpl 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