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 static android.app.WallpaperManager.SetWallpaperFlags;
19 
20 import android.app.Activity;
21 import android.app.WallpaperManager;
22 import android.content.Context;
23 import android.graphics.Bitmap;
24 import android.graphics.Point;
25 import android.graphics.Rect;
26 import android.graphics.drawable.ColorDrawable;
27 import android.os.ParcelFileDescriptor;
28 import android.os.ParcelFileDescriptor.AutoCloseInputStream;
29 import android.util.Log;
30 import android.widget.ImageView;
31 
32 import androidx.annotation.WorkerThread;
33 
34 import com.android.wallpaper.util.WallpaperCropUtils;
35 
36 import com.bumptech.glide.Glide;
37 import com.bumptech.glide.load.Key;
38 import com.bumptech.glide.load.MultiTransformation;
39 import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
40 import com.bumptech.glide.load.resource.bitmap.FitCenter;
41 import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
42 import com.bumptech.glide.request.RequestOptions;
43 
44 import java.io.InputStream;
45 import java.security.MessageDigest;
46 import java.util.concurrent.ExecutionException;
47 
48 /**
49  * Asset representing the currently-set image wallpaper, including when daily rotation
50  * is set with a static wallpaper (but not when daily rotation uses a live wallpaper).
51  */
52 public class CurrentWallpaperAsset extends StreamableAsset {
53 
54     private static final String TAG = "CurrentWallpaperAsset";
55     int mWallpaperId;
56     private final WallpaperManager mWallpaperManager;
57     @SetWallpaperFlags
58     private final int mWallpaperManagerFlag;
59 
60     private final boolean mCropped;
61 
CurrentWallpaperAsset(Context context, @SetWallpaperFlags int wallpaperManagerFlag, boolean getCropped)62     public CurrentWallpaperAsset(Context context, @SetWallpaperFlags int wallpaperManagerFlag,
63             boolean getCropped) {
64         mWallpaperManager = WallpaperManager.getInstance(context.getApplicationContext());
65         mWallpaperManagerFlag = wallpaperManagerFlag;
66         mWallpaperId = mWallpaperManager.getWallpaperId(mWallpaperManagerFlag);
67         mCropped = getCropped;
68     }
69 
70     @Override
openInputStream()71     protected InputStream openInputStream() {
72         ParcelFileDescriptor pfd = getWallpaperPfd();
73 
74         if (pfd == null) {
75             Log.e(TAG, "ParcelFileDescriptor for wallpaper " + mWallpaperManagerFlag
76                     + " is null, unable to open InputStream.");
77             return null;
78         }
79 
80         return new AutoCloseInputStream(pfd);
81     }
82 
83     @Override
hashCode()84     public int hashCode() {
85         int result = 17;
86         result = result * 31 + mWallpaperManagerFlag;
87         result = result * 31 + mWallpaperId;
88         return result;
89     }
90 
91     @Override
equals(Object object)92     public boolean equals(Object object) {
93         if (object instanceof CurrentWallpaperAsset) {
94             CurrentWallpaperAsset otherAsset = (CurrentWallpaperAsset) object;
95             return otherAsset.mWallpaperManagerFlag == mWallpaperManagerFlag
96                     && otherAsset.mWallpaperId == mWallpaperId;
97 
98         }
99         return false;
100     }
101 
102 
103     @Override
loadLowResDrawable(Activity activity, ImageView imageView, int placeholderColor, BitmapTransformation transformation)104     public void loadLowResDrawable(Activity activity, ImageView imageView, int placeholderColor,
105             BitmapTransformation transformation) {
106         MultiTransformation<Bitmap> multiTransformation =
107                 new MultiTransformation<>(new FitCenter(), transformation);
108         Glide.with(activity)
109                 .asDrawable()
110                 .load(this)
111                 .apply(RequestOptions.bitmapTransform(multiTransformation)
112                         .placeholder(new ColorDrawable(placeholderColor)))
113                 .into(imageView);
114     }
115 
116     @Override
117     @WorkerThread
getLowResBitmap(Context context)118     public Bitmap getLowResBitmap(Context context) {
119         try {
120             return Glide.with(context)
121                     .asBitmap()
122                     .load(this)
123                     .submit()
124                     .get();
125         } catch (InterruptedException | ExecutionException e) {
126             Log.w(TAG, "Couldn't obtain low res bitmap", e);
127         }
128         return null;
129     }
130 
131     @Override
loadDrawable(Context context, ImageView imageView, int unusedPlaceholderColor)132     public void loadDrawable(Context context, ImageView imageView,
133                              int unusedPlaceholderColor) {
134         Glide.with(context)
135                 .asDrawable()
136                 .load(CurrentWallpaperAsset.this)
137                 .apply(RequestOptions.centerCropTransform())
138                 .transition(DrawableTransitionOptions.withCrossFade())
139                 .into(imageView);
140     }
141 
142     @Override
adjustCropRect(Context context, Point assetDimensions, Rect cropRect, boolean offsetToStart)143     protected void adjustCropRect(Context context, Point assetDimensions, Rect cropRect,
144             boolean offsetToStart) {
145         if (offsetToStart) {
146             cropRect.offsetTo(0, 0);
147         }
148         WallpaperCropUtils.adjustCurrentWallpaperCropRect(context, assetDimensions, cropRect);
149     }
150 
getKey()151     public Key getKey() {
152         return new CurrentWallpaperKey(mWallpaperManager, mWallpaperManagerFlag);
153     }
154 
getWallpaperPfd()155     ParcelFileDescriptor getWallpaperPfd() {
156         return mWallpaperManager.getWallpaperFile(mWallpaperManagerFlag, mCropped);
157     }
158 
159     /**
160      * Glide caching key for currently-set wallpapers using wallpaper IDs provided by
161      * WallpaperManager.
162      */
163     private static final class CurrentWallpaperKey implements Key {
164         private final WallpaperManager mWallpaperManager;
165         @SetWallpaperFlags
166         private final int mWallpaperFlag;
167 
CurrentWallpaperKey(WallpaperManager wallpaperManager, @SetWallpaperFlags int wallpaperFlag)168         CurrentWallpaperKey(WallpaperManager wallpaperManager,
169                 @SetWallpaperFlags int wallpaperFlag) {
170             mWallpaperManager = wallpaperManager;
171             mWallpaperFlag = wallpaperFlag;
172         }
173 
174         @Override
toString()175         public String toString() {
176             return getCacheKey();
177         }
178 
179         @Override
hashCode()180         public int hashCode() {
181             return getCacheKey().hashCode();
182         }
183 
184         @Override
equals(Object object)185         public boolean equals(Object object) {
186             if (object instanceof CurrentWallpaperKey) {
187                 CurrentWallpaperKey otherKey = (CurrentWallpaperKey) object;
188                 return getCacheKey().equals(otherKey.getCacheKey());
189 
190             }
191             return false;
192         }
193 
194         @Override
updateDiskCacheKey(MessageDigest messageDigest)195         public void updateDiskCacheKey(MessageDigest messageDigest) {
196             messageDigest.update(getCacheKey().getBytes(CHARSET));
197         }
198 
199         /**
200          * Returns an inexpensively calculated {@link String} suitable for use as a disk cache key.
201          */
getCacheKey()202         private String getCacheKey() {
203             return "CurrentWallpaperKey{"
204                     + "flag=" + mWallpaperFlag
205                     + ",id=" + mWallpaperManager.getWallpaperId(mWallpaperFlag)
206                     + '}';
207         }
208     }
209 }
210