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