• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 package com.android.launcher3.widget.custom;
17 
18 import android.appwidget.AppWidgetManager;
19 import android.appwidget.AppWidgetProviderInfo;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.content.res.TypedArray;
23 import android.content.res.XmlResourceParser;
24 import android.os.Parcel;
25 import android.os.Process;
26 import android.util.SparseArray;
27 import android.util.Xml;
28 
29 import com.android.launcher3.LauncherAppWidgetInfo;
30 import com.android.launcher3.LauncherAppWidgetProviderInfo;
31 import com.android.launcher3.R;
32 
33 import org.xmlpull.v1.XmlPullParser;
34 import org.xmlpull.v1.XmlPullParserException;
35 
36 import java.io.IOException;
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 import static com.android.launcher3.LauncherAppWidgetProviderInfo.CLS_CUSTOM_WIDGET_PREFIX;
41 
42 /**
43  * Utility class to parse {@ink CustomAppWidgetProviderInfo} definitions from xml
44  */
45 public class CustomWidgetParser {
46 
47     private static List<LauncherAppWidgetProviderInfo> sCustomWidgets;
48     private static SparseArray<ComponentName> sWidgetsIdMap;
49 
getCustomWidgets(Context context)50     public static List<LauncherAppWidgetProviderInfo> getCustomWidgets(Context context) {
51         if (sCustomWidgets == null) {
52             // Synchronization not needed as it it safe to load multiple times
53             parseCustomWidgets(context);
54         }
55 
56         return sCustomWidgets;
57     }
58 
getWidgetIdForCustomProvider(Context context, ComponentName provider)59     public static int getWidgetIdForCustomProvider(Context context, ComponentName provider) {
60         if (sWidgetsIdMap == null) {
61             parseCustomWidgets(context);
62         }
63         int index = sWidgetsIdMap.indexOfValue(provider);
64         if (index >= 0) {
65             return LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - sWidgetsIdMap.keyAt(index);
66         } else {
67             return AppWidgetManager.INVALID_APPWIDGET_ID;
68         }
69     }
70 
getWidgetProvider(Context context, int widgetId)71     public static LauncherAppWidgetProviderInfo getWidgetProvider(Context context, int widgetId) {
72         if (sWidgetsIdMap == null || sCustomWidgets == null) {
73             parseCustomWidgets(context);
74         }
75         ComponentName cn = sWidgetsIdMap.get(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - widgetId);
76         for (LauncherAppWidgetProviderInfo info : sCustomWidgets) {
77             if (info.provider.equals(cn)) {
78                 return info;
79             }
80         }
81         return null;
82     }
83 
parseCustomWidgets(Context context)84     private static void parseCustomWidgets(Context context) {
85         ArrayList<LauncherAppWidgetProviderInfo> widgets = new ArrayList<>();
86         SparseArray<ComponentName> idMap = new SparseArray<>();
87 
88         List<AppWidgetProviderInfo> providers = AppWidgetManager.getInstance(context)
89                 .getInstalledProvidersForProfile(Process.myUserHandle());
90         if (providers.isEmpty()) {
91             sCustomWidgets = widgets;
92             sWidgetsIdMap = idMap;
93             return;
94         }
95 
96         Parcel parcel = Parcel.obtain();
97         providers.get(0).writeToParcel(parcel, 0);
98 
99         try (XmlResourceParser parser = context.getResources().getXml(R.xml.custom_widgets)) {
100             final int depth = parser.getDepth();
101             int type;
102 
103             while (((type = parser.next()) != XmlPullParser.END_TAG ||
104                     parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
105                 if ((type == XmlPullParser.START_TAG) && "widget".equals(parser.getName())) {
106                     TypedArray a = context.obtainStyledAttributes(
107                             Xml.asAttributeSet(parser), R.styleable.CustomAppWidgetProviderInfo);
108 
109                     parcel.setDataPosition(0);
110                     CustomAppWidgetProviderInfo info = newInfo(a, parcel, context);
111                     widgets.add(info);
112                     a.recycle();
113 
114                     idMap.put(info.providerId, info.provider);
115                 }
116             }
117         } catch (IOException | XmlPullParserException e) {
118             throw new RuntimeException(e);
119         }
120         parcel.recycle();
121         sCustomWidgets = widgets;
122         sWidgetsIdMap = idMap;
123     }
124 
newInfo(TypedArray a, Parcel parcel, Context context)125     private static CustomAppWidgetProviderInfo newInfo(TypedArray a, Parcel parcel, Context context) {
126         int providerId = a.getInt(R.styleable.CustomAppWidgetProviderInfo_providerId, 0);
127         CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false, providerId);
128         info.provider = new ComponentName(context.getPackageName(), CLS_CUSTOM_WIDGET_PREFIX + providerId);
129 
130         info.label = a.getString(R.styleable.CustomAppWidgetProviderInfo_android_label);
131         info.initialLayout = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_initialLayout, 0);
132         info.icon = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_icon, 0);
133         info.previewImage = a.getResourceId(R.styleable.CustomAppWidgetProviderInfo_android_previewImage, 0);
134         info.resizeMode = a.getInt(R.styleable.CustomAppWidgetProviderInfo_android_resizeMode, 0);
135 
136         info.spanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numColumns, 1);
137         info.spanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numRows, 1);
138         info.minSpanX = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinColumns, 1);
139         info.minSpanY = a.getInt(R.styleable.CustomAppWidgetProviderInfo_numMinRows, 1);
140         return info;
141     }
142 }
143