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