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.server.appwidget;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.appwidget.AppWidgetProviderInfo;
22 import android.content.ComponentName;
23 import android.os.Build;
24 import android.text.TextUtils;
25 import android.util.SizeF;
26 import android.util.Slog;
27 
28 import com.android.modules.utils.TypedXmlPullParser;
29 import com.android.modules.utils.TypedXmlSerializer;
30 
31 import java.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.List;
35 import java.util.Objects;
36 import java.util.stream.Collectors;
37 
38 /**
39  * @hide
40  */
41 public class AppWidgetXmlUtil {
42 
43     private static final String TAG = "AppWidgetXmlUtil";
44 
45     private static final String ATTR_MIN_WIDTH = "min_width";
46     private static final String ATTR_MIN_HEIGHT = "min_height";
47     private static final String ATTR_MIN_RESIZE_WIDTH = "min_resize_width";
48     private static final String ATTR_MIN_RESIZE_HEIGHT = "min_resize_height";
49     private static final String ATTR_MAX_RESIZE_WIDTH = "max_resize_width";
50     private static final String ATTR_MAX_RESIZE_HEIGHT = "max_resize_height";
51     private static final String ATTR_TARGET_CELL_WIDTH = "target_cell_width";
52     private static final String ATTR_TARGET_CELL_HEIGHT = "target_cell_height";
53     private static final String ATTR_UPDATE_PERIOD_MILLIS = "update_period_millis";
54     private static final String ATTR_INITIAL_LAYOUT = "initial_layout";
55     private static final String ATTR_INITIAL_KEYGUARD_LAYOUT = "initial_keyguard_layout";
56     private static final String ATTR_CONFIGURE = "configure";
57     private static final String ATTR_LABEL = "label";
58     private static final String ATTR_ICON = "icon";
59     private static final String ATTR_PREVIEW_IMAGE = "preview_image";
60     private static final String ATTR_PREVIEW_LAYOUT = "preview_layout";
61     private static final String ATTR_AUTO_ADVANCED_VIEW_ID = "auto_advance_view_id";
62     private static final String ATTR_RESIZE_MODE = "resize_mode";
63     private static final String ATTR_WIDGET_CATEGORY = "widget_category";
64     private static final String ATTR_WIDGET_FEATURES = "widget_features";
65     private static final String ATTR_DESCRIPTION_RES = "description_res";
66     private static final String ATTR_PROVIDER_INHERITANCE = "provider_inheritance";
67     private static final String ATTR_OS_FINGERPRINT = "os_fingerprint";
68     private static final String SIZE_SEPARATOR = ",";
69 
70     /**
71      * @hide
72      */
writeAppWidgetProviderInfoLocked(@onNull final TypedXmlSerializer out, @NonNull final AppWidgetProviderInfo info)73     public static void writeAppWidgetProviderInfoLocked(@NonNull final TypedXmlSerializer out,
74             @NonNull final AppWidgetProviderInfo info) throws IOException {
75         Objects.requireNonNull(out);
76         Objects.requireNonNull(info);
77         out.attributeInt(null, ATTR_MIN_WIDTH, info.minWidth);
78         out.attributeInt(null, ATTR_MIN_HEIGHT, info.minHeight);
79         out.attributeInt(null, ATTR_MIN_RESIZE_WIDTH, info.minResizeWidth);
80         out.attributeInt(null, ATTR_MIN_RESIZE_HEIGHT, info.minResizeHeight);
81         out.attributeInt(null, ATTR_MAX_RESIZE_WIDTH, info.maxResizeWidth);
82         out.attributeInt(null, ATTR_MAX_RESIZE_HEIGHT, info.maxResizeHeight);
83         out.attributeInt(null, ATTR_TARGET_CELL_WIDTH, info.targetCellWidth);
84         out.attributeInt(null, ATTR_TARGET_CELL_HEIGHT, info.targetCellHeight);
85         out.attributeInt(null, ATTR_UPDATE_PERIOD_MILLIS, info.updatePeriodMillis);
86         out.attributeInt(null, ATTR_INITIAL_LAYOUT, info.initialLayout);
87         out.attributeInt(null, ATTR_INITIAL_KEYGUARD_LAYOUT, info.initialKeyguardLayout);
88         if (info.configure != null) {
89             out.attribute(null, ATTR_CONFIGURE, info.configure.flattenToShortString());
90         }
91         if (info.label != null) {
92             out.attribute(null, ATTR_LABEL, info.label);
93         }
94         out.attributeInt(null, ATTR_ICON, info.icon);
95         out.attributeInt(null, ATTR_PREVIEW_IMAGE, info.previewImage);
96         out.attributeInt(null, ATTR_PREVIEW_LAYOUT, info.previewLayout);
97         out.attributeInt(null, ATTR_AUTO_ADVANCED_VIEW_ID, info.autoAdvanceViewId);
98         out.attributeInt(null, ATTR_RESIZE_MODE, info.resizeMode);
99         out.attributeInt(null, ATTR_WIDGET_CATEGORY, info.widgetCategory);
100         out.attributeInt(null, ATTR_WIDGET_FEATURES, info.widgetFeatures);
101         out.attributeInt(null, ATTR_DESCRIPTION_RES, info.descriptionRes);
102         out.attributeBoolean(null, ATTR_PROVIDER_INHERITANCE, info.isExtendedFromAppWidgetProvider);
103         out.attribute(null, ATTR_OS_FINGERPRINT, Build.FINGERPRINT);
104     }
105 
106     /**
107      * @hide
108      */
109     @Nullable
readAppWidgetProviderInfoLocked( @onNull final TypedXmlPullParser parser)110     public static AppWidgetProviderInfo readAppWidgetProviderInfoLocked(
111             @NonNull final TypedXmlPullParser parser) {
112         Objects.requireNonNull(parser);
113         final String fingerprint = parser.getAttributeValue(null, ATTR_OS_FINGERPRINT);
114         if (!Build.FINGERPRINT.equals(fingerprint)) {
115             return null;
116         }
117         final AppWidgetProviderInfo info = new AppWidgetProviderInfo();
118         info.minWidth = parser.getAttributeInt(null, ATTR_MIN_WIDTH, 0);
119         info.minHeight = parser.getAttributeInt(null, ATTR_MIN_HEIGHT, 0);
120         info.minResizeWidth = parser.getAttributeInt(null, ATTR_MIN_RESIZE_WIDTH, 0);
121         info.minResizeHeight = parser.getAttributeInt(null, ATTR_MIN_RESIZE_HEIGHT, 0);
122         info.maxResizeWidth = parser.getAttributeInt(null, ATTR_MAX_RESIZE_WIDTH, 0);
123         info.maxResizeHeight = parser.getAttributeInt(null, ATTR_MAX_RESIZE_HEIGHT, 0);
124         info.targetCellWidth = parser.getAttributeInt(null, ATTR_TARGET_CELL_WIDTH, 0);
125         info.targetCellHeight = parser.getAttributeInt(null, ATTR_TARGET_CELL_HEIGHT, 0);
126         info.updatePeriodMillis = parser.getAttributeInt(null, ATTR_UPDATE_PERIOD_MILLIS, 0);
127         info.initialLayout = parser.getAttributeInt(null, ATTR_INITIAL_LAYOUT, 0);
128         info.initialKeyguardLayout = parser.getAttributeInt(
129                 null, ATTR_INITIAL_KEYGUARD_LAYOUT, 0);
130         final String configure = parser.getAttributeValue(null, ATTR_CONFIGURE);
131         if (!TextUtils.isEmpty(configure)) {
132             info.configure = ComponentName.unflattenFromString(configure);
133         }
134         info.label = parser.getAttributeValue(null, ATTR_LABEL);
135         info.icon = parser.getAttributeInt(null, ATTR_ICON, 0);
136         info.previewImage = parser.getAttributeInt(null, ATTR_PREVIEW_IMAGE, 0);
137         info.previewLayout = parser.getAttributeInt(null, ATTR_PREVIEW_LAYOUT, 0);
138         info.autoAdvanceViewId = parser.getAttributeInt(null, ATTR_AUTO_ADVANCED_VIEW_ID, 0);
139         info.resizeMode = parser.getAttributeInt(null, ATTR_RESIZE_MODE, 0);
140         info.widgetCategory = parser.getAttributeInt(null, ATTR_WIDGET_CATEGORY, 0);
141         info.widgetFeatures = parser.getAttributeInt(null, ATTR_WIDGET_FEATURES, 0);
142         info.descriptionRes = parser.getAttributeInt(null, ATTR_DESCRIPTION_RES, 0);
143         info.isExtendedFromAppWidgetProvider = parser.getAttributeBoolean(null,
144             ATTR_PROVIDER_INHERITANCE, false);
145         return info;
146     }
147 
148     @NonNull
serializeWidgetSizes(@onNull List<SizeF> sizes)149     static String serializeWidgetSizes(@NonNull List<SizeF> sizes) {
150         return sizes.stream().map(SizeF::toString)
151                 .collect(Collectors.joining(SIZE_SEPARATOR));
152     }
153 
154     @Nullable
deserializeWidgetSizesStr(@ullable String sizesStr)155     static ArrayList<SizeF> deserializeWidgetSizesStr(@Nullable String sizesStr) {
156         if (sizesStr == null || sizesStr.isEmpty()) {
157             return null;
158         }
159         try {
160             return Arrays.stream(sizesStr.split(SIZE_SEPARATOR))
161                     .map(SizeF::parseSizeF)
162                     .collect(Collectors.toCollection(ArrayList::new));
163         } catch (NumberFormatException e) {
164             Slog.e(TAG, "Error parsing widget sizes", e);
165             return null;
166         }
167     }
168 }
169