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.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 
    212     public AppWidgetProviderInfo() {
    213 
    214     }
    215 
    216     /**
    217      * Unflatten the AppWidgetProviderInfo from a parcel.
    218      */
    219     @SuppressWarnings("deprecation")
    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      */
    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      */
    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      */
    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      */
    302     public final UserHandle getProfile() {
    303         return new UserHandle(UserHandle.getUserId(providerInfo.applicationInfo.uid));
    304     }
    305 
    306     @Override
    307     @SuppressWarnings("deprecation")
    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")
    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 
    360     public int describeContents() {
    361         return 0;
    362     }
    363 
    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 
    398     public String toString() {
    399         return "AppWidgetProviderInfo(" + getProfile() + '/' + provider + ')';
    400     }
    401 }
    402