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.compat.annotation.UnsupportedAppUsage; 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><appwidget-provider></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><receiver></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><receiver></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><receiver></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 AppWidgetProviderInfo()277 public AppWidgetProviderInfo() { 278 279 } 280 281 /** 282 * Unflatten the AppWidgetProviderInfo from a parcel. 283 */ 284 @SuppressWarnings("deprecation") AppWidgetProviderInfo(Parcel in)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 */ loadLabel(PackageManager packageManager)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><receiver></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 */ loadIcon(@onNull Context context, int density)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><receiver></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 */ loadPreviewImage(@onNull Context context, int density)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 */ getProfile()364 public final UserHandle getProfile() { 365 return new UserHandle(UserHandle.getUserId(providerInfo.applicationInfo.uid)); 366 } 367 368 @Override 369 @SuppressWarnings("deprecation") writeToParcel(Parcel out, int flags)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") clone()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 describeContents()414 public int describeContents() { 415 return 0; 416 } 417 loadDrawable(Context context, int density, int resourceId, boolean loadDefaultIcon)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 */ updateDimensions(DisplayMetrics displayMetrics)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 toString()463 public String toString() { 464 return "AppWidgetProviderInfo(" + getProfile() + '/' + provider + ')'; 465 } 466 } 467