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.asset; 17 18 import android.annotation.TargetApi; 19 import android.app.Activity; 20 import android.app.WallpaperManager; 21 import android.content.Context; 22 import android.graphics.Bitmap; 23 import android.graphics.Point; 24 import android.graphics.Rect; 25 import android.graphics.drawable.BitmapDrawable; 26 import android.graphics.drawable.ColorDrawable; 27 import android.graphics.drawable.Drawable; 28 import android.os.Build; 29 import android.os.Build.VERSION; 30 import android.os.Build.VERSION_CODES; 31 import android.os.Handler; 32 import android.os.Looper; 33 import android.widget.ImageView; 34 35 import com.bumptech.glide.Glide; 36 import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions; 37 import com.bumptech.glide.request.RequestOptions; 38 39 import java.util.concurrent.ExecutorService; 40 import java.util.concurrent.Executors; 41 42 /** 43 * Asset representing the system's built-in wallpaper. 44 * NOTE: This is only used for KitKat and newer devices. On older versions of Android, the 45 * built-in wallpaper is accessed via the system Resources object, and is thus be represented 46 * by a {@code ResourceAsset} instead. 47 */ 48 @TargetApi(Build.VERSION_CODES.KITKAT) 49 public final class BuiltInWallpaperAsset extends Asset { 50 private static final ExecutorService sExecutorService = Executors.newCachedThreadPool(); 51 private static final boolean SCALE_TO_FIT = true; 52 private static final boolean CROP_TO_FIT = false; 53 private static final float HORIZONTAL_CENTER_ALIGNED = 0.5f; 54 private static final float VERTICAL_CENTER_ALIGNED = 0.5f; 55 56 private final Context mContext; 57 58 private Point mDimensions; 59 private WallpaperModel mBuiltInWallpaperModel; 60 61 /** 62 * @param context The application's context. 63 */ BuiltInWallpaperAsset(Context context)64 public BuiltInWallpaperAsset(Context context) { 65 if (VERSION.SDK_INT < VERSION_CODES.KITKAT) { 66 throw new AssertionError("BuiltInWallpaperAsset should not be instantiated on a pre-KitKat" 67 + " build"); 68 } 69 70 mContext = context.getApplicationContext(); 71 } 72 73 @Override decodeBitmapRegion(Rect rect, int targetWidth, int targetHeight, boolean shouldAdjustForRtl, BitmapReceiver receiver)74 public void decodeBitmapRegion(Rect rect, int targetWidth, int targetHeight, 75 boolean shouldAdjustForRtl, BitmapReceiver receiver) { 76 sExecutorService.execute(() -> { 77 Point dimensions = calculateRawDimensions(); 78 79 float horizontalCenter = BitmapUtils.calculateHorizontalAlignment(dimensions, rect); 80 float verticalCenter = BitmapUtils.calculateVerticalAlignment(dimensions, rect); 81 82 Drawable drawable = WallpaperManager.getInstance(mContext).getBuiltInDrawable( 83 rect.width(), 84 rect.height(), 85 CROP_TO_FIT, 86 horizontalCenter, 87 verticalCenter); 88 Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); 89 decodeBitmapCompleted(receiver, bitmap); 90 }); 91 } 92 93 @Override decodeRawDimensions(Activity unused, DimensionsReceiver receiver)94 public void decodeRawDimensions(Activity unused, DimensionsReceiver receiver) { 95 sExecutorService.execute(() -> { 96 Point dimensions = calculateRawDimensions(); 97 new Handler(Looper.getMainLooper()).post( 98 () -> receiver.onDimensionsDecoded(dimensions)); 99 }); 100 } 101 102 @Override decodeBitmap(int targetWidth, int targetHeight, boolean useHardwareBitmapIfPossible, BitmapReceiver receiver)103 public void decodeBitmap(int targetWidth, int targetHeight, boolean useHardwareBitmapIfPossible, 104 BitmapReceiver receiver) { 105 sExecutorService.execute(() -> { 106 final WallpaperManager wallpaperManager = WallpaperManager.getInstance(mContext); 107 108 Drawable drawable = (targetWidth <= 0 || targetHeight <= 0) 109 ? wallpaperManager.getBuiltInDrawable() 110 : wallpaperManager.getBuiltInDrawable( 111 targetWidth, 112 targetHeight, 113 SCALE_TO_FIT, 114 HORIZONTAL_CENTER_ALIGNED, 115 VERTICAL_CENTER_ALIGNED); 116 117 // Manually request that WallpaperManager loses its reference to the built-in wallpaper 118 // bitmap, which can occupy a large memory allocation for the lifetime of the app. 119 wallpaperManager.forgetLoadedWallpaper(); 120 121 Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap(); 122 decodeBitmapCompleted(receiver, bitmap); 123 }); 124 } 125 126 @Override decodeBitmap(BitmapReceiver receiver)127 public void decodeBitmap(BitmapReceiver receiver) { 128 decodeBitmap(0, 0, receiver); 129 } 130 131 @Override supportsTiling()132 public boolean supportsTiling() { 133 return false; 134 } 135 136 /** 137 * Calculates the raw dimensions of the built-in drawable. This method should not be called from 138 * the main UI thread. 139 * 140 * @return Raw dimensions of the built-in wallpaper drawable. 141 */ calculateRawDimensions()142 private Point calculateRawDimensions() { 143 if (mDimensions != null) { 144 return mDimensions; 145 } 146 147 Drawable builtInDrawable = WallpaperManager.getInstance(mContext).getBuiltInDrawable(); 148 Bitmap builtInBitmap = ((BitmapDrawable) builtInDrawable).getBitmap(); 149 mDimensions = new Point(builtInBitmap.getWidth(), builtInBitmap.getHeight()); 150 return mDimensions; 151 } 152 153 @Override loadDrawable(Context context, ImageView imageView, int placeholderColor)154 public void loadDrawable(Context context, ImageView imageView, int placeholderColor) { 155 if (mBuiltInWallpaperModel == null) { 156 mBuiltInWallpaperModel = 157 new WallpaperModel(context.getApplicationContext(), WallpaperModel.SOURCE_BUILT_IN); 158 } 159 160 Glide.with(context) 161 .asDrawable() 162 .load(mBuiltInWallpaperModel) 163 .apply(RequestOptions.centerCropTransform() 164 .placeholder(new ColorDrawable(placeholderColor))) 165 .transition(DrawableTransitionOptions.withCrossFade()) 166 .into(imageView); 167 } 168 } 169