• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.IdRes;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SuppressLint;
24 import android.app.PendingIntent;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.content.ComponentName;
27 import android.content.Context;
28 import android.content.pm.ActivityInfo;
29 import android.content.pm.PackageManager;
30 import android.content.res.ResourceId;
31 import android.content.res.Resources;
32 import android.graphics.drawable.Drawable;
33 import android.os.Bundle;
34 import android.os.Parcel;
35 import android.os.Parcelable;
36 import android.os.UserHandle;
37 import android.util.DisplayMetrics;
38 import android.util.TypedValue;
39 
40 import java.lang.annotation.Retention;
41 import java.lang.annotation.RetentionPolicy;
42 
43 /**
44  * Describes the meta data for an installed AppWidget provider.  The fields in this class
45  * correspond to the fields in the <code>&lt;appwidget-provider&gt;</code> xml tag.
46  */
47 public class AppWidgetProviderInfo implements Parcelable {
48 
49     /**
50      * Widget is not resizable.
51      */
52     public static final int RESIZE_NONE             = 0;
53     /**
54      * Widget is resizable in the horizontal axis only.
55      */
56     public static final int RESIZE_HORIZONTAL       = 1;
57     /**
58      * Widget is resizable in the vertical axis only.
59      */
60     public static final int RESIZE_VERTICAL         = 2;
61     /**
62      * Widget is resizable in both the horizontal and vertical axes.
63      */
64     public static final int RESIZE_BOTH = RESIZE_HORIZONTAL | RESIZE_VERTICAL;
65 
66     /** @hide */
67     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
68             RESIZE_HORIZONTAL,
69             RESIZE_VERTICAL,
70     })
71     @Retention(RetentionPolicy.SOURCE)
72     public @interface ResizeModeFlags {}
73 
74     /** {@hide} */
75     public static final int WIDGET_CATEGORY_UNKNOWN = -1;
76 
77     /**
78      * Indicates that the widget can be displayed on the home screen. This is the default value.
79      */
80     public static final int WIDGET_CATEGORY_HOME_SCREEN = 1;
81 
82     /**
83      * Indicates that the widget can be displayed on the keyguard.
84      */
85     public static final int WIDGET_CATEGORY_KEYGUARD = 2;
86 
87     /**
88      * Indicates that the widget can be displayed within a space reserved for the search box.
89      */
90     public static final int WIDGET_CATEGORY_SEARCHBOX = 4;
91 
92     /** @hide */
93     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
94             WIDGET_CATEGORY_HOME_SCREEN,
95             WIDGET_CATEGORY_KEYGUARD,
96             WIDGET_CATEGORY_SEARCHBOX,
97     })
98     @Retention(RetentionPolicy.SOURCE)
99     public @interface CategoryFlags {}
100 
101     /**
102      * The widget can be reconfigured anytime after it is bound by starting the
103      * {@link #configure} activity.
104      *
105      * @see #widgetFeatures
106      */
107     public static final int WIDGET_FEATURE_RECONFIGURABLE = 1;
108 
109     /**
110      * The widget is added directly by the app, and the host may hide this widget when providing
111      * the user with the list of available widgets to choose from.
112      *
113      * @see AppWidgetManager#requestPinAppWidget(ComponentName, Bundle, PendingIntent)
114      * @see #widgetFeatures
115      */
116     public static final int WIDGET_FEATURE_HIDE_FROM_PICKER = 2;
117 
118     /**
119      * The widget provides a default configuration. The host may choose not to launch the provided
120      * configuration activity.
121      *
122      * @see #widgetFeatures
123      */
124     public static final int WIDGET_FEATURE_CONFIGURATION_OPTIONAL = 4;
125 
126     /** @hide */
127     @IntDef(flag = true, prefix = { "FLAG_" }, value = {
128             WIDGET_FEATURE_RECONFIGURABLE,
129             WIDGET_FEATURE_HIDE_FROM_PICKER,
130             WIDGET_FEATURE_CONFIGURATION_OPTIONAL
131     })
132     @Retention(RetentionPolicy.SOURCE)
133     public @interface FeatureFlags {}
134 
135     /**
136      * Identity of this AppWidget component.  This component should be a {@link
137      * android.content.BroadcastReceiver}, and it will be sent the AppWidget intents
138      * {@link android.appwidget as described in the AppWidget package documentation}.
139      *
140      * <p>This field corresponds to the <code>android:name</code> attribute in
141      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
142      */
143     public ComponentName provider;
144 
145     /**
146      * The default height of the widget when added to a host, in dp. The widget will get
147      * at least this width, and will often be given more, depending on the host.
148      *
149      * <p>This field corresponds to the <code>android:minWidth</code> attribute in
150      * the AppWidget meta-data file.
151      */
152     public int minWidth;
153 
154     /**
155      * The default height of the widget when added to a host, in dp. The widget will get
156      * at least this height, and will often be given more, depending on the host.
157      *
158      * <p>This field corresponds to the <code>android:minHeight</code> attribute in
159      * the AppWidget meta-data file.
160      */
161     public int minHeight;
162 
163     /**
164      * Minimum width (in dp) which the widget can be resized to. This field has no effect if it
165      * is greater than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
166      *
167      * <p>This field corresponds to the <code>android:minResizeWidth</code> attribute in
168      * the AppWidget meta-data file.
169      */
170     public int minResizeWidth;
171 
172     /**
173      * Minimum height (in dp) which the widget can be resized to. This field has no effect if it
174      * is greater than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
175      *
176      * <p>This field corresponds to the <code>android:minResizeHeight</code> attribute in
177      * the AppWidget meta-data file.
178      */
179     public int minResizeHeight;
180 
181     /**
182      * Maximum width (in dp) which the widget can be resized to. This field has no effect if it is
183      * smaller than minWidth or if horizontal resizing isn't enabled (see {@link #resizeMode}).
184      *
185      * <p>This field corresponds to the <code>android:maxResizeWidth</code> attribute in the
186      * AppWidget meta-data file.
187      */
188     @SuppressLint("MutableBareField")
189     public int maxResizeWidth;
190 
191     /**
192      * Maximum height (in dp) which the widget can be resized to. This field has no effect if it is
193      * smaller than minHeight or if vertical resizing isn't enabled (see {@link #resizeMode}).
194      *
195      * <p>This field corresponds to the <code>android:maxResizeHeight</code> attribute in the
196      * AppWidget meta-data file.
197      */
198     @SuppressLint("MutableBareField")
199     public int maxResizeHeight;
200 
201     /**
202      * The default width of a widget when added to a host, in units of launcher grid cells.
203      *
204      * <p>This field corresponds to the <code>android:targetCellWidth</code> attribute in the
205      * AppWidget meta-data file.
206      */
207     @SuppressLint("MutableBareField")
208     public int targetCellWidth;
209 
210     /**
211      * The default height of a widget when added to a host, in units of launcher grid cells.
212      *
213      * <p>This field corresponds to the <code>android:targetCellHeight</code> attribute in the
214      * AppWidget meta-data file.
215      */
216     @SuppressLint("MutableBareField")
217     public int targetCellHeight;
218 
219     /**
220      * How often, in milliseconds, that this AppWidget wants to be updated.
221      * The AppWidget manager may place a limit on how often a AppWidget is updated.
222      *
223      * <p>This field corresponds to the <code>android:updatePeriodMillis</code> attribute in
224      * the AppWidget meta-data file.
225      *
226      * <p class="note"><b>Note:</b> Updates requested with <code>updatePeriodMillis</code>
227      * will not be delivered more than once every 30 minutes.</p>
228      */
229     public int updatePeriodMillis;
230 
231     /**
232      * The resource id of the initial layout for this AppWidget.  This should be
233      * displayed until the RemoteViews for the AppWidget is available.
234      *
235      * <p>This field corresponds to the <code>android:initialLayout</code> attribute in
236      * the AppWidget meta-data file.
237      */
238     public int initialLayout;
239 
240     /**
241      * The resource id of the initial layout for this AppWidget when it is displayed on keyguard.
242      * This parameter only needs to be provided if the widget can be displayed on the keyguard,
243      * see {@link #widgetCategory}.
244      *
245      * <p>This field corresponds to the <code>android:initialKeyguardLayout</code> attribute in
246      * the AppWidget meta-data file.
247      */
248     public int initialKeyguardLayout;
249 
250     /**
251      * The activity to launch that will configure the AppWidget.
252      *
253      * <p>This class name of field corresponds to the <code>android:configure</code> attribute in
254      * the AppWidget meta-data file.  The package name always corresponds to the package containing
255      * the AppWidget provider.
256      */
257     public ComponentName configure;
258 
259     /**
260      * The label to display to the user in the AppWidget picker.
261      *
262      * @deprecated Use {@link #loadLabel(android.content.pm.PackageManager)}.
263      */
264     @Deprecated
265     public String label;
266 
267     /**
268      * The icon to display for this AppWidget in the AppWidget picker. If not supplied in the
269      * xml, the application icon will be used.
270      *
271      * <p>This field corresponds to the <code>android:icon</code> attribute in
272      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
273      */
274     public int icon;
275 
276     /**
277      * The view id of the AppWidget subview which should be auto-advanced by the widget's host.
278      *
279      * <p>This field corresponds to the <code>android:autoAdvanceViewId</code> attribute in
280      * the AppWidget meta-data file.
281      */
282     public int autoAdvanceViewId;
283 
284     /**
285      * A preview of what the AppWidget will look like after it's configured.
286      * If not supplied, the AppWidget's icon will be used.
287      *
288      * <p>This field corresponds to the <code>android:previewImage</code> attribute in the AppWidget
289      * meta-data file.
290      */
291     public int previewImage;
292 
293     /**
294      * The layout resource id of a preview of what the AppWidget will look like after it's
295      * configured.
296      *
297      * <p>Unlike previewImage, previewLayout can better showcase AppWidget in different locales,
298      * system themes, display sizes & density etc.
299      *
300      * <p>If supplied, this will take precedence over the previewImage on supported widget hosts.
301      * Otherwise, previewImage will be used.
302      *
303      * <p>This field corresponds to the <code>android:previewLayout</code> attribute in the
304      * AppWidget meta-data file.
305      */
306     @SuppressLint("MutableBareField")
307     @IdRes
308     public int previewLayout;
309 
310     /**
311      * The rules by which a widget can be resized. See {@link #RESIZE_NONE},
312      * {@link #RESIZE_NONE}, {@link #RESIZE_HORIZONTAL},
313      * {@link #RESIZE_VERTICAL}, {@link #RESIZE_BOTH}.
314      *
315      * <p>This field corresponds to the <code>android:resizeMode</code> attribute in
316      * the AppWidget meta-data file.
317      */
318     @ResizeModeFlags
319     public int resizeMode;
320 
321     /**
322      * Determines whether this widget can be displayed on the home screen, the keyguard, or both.
323      * A widget which is displayed on both needs to ensure that it follows the design guidelines
324      * for both widget classes. This can be achieved by querying the AppWidget options in its
325      * widget provider's update method.
326      *
327      * <p>This field corresponds to the <code>widgetCategory</code> attribute in
328      * the AppWidget meta-data file.
329      */
330     @CategoryFlags
331     public int widgetCategory;
332 
333     /**
334      * Resource id for the description of the AppWidget.
335      *
336      * <p>This field corresponds to the <code>android:description</code> attribute in the AppWidget
337      * meta-data file.
338      */
339     @SuppressLint("MutableBareField")
340     @IdRes
341     public int descriptionRes;
342 
343     /**
344      * Flags indicating various features supported by the widget. These are hints to the widget
345      * host, and do not actually change the behavior of the widget.
346      *
347      * @see #WIDGET_FEATURE_RECONFIGURABLE
348      * @see #WIDGET_FEATURE_HIDE_FROM_PICKER
349      * @see #WIDGET_FEATURE_CONFIGURATION_OPTIONAL
350      */
351     @FeatureFlags
352     public int widgetFeatures;
353 
354     /** @hide */
355     @UnsupportedAppUsage
356     public ActivityInfo providerInfo;
357 
AppWidgetProviderInfo()358     public AppWidgetProviderInfo() {
359 
360     }
361 
362     /**
363      * Unflatten the AppWidgetProviderInfo from a parcel.
364      */
365     @SuppressWarnings("deprecation")
AppWidgetProviderInfo(Parcel in)366     public AppWidgetProviderInfo(Parcel in) {
367         this.provider = in.readTypedObject(ComponentName.CREATOR);
368         this.minWidth = in.readInt();
369         this.minHeight = in.readInt();
370         this.minResizeWidth = in.readInt();
371         this.minResizeHeight = in.readInt();
372         this.maxResizeWidth = in.readInt();
373         this.maxResizeHeight = in.readInt();
374         this.targetCellWidth = in.readInt();
375         this.targetCellHeight = in.readInt();
376         this.updatePeriodMillis = in.readInt();
377         this.initialLayout = in.readInt();
378         this.initialKeyguardLayout = in.readInt();
379         this.configure = in.readTypedObject(ComponentName.CREATOR);
380         this.label = in.readString();
381         this.icon = in.readInt();
382         this.previewImage = in.readInt();
383         this.previewLayout = in.readInt();
384         this.autoAdvanceViewId = in.readInt();
385         this.resizeMode = in.readInt();
386         this.widgetCategory = in.readInt();
387         this.providerInfo = in.readTypedObject(ActivityInfo.CREATOR);
388         this.widgetFeatures = in.readInt();
389         this.descriptionRes = in.readInt();
390     }
391 
392     /**
393      * Loads the localized label to display to the user in the AppWidget picker.
394      *
395      * @param packageManager Package manager instance for loading resources.
396      * @return The label for the current locale.
397      */
loadLabel(PackageManager packageManager)398     public final String loadLabel(PackageManager packageManager) {
399         CharSequence label = providerInfo.loadLabel(packageManager);
400         if (label != null) {
401             return label.toString().trim();
402         }
403         return null;
404     }
405 
406     /**
407      * Loads the icon to display for this AppWidget in the AppWidget picker. If not
408      * supplied in the xml, the application icon will be used. A client can optionally
409      * provide a desired density such as {@link android.util.DisplayMetrics#DENSITY_LOW}
410      * {@link android.util.DisplayMetrics#DENSITY_MEDIUM}, etc. If no density is
411      * provided, the density of the current display will be used.
412      * <p>
413      * The loaded icon corresponds to the <code>android:icon</code> attribute in
414      * the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
415      * </p>
416      *
417      * @param context Context for accessing resources.
418      * @param density The optional desired density as per
419      *         {@link android.util.DisplayMetrics#densityDpi}.
420      * @return The provider icon.
421      */
loadIcon(@onNull Context context, int density)422     public final Drawable loadIcon(@NonNull Context context, int density) {
423         return loadDrawable(context, density, providerInfo.getIconResource(), true);
424     }
425 
426     /**
427      * Loads a preview of what the AppWidget will look like after it's configured.
428      * A client can optionally provide a desired density such as
429      * {@link android.util.DisplayMetrics#DENSITY_LOW}
430      * {@link android.util.DisplayMetrics#DENSITY_MEDIUM}, etc. If no density is
431      * provided, the density of the current display will be used.
432      * <p>
433      * The loaded image corresponds to the <code>android:previewImage</code> attribute
434      * in the <code>&lt;receiver&gt;</code> element in the AndroidManifest.xml file.
435      * </p>
436      *
437      * @param context Context for accessing resources.
438      * @param density The optional desired density as per
439      *         {@link android.util.DisplayMetrics#densityDpi}.
440      * @return The widget preview image or null if preview image is not available.
441      */
loadPreviewImage(@onNull Context context, int density)442     public final Drawable loadPreviewImage(@NonNull Context context, int density) {
443         return loadDrawable(context, density, previewImage, false);
444     }
445 
446     /**
447      * Loads localized description for the app widget.
448      *
449      * <p>Description is intended to be displayed in the UI of the widget picker.
450      *
451      * @param context Context for accessing resources.
452      *
453      * @return CharSequence for app widget description for the current locale.
454      */
455     @Nullable
loadDescription(@onNull Context context)456     public final CharSequence loadDescription(@NonNull Context context) {
457         if (ResourceId.isValid(descriptionRes)) {
458             CharSequence description =
459                     context.getPackageManager().getText(
460                             providerInfo.packageName,
461                             descriptionRes,
462                             providerInfo.applicationInfo);
463             if (description != null) {
464                 return description.toString().trim();
465             }
466         }
467         return null;
468     }
469 
470     /**
471      * Gets the user profile in which the provider resides.
472      *
473      * @return The hosting user profile.
474      */
getProfile()475     public final UserHandle getProfile() {
476         return new UserHandle(UserHandle.getUserId(providerInfo.applicationInfo.uid));
477     }
478 
479     /**
480      * Returns the broadcast receiver that is providing this widget.
481      */
482     @NonNull
getActivityInfo()483     public ActivityInfo getActivityInfo() {
484         return providerInfo;
485     }
486 
487     @Override
488     @SuppressWarnings("deprecation")
writeToParcel(Parcel out, int flags)489     public void writeToParcel(Parcel out, int flags) {
490         out.writeTypedObject(this.provider, flags);
491         out.writeInt(this.minWidth);
492         out.writeInt(this.minHeight);
493         out.writeInt(this.minResizeWidth);
494         out.writeInt(this.minResizeHeight);
495         out.writeInt(this.maxResizeWidth);
496         out.writeInt(this.maxResizeHeight);
497         out.writeInt(this.targetCellWidth);
498         out.writeInt(this.targetCellHeight);
499         out.writeInt(this.updatePeriodMillis);
500         out.writeInt(this.initialLayout);
501         out.writeInt(this.initialKeyguardLayout);
502         out.writeTypedObject(this.configure, flags);
503         out.writeString(this.label);
504         out.writeInt(this.icon);
505         out.writeInt(this.previewImage);
506         out.writeInt(this.previewLayout);
507         out.writeInt(this.autoAdvanceViewId);
508         out.writeInt(this.resizeMode);
509         out.writeInt(this.widgetCategory);
510         out.writeTypedObject(this.providerInfo, flags);
511         out.writeInt(this.widgetFeatures);
512         out.writeInt(this.descriptionRes);
513     }
514 
515     @Override
516     @SuppressWarnings("deprecation")
clone()517     public AppWidgetProviderInfo clone() {
518         AppWidgetProviderInfo that = new AppWidgetProviderInfo();
519         that.provider = this.provider == null ? null : this.provider.clone();
520         that.minWidth = this.minWidth;
521         that.minHeight = this.minHeight;
522         that.minResizeWidth = this.minResizeWidth;
523         that.minResizeHeight = this.minResizeHeight;
524         that.maxResizeWidth = this.maxResizeWidth;
525         that.maxResizeHeight = this.maxResizeHeight;
526         that.targetCellWidth = this.targetCellWidth;
527         that.targetCellHeight = this.targetCellHeight;
528         that.updatePeriodMillis = this.updatePeriodMillis;
529         that.initialLayout = this.initialLayout;
530         that.initialKeyguardLayout = this.initialKeyguardLayout;
531         that.configure = this.configure == null ? null : this.configure.clone();
532         that.label = this.label;
533         that.icon = this.icon;
534         that.previewImage = this.previewImage;
535         that.previewLayout = this.previewLayout;
536         that.autoAdvanceViewId = this.autoAdvanceViewId;
537         that.resizeMode = this.resizeMode;
538         that.widgetCategory = this.widgetCategory;
539         that.providerInfo = this.providerInfo;
540         that.widgetFeatures = this.widgetFeatures;
541         that.descriptionRes = this.descriptionRes;
542         return that;
543     }
544 
describeContents()545     public int describeContents() {
546         return 0;
547     }
548 
loadDrawable(Context context, int density, int resourceId, boolean loadDefaultIcon)549     private Drawable loadDrawable(Context context, int density, int resourceId,
550             boolean loadDefaultIcon) {
551         try {
552             Resources resources = context.getPackageManager().getResourcesForApplication(
553                     providerInfo.applicationInfo);
554             if (ResourceId.isValid(resourceId)) {
555                 if (density < 0) {
556                     density = 0;
557                 }
558                 return resources.getDrawableForDensity(resourceId, density, null);
559             }
560         } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) {
561             /* ignore */
562         }
563         return loadDefaultIcon ? providerInfo.loadIcon(context.getPackageManager()) : null;
564     }
565 
566     /**
567      * @hide
568      */
updateDimensions(DisplayMetrics displayMetrics)569     public void updateDimensions(DisplayMetrics displayMetrics) {
570         // Converting complex to dp.
571         minWidth = TypedValue.complexToDimensionPixelSize(minWidth, displayMetrics);
572         minHeight = TypedValue.complexToDimensionPixelSize(minHeight, displayMetrics);
573         minResizeWidth = TypedValue.complexToDimensionPixelSize(minResizeWidth, displayMetrics);
574         minResizeHeight = TypedValue.complexToDimensionPixelSize(minResizeHeight, displayMetrics);
575         maxResizeWidth = TypedValue.complexToDimensionPixelSize(maxResizeWidth, displayMetrics);
576         maxResizeHeight = TypedValue.complexToDimensionPixelSize(maxResizeHeight, displayMetrics);
577     }
578 
579     /**
580      * Parcelable.Creator that instantiates AppWidgetProviderInfo objects
581      */
582     public static final @android.annotation.NonNull Parcelable.Creator<AppWidgetProviderInfo> CREATOR
583             = new Parcelable.Creator<AppWidgetProviderInfo>()
584     {
585         public AppWidgetProviderInfo createFromParcel(Parcel parcel)
586         {
587             return new AppWidgetProviderInfo(parcel);
588         }
589 
590         public AppWidgetProviderInfo[] newArray(int size)
591         {
592             return new AppWidgetProviderInfo[size];
593         }
594     };
595 
toString()596     public String toString() {
597         return "AppWidgetProviderInfo(" + getProfile() + '/' + provider + ')';
598     }
599 }
600