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