1 /*
2  * Copyright (C) 2006 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.appwidget;
18 
19 import android.annotation.NonNull;
20 import android.content.Context;
21 import android.content.pm.ActivityInfo;
22 import android.content.pm.PackageManager;
23 import android.content.res.Resources;
24 import android.graphics.drawable.Drawable;
25 import android.os.Parcel;
26 import android.os.Parcelable;
27 import android.content.ComponentName;
28 import android.os.UserHandle;
29 
30 /**
31  * Describes the meta data for an installed AppWidget provider.  The fields in this class
32  * correspond to the fields in the <code>&lt;appwidget-provider&gt;</code> xml tag.
33  */
34 public class AppWidgetProviderInfo implements Parcelable {
35 
36     /**
37      * Widget is not resizable.
38      */
39     public static final int RESIZE_NONE             = 0;
40     /**
41      * Widget is resizable in the horizontal axis only.
42      */
43     public static final int RESIZE_HORIZONTAL       = 1;
44     /**
45      * Widget is resizable in the vertical axis only.
46      */
47     public static final int RESIZE_VERTICAL         = 2;
48     /**
49      * Widget is resizable in both the horizontal and vertical axes.
50      */
51     public static final int RESIZE_BOTH = RESIZE_HORIZONTAL | RESIZE_VERTICAL;
52 
53     /**
54      * Indicates that the widget can be displayed on the home screen. This is the default value.
55      */
56     public static final int WIDGET_CATEGORY_HOME_SCREEN = 1;
57 
58     /**
59      * Indicates that the widget can be displayed on the keyguard.
60      */
61     public static final int WIDGET_CATEGORY_KEYGUARD = 2;
62 
63     /**
64      * Indicates that the widget can be displayed within a space reserved for the search box.
65      */
66     public static final int WIDGET_CATEGORY_SEARCHBOX = 4;
67 
68     /**
69      * Identity of this AppWidget component.  This component should be a {@link
70      * android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
71      * {@link android.appwidget as described in the AppWidget package documentation}.
72      *
73      * <p>This field corresponds to the <code>android:name</code> attribute in
74      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
75      */
76     public ComponentName provider;
77 
78     /**
79      * The default height of the widget when added to a host, in dp. The widget will get
80      * at least this width, and will often be given more, depending on the host.
81      *
82      * <p>This field corresponds to the <code>android:minWidth</code> attribute in
83      * the AppWidget meta-data file.
84      */
85     public int minWidth;
86 
87     /**
88      * The default height of the widget when added to a host, in dp. The widget will get
89      * at least this height, and will often be given more, depending on the host.
90      *
91      * <p>This field corresponds to the <code>android:minHeight</code> attribute in
92      * the AppWidget meta-data file.
93      */
94     public int minHeight;
95 
96     /**
97      * Minimum width (in dp) which the widget can be resized to. This field has no effect if it
98      * is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
99      *
100      * <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in
101      * the AppWidget meta-data file.
102      */
103     public int minResizeWidth;
104 
105     /**
106      * Minimum height (in dp) which the widget can be resized to. This field has no effect if it
107      * is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
108      *
109      * <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in
110      * the AppWidget meta-data file.
111      */
112     public int minResizeHeight;
113 
114     /**
115      * How often, in milliseconds, that this AppWidget wants to be updated.
116      * The AppWidget manager may place a limit on how often a AppWidget is updated.
117      *
118      * <p>This field corresponds to the <code>android:updatePeriodMillis</code> attribute in
119      * the AppWidget meta-data file.
120      *
121      * <p class="note"><b>Note:</b> Updates requested with <code>updatePeriodMillis</code>
122      * will not be delivered more than once every 30 minutes.</p>
123      */
124     public int updatePeriodMillis;
125 
126     /**
127      * The resource id of the initial layout for this AppWidget.  This should be
128      * displayed until the RemoteViews for the AppWidget is available.
129      *
130      * <p>This field corresponds to the <code>android:initialLayout</code> attribute in
131      * the AppWidget meta-data file.
132      */
133     public int initialLayout;
134 
135     /**
136      * The resource id of the initial layout for this AppWidget when it is displayed on keyguard.
137      * This parameter only needs to be provided if the widget can be displayed on the keyguard,
138      * see {@link #widgetCategory}.
139      *
140      * <p>This field corresponds to the <code>android:initialKeyguardLayout</code> attribute in
141      * the AppWidget meta-data file.
142      */
143     public int initialKeyguardLayout;
144 
145     /**
146      * The activity to launch that will configure the AppWidget.
147      *
148      * <p>This class name of field corresponds to the <code>android:configure</code> attribute in
149      * the AppWidget meta-data file.  The package name always corresponds to the package containing
150      * the AppWidget provider.
151      */
152     public ComponentName configure;
153 
154     /**
155      * The label to display to the user in the AppWidget picker.
156      *
157      * @deprecated Use {@link #loadLabel(android.content.pm.PackageManager)}.
158      */
159     @Deprecated
160     public String label;
161 
162     /**
163      * The icon to display for this AppWidget in the AppWidget picker. If not supplied in the
164      * xml, the application icon will be used.
165      *
166      * <p>This field corresponds to the <code>android:icon</code> attribute in
167      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
168      */
169     public int icon;
170 
171     /**
172      * The view id of the AppWidget subview which should be auto-advanced by the widget's host.
173      *
174      * <p>This field corresponds to the <code>android:autoAdvanceViewId</code> attribute in
175      * the AppWidget meta-data file.
176      */
177     public int autoAdvanceViewId;
178 
179     /**
180      * A preview of what the AppWidget will look like after it's configured.
181      * If not supplied, the AppWidget's icon will be used.
182      *
183      * <p>This field corresponds to the <code>android:previewImage</code> attribute in
184      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
185      */
186     public int previewImage;
187 
188     /**
189      * The rules by which a widget can be resized. See {@link #RESIZE_NONE},
190      * {@link #RESIZE_NONE}, {@link #RESIZE_HORIZONTAL},
191      * {@link #RESIZE_VERTICAL}, {@link #RESIZE_BOTH}.
192      *
193      * <p>This field corresponds to the <code>android:resizeMode</code> attribute in
194      * the AppWidget meta-data file.
195      */
196     public int resizeMode;
197 
198     /**
199      * Determines whether this widget can be displayed on the home screen, the keyguard, or both.
200      * A widget which is displayed on both needs to ensure that it follows the design guidelines
201      * for both widget classes. This can be achieved by querying the AppWidget options in its
202      * widget provider's update method.
203      *
204      * <p>This field corresponds to the <code>widgetCategory</code> attribute in
205      * the AppWidget meta-data file.
206      */
207     public int widgetCategory;
208 
209     /** @hide */
210     public ActivityInfo providerInfo;
211 
AppWidgetProviderInfo()212     public AppWidgetProviderInfo() {
213 
214     }
215 
216     /**
217      * Unflatten the AppWidgetProviderInfo from a parcel.
218      */
219     @SuppressWarnings("deprecation")
AppWidgetProviderInfo(Parcel in)220     public AppWidgetProviderInfo(Parcel in) {
221         if (0 != in.readInt()) {
222             this.provider = new ComponentName(in);
223         }
224         this.minWidth = in.readInt();
225         this.minHeight = in.readInt();
226         this.minResizeWidth = in.readInt();
227         this.minResizeHeight = in.readInt();
228         this.updatePeriodMillis = in.readInt();
229         this.initialLayout = in.readInt();
230         this.initialKeyguardLayout = in.readInt();
231         if (0 != in.readInt()) {
232             this.configure = new ComponentName(in);
233         }
234         this.label = in.readString();
235         this.icon = in.readInt();
236         this.previewImage = in.readInt();
237         this.autoAdvanceViewId = in.readInt();
238         this.resizeMode = in.readInt();
239         this.widgetCategory = in.readInt();
240         this.providerInfo = in.readParcelable(null);
241     }
242 
243     /**
244      * Loads the localized label to display to the user in the AppWidget picker.
245      *
246      * @param packageManager Package manager instance for loading resources.
247      * @return The label for the current locale.
248      */
loadLabel(PackageManager packageManager)249     public final String loadLabel(PackageManager packageManager) {
250         CharSequence label = providerInfo.loadLabel(packageManager);
251         if (label != null) {
252             return label.toString().trim();
253         }
254         return null;
255     }
256 
257     /**
258      * Loads the icon to display for this AppWidget in the AppWidget picker. If not
259      * supplied in the xml, the application icon will be used. A client can optionally
260      * provide a desired density such as {@link android.util.DisplayMetrics#DENSITY_LOW}
261      * {@link android.util.DisplayMetrics#DENSITY_MEDIUM}, etc. If no density is
262      * provided, the density of the current display will be used.
263      * <p>
264      * The loaded icon corresponds to the <code>android:icon</code> attribute in
265      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
266      * </p>
267      *
268      * @param context Context for accessing resources.
269      * @param density The optional desired density as per
270      *         {@link android.util.DisplayMetrics#densityDpi}.
271      * @return The provider icon.
272      */
loadIcon(@onNull Context context, int density)273     public final Drawable loadIcon(@NonNull Context context, int density) {
274         return loadDrawable(context, density, providerInfo.getIconResource(), true);
275     }
276 
277     /**
278      * Loads a preview of what the AppWidget will look like after it's configured.
279      * A client can optionally provide a desired density such as
280      * {@link android.util.DisplayMetrics#DENSITY_LOW}
281      * {@link android.util.DisplayMetrics#DENSITY_MEDIUM}, etc. If no density is
282      * provided, the density of the current display will be used.
283      * <p>
284      * The loaded image corresponds to the <code>android:previewImage</code> attribute
285      * in the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
286      * </p>
287      *
288      * @param context Context for accessing resources.
289      * @param density The optional desired density as per
290      *         {@link android.util.DisplayMetrics#densityDpi}.
291      * @return The widget preview image or null if preview image is not available.
292      */
loadPreviewImage(@onNull Context context, int density)293     public final Drawable loadPreviewImage(@NonNull Context context, int density) {
294         return loadDrawable(context, density, previewImage, false);
295     }
296 
297     /**
298      * Gets the user profile in which the provider resides.
299      *
300      * @return The hosting user profile.
301      */
getProfile()302     public final UserHandle getProfile() {
303         return new UserHandle(UserHandle.getUserId(providerInfo.applicationInfo.uid));
304     }
305 
306     @Override
307     @SuppressWarnings("deprecation")
writeToParcel(android.os.Parcel out, int flags)308     public void writeToParcel(android.os.Parcel out, int flags) {
309         if (this.provider != null) {
310             out.writeInt(1);
311             this.provider.writeToParcel(out, flags);
312         } else {
313             out.writeInt(0);
314         }
315         out.writeInt(this.minWidth);
316         out.writeInt(this.minHeight);
317         out.writeInt(this.minResizeWidth);
318         out.writeInt(this.minResizeHeight);
319         out.writeInt(this.updatePeriodMillis);
320         out.writeInt(this.initialLayout);
321         out.writeInt(this.initialKeyguardLayout);
322         if (this.configure != null) {
323             out.writeInt(1);
324             this.configure.writeToParcel(out, flags);
325         } else {
326             out.writeInt(0);
327         }
328         out.writeString(this.label);
329         out.writeInt(this.icon);
330         out.writeInt(this.previewImage);
331         out.writeInt(this.autoAdvanceViewId);
332         out.writeInt(this.resizeMode);
333         out.writeInt(this.widgetCategory);
334         out.writeParcelable(this.providerInfo, flags);
335     }
336 
337     @Override
338     @SuppressWarnings("deprecation")
clone()339     public AppWidgetProviderInfo clone() {
340         AppWidgetProviderInfo that = new AppWidgetProviderInfo();
341         that.provider = this.provider == null ? null : this.provider.clone();
342         that.minWidth = this.minWidth;
343         that.minHeight = this.minHeight;
344         that.minResizeWidth = this.minResizeHeight;
345         that.minResizeHeight = this.minResizeHeight;
346         that.updatePeriodMillis = this.updatePeriodMillis;
347         that.initialLayout = this.initialLayout;
348         that.initialKeyguardLayout = this.initialKeyguardLayout;
349         that.configure = this.configure == null ? null : this.configure.clone();
350         that.label = this.label == null ? null : this.label.substring(0);
351         that.icon = this.icon;
352         that.previewImage = this.previewImage;
353         that.autoAdvanceViewId = this.autoAdvanceViewId;
354         that.resizeMode = this.resizeMode;
355         that.widgetCategory = this.widgetCategory;
356         that.providerInfo = this.providerInfo;
357         return that;
358     }
359 
describeContents()360     public int describeContents() {
361         return 0;
362     }
363 
loadDrawable(Context context, int density, int resourceId, boolean loadDefaultIcon)364     private Drawable loadDrawable(Context context, int density, int resourceId,
365             boolean loadDefaultIcon) {
366         try {
367             Resources resources = context.getPackageManager().getResourcesForApplication(
368                     providerInfo.applicationInfo);
369             if (resourceId > 0) {
370                 if (density <= 0) {
371                     density = context.getResources().getDisplayMetrics().densityDpi;
372                 }
373                 return resources.getDrawableForDensity(resourceId, density);
374             }
375         } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
376             /* ignore */
377         }
378         return loadDefaultIcon ? providerInfo.loadIcon(context.getPackageManager()) : null;
379     }
380 
381     /**
382      * Parcelable.Creator that instantiates AppWidgetProviderInfo objects
383      */
384     public static final Parcelable.Creator<AppWidgetProviderInfo> CREATOR
385             = new Parcelable.Creator<AppWidgetProviderInfo>()
386     {
387         public AppWidgetProviderInfo createFromParcel(Parcel parcel)
388         {
389             return new AppWidgetProviderInfo(parcel);
390         }
391 
392         public AppWidgetProviderInfo[] newArray(int size)
393         {
394             return new AppWidgetProviderInfo[size];
395         }
396     };
397 
toString()398     public String toString() {
399         return "AppWidgetProviderInfo(" + getProfile() + '/' + provider + ')';
400     }
401 }
402