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