1 /* 2 * Copyright (C) 2017 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 package com.android.wallpaper.model; 17 18 import android.app.Activity; 19 import android.app.WallpaperColors; 20 import android.content.Context; 21 import android.content.res.Resources; 22 import android.graphics.Bitmap; 23 import android.graphics.Color; 24 import android.graphics.Point; 25 import android.graphics.Rect; 26 import android.graphics.drawable.Drawable; 27 import android.net.Uri; 28 import android.os.Parcel; 29 import android.os.Parcelable; 30 31 import androidx.annotation.DrawableRes; 32 import androidx.annotation.IntDef; 33 import androidx.annotation.Nullable; 34 35 import com.android.wallpaper.asset.Asset; 36 import com.android.wallpaper.config.BaseFlags; 37 import com.android.wallpaper.module.InjectorProvider; 38 39 import java.util.HashMap; 40 import java.util.Iterator; 41 import java.util.List; 42 import java.util.Map; 43 import java.util.PriorityQueue; 44 import java.util.concurrent.CompletableFuture; 45 import java.util.concurrent.ExecutorService; 46 import java.util.concurrent.Executors; 47 import java.util.concurrent.Future; 48 49 /** 50 * Interface for wallpaper info model. 51 */ 52 public abstract class WallpaperInfo implements Parcelable { 53 54 private static final ExecutorService sExecutor = Executors.newCachedThreadPool(); 55 private ColorInfo mColorInfo = new ColorInfo(); 56 57 private PriorityQueue<String> mEffectNames = new PriorityQueue<>(); 58 59 protected final HashMap<String, String> mCropHints = new HashMap<>(); 60 WallpaperInfo()61 public WallpaperInfo() { 62 } 63 WallpaperInfo(Parcel in)64 protected WallpaperInfo(Parcel in) { 65 mColorInfo = new ColorInfo(in.readParcelable(WallpaperColors.class.getClassLoader()), 66 in.readInt()); 67 } 68 69 @Override writeToParcel(Parcel parcel, int flags)70 public void writeToParcel(Parcel parcel, int flags) { 71 parcel.writeParcelable(mColorInfo.getWallpaperColors(), flags); 72 parcel.writeInt(mColorInfo.getPlaceholderColor()); 73 } 74 75 public static final int BACKUP_NOT_ALLOWED = 0; 76 public static final int BACKUP_ALLOWED = 1; 77 78 /** 79 * @param context 80 * @return The title for this wallpaper, if applicable (as in a wallpaper "app" or live 81 * wallpaper), or null if not applicable. 82 */ getTitle(Context context)83 public String getTitle(Context context) { 84 return null; 85 } 86 87 /** 88 * Returns the content description for this wallpaper, or null if none exists. 89 */ getContentDescription(Context context)90 public String getContentDescription(Context context) { 91 return null; 92 } 93 94 /** 95 * @return The available attributions for this wallpaper, as a list of strings. These represent 96 * the author / website or any other attribution required to be displayed for this wallpaper 97 * regarding authorship, ownership, etc. 98 */ getAttributions(Context context)99 public abstract List<String> getAttributions(Context context); 100 101 /** 102 * Returns the base (remote) image URL for this wallpaper, or null if none exists. 103 */ getBaseImageUrl()104 public String getBaseImageUrl() { 105 return null; 106 } 107 108 /** 109 * Returns the action or "explore" URL for the wallpaper, or null if none exists. 110 */ getActionUrl(Context unused)111 public String getActionUrl(Context unused) { 112 return null; 113 } 114 115 /** Returns the URI corresponding to the wallpaper, or null if none exists. */ 116 @Nullable getImageWallpaperUri()117 public Uri getImageWallpaperUri() { 118 return null; 119 } 120 121 /** 122 * Returns the icon to use to represent the action link corresponding to 123 * {@link #getActionUrl(Context)} 124 */ 125 126 /** 127 * @param context 128 * @return An overlay icon to be used instead of a thumbnail, if appropriate, or null if not 129 * applicable. 130 */ getOverlayIcon(Context context)131 public Drawable getOverlayIcon(Context context) { 132 return null; 133 } 134 135 ; 136 137 @Override describeContents()138 public int describeContents() { 139 return 0; 140 } 141 142 /** 143 * @param context The client application's context. 144 * @return The {@link Asset} representing the wallpaper image. 145 */ getAsset(Context context)146 public abstract Asset getAsset(Context context); 147 148 /** 149 * @param context The client application's context. 150 * @return The {@link Asset} representing the wallpaper's thumbnail. 151 */ getThumbAsset(Context context)152 public abstract Asset getThumbAsset(Context context); 153 154 /** 155 * @param context The client application's context. 156 * @return An {@link Asset} that is appropriately sized to be directly set to the desktop. By 157 * default, this just the full wallpaper image asset (#getAsset) but subclasses may provide an 158 * Asset sized exactly for the device's primary display (i.e., cropped prior to providing a 159 * bitmap or input stream). 160 */ getDesktopAsset(Context context)161 public Asset getDesktopAsset(Context context) { 162 return getAsset(context); 163 } 164 165 /** 166 * @return the {@link android.app.WallpaperInfo} associated with this wallpaper, which is 167 * generally present for live wallpapers, or null if there is none. 168 */ getWallpaperComponent()169 public android.app.WallpaperInfo getWallpaperComponent() { 170 return null; 171 } 172 173 /** 174 * Returns the ID of the collection this image is associated with, if any. 175 */ getCollectionId(Context context)176 public abstract String getCollectionId(Context context); 177 178 /** 179 * Returns the ID of this wallpaper or null if there is no ID. 180 */ getWallpaperId()181 public String getWallpaperId() { 182 return null; 183 } 184 185 /** 186 * Returns the distinct ID of the stored wallpaper or null if there is no ID. 187 */ getStoredWallpaperId(Context context)188 public String getStoredWallpaperId(Context context) { 189 if (getWallpaperId() == null) { 190 return null; 191 } 192 return getCollectionId(context) + "-" + getWallpaperId(); 193 } 194 195 /** 196 * Returns whether backup is allowed for this wallpaper. 197 */ 198 @BackupPermission getBackupPermission()199 public int getBackupPermission() { 200 return BACKUP_ALLOWED; 201 } 202 203 /** 204 * Shows the appropriate preview activity for this WallpaperInfo. 205 * 206 * @param srcActivity 207 * @param factory A factory for showing the inline preview activity for within this app. 208 * Only used for certain WallpaperInfo implementations that require an inline preview 209 * (as opposed to some external preview activity). 210 * @param requestCode Request code to pass in when starting the inline preview activity. 211 */ showPreview(Activity srcActivity, InlinePreviewIntentFactory factory, int requestCode, boolean isAssetIdPresent)212 public abstract void showPreview(Activity srcActivity, InlinePreviewIntentFactory factory, 213 int requestCode, boolean isAssetIdPresent); 214 215 /** 216 * Shows the appropriate preview activity for this WallpaperInfo. 217 * 218 * @param factory A factory for showing the inline preview activity for within 219 * this app. 220 * Only used for certain WallpaperInfo implementations that 221 * require 222 * an inline preview 223 * (as opposed to some external preview activity). 224 * @param requestCode Request code to pass in when starting the inline preview 225 * activity. 226 * @param shouldRefreshCategory category type to pass in when starting the inline preview 227 * activity. 228 */ showPreview(Activity srcActivity, InlinePreviewIntentFactory factory, int requestCode, boolean isAssetIdPresent, boolean shouldRefreshCategory)229 public abstract void showPreview(Activity srcActivity, InlinePreviewIntentFactory factory, 230 int requestCode, boolean isAssetIdPresent, 231 boolean shouldRefreshCategory); 232 233 /** 234 * Returns a Future to obtain a wallpaper color and a placeholder color calculated in a 235 * background thread for this wallpaper's thumbnail. 236 * If it's already available, the Future will return the color immediately. 237 * This is intended to be a "best effort" attempt and might not obtain a color if no low res 238 * thumbnail is available. 239 */ computeColorInfo(Context context)240 public Future<ColorInfo> computeColorInfo(Context context) { 241 if (mColorInfo.getWallpaperColors() != null 242 && mColorInfo.getPlaceholderColor() != Color.TRANSPARENT) { 243 return CompletableFuture.completedFuture(mColorInfo); 244 } 245 final Context appContext = context.getApplicationContext(); 246 return sExecutor.submit(() -> { 247 synchronized (WallpaperInfo.this) { 248 if (mColorInfo.getWallpaperColors() != null 249 && mColorInfo.getPlaceholderColor() != Color.TRANSPARENT) { 250 return mColorInfo; 251 } 252 253 Asset thumbAsset = getThumbAsset(appContext); 254 Bitmap lowResBitmap = thumbAsset.getLowResBitmap(appContext); 255 if (lowResBitmap == null) { 256 return new ColorInfo( 257 new WallpaperColors(Color.valueOf(Color.TRANSPARENT), null, null), 258 Color.TRANSPARENT); 259 } 260 mColorInfo = new ColorInfo(WallpaperColors.fromBitmap(lowResBitmap)); 261 return mColorInfo; 262 } 263 }); 264 } 265 266 /** 267 * Remove the effect name from this wallpaper, only use it for logging. 268 */ 269 public void removeEffectName(String effect) { 270 mEffectNames.remove(effect); 271 } 272 273 /** 274 * Add the effect name apply with this wallpaper, only use it for logging. 275 */ 276 public void addEffectName(String effect) { 277 mEffectNames.add(effect); 278 } 279 280 /** 281 * Returns the effects apply with this wallpaper. 282 */ 283 public String getEffectNames() { 284 if (mEffectNames.isEmpty()) { 285 return null; 286 } 287 String effectNames = ""; 288 Iterator value = mEffectNames.iterator(); 289 while (value.hasNext()) { 290 if (!effectNames.isEmpty()) { 291 effectNames += ","; 292 } 293 effectNames += value.next(); 294 } 295 296 return effectNames; 297 } 298 299 /** 300 * Whether backup is allowed for this type of wallpaper. 301 */ 302 @IntDef({ 303 BACKUP_NOT_ALLOWED, 304 BACKUP_ALLOWED 305 }) 306 public @interface BackupPermission { 307 } 308 309 /** 310 * Returns a group name under which this Wallpaper should be grouped when displayed in 311 * a gallery, or an empty String if no grouping is required. 312 */ 313 public String getGroupName(Context context) { 314 return ""; 315 } 316 317 /** 318 * Returns the resource id of a drawable to use as a badge when displaying this wallpaper 319 * in a gallery, or {@link Resources#ID_NULL} if no badge is required. 320 */ 321 @DrawableRes 322 public int getBadgeDrawableRes() { 323 return Resources.ID_NULL; 324 } 325 326 /** Sets the crop {@link Rect} of each displaySize for this wallpaper. */ 327 public void setWallpaperCropHints(Map<Point, Rect> cropHints) { 328 if (cropHints == null) { 329 return; 330 } 331 332 cropHints.forEach((displaySize, rect) -> { 333 if (rect != null) { 334 mCropHints.put(displaySize.flattenToString(), 335 rect.flattenToString()); 336 } 337 }); 338 } 339 340 /** Returns the crop {@link Rect} of each displaySize for this wallpaper. */ 341 public @Nullable Map<Point, Rect> getWallpaperCropHints() { 342 BaseFlags flags = InjectorProvider.getInjector().getFlags(); 343 if (!flags.isMultiCropEnabled()) { 344 return null; 345 } 346 347 Map<Point, Rect> cropHints = new HashMap<>(); 348 mCropHints.forEach( 349 (displaySize, rect) -> cropHints.put( 350 Point.unflattenFromString(displaySize), 351 Rect.unflattenFromString(rect))); 352 return cropHints; 353 } 354 355 /** 356 * Inner class to keep wallpaper colors and placeholder color. 357 */ 358 public static class ColorInfo { 359 private WallpaperColors mWallpaperColors; 360 private Integer mPlaceholderColor = Color.TRANSPARENT; 361 362 public ColorInfo() { 363 } 364 365 public ColorInfo(WallpaperColors wallpaperColors) { 366 mWallpaperColors = wallpaperColors; 367 if (mWallpaperColors != null) { 368 mPlaceholderColor = mWallpaperColors.getPrimaryColor().toArgb(); 369 } 370 } 371 372 public ColorInfo(WallpaperColors wallpaperColors, Integer placeholderColor) { 373 mWallpaperColors = wallpaperColors; 374 mPlaceholderColor = placeholderColor; 375 } 376 377 public WallpaperColors getWallpaperColors() { 378 return mWallpaperColors; 379 } 380 381 public Integer getPlaceholderColor() { 382 return mPlaceholderColor; 383 } 384 } 385 386 public ColorInfo getColorInfo() { 387 return mColorInfo; 388 } 389 } 390