• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.module;
17 
18 import static android.app.WallpaperManager.FLAG_LOCK;
19 import static android.app.WallpaperManager.FLAG_SYSTEM;
20 
21 import android.annotation.SuppressLint;
22 import android.app.WallpaperManager;
23 import android.content.Context;
24 import android.graphics.Bitmap;
25 import android.graphics.BitmapFactory;
26 import android.graphics.drawable.BitmapDrawable;
27 import android.os.AsyncTask;
28 import android.os.ParcelFileDescriptor;
29 import android.util.Log;
30 
31 import com.android.wallpaper.R;
32 import com.android.wallpaper.asset.BitmapUtils;
33 import com.android.wallpaper.model.LiveWallpaperMetadata;
34 import com.android.wallpaper.model.WallpaperMetadata;
35 
36 import java.io.FileInputStream;
37 import java.io.IOException;
38 import java.io.InputStream;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42 
43 /**
44  * Default implementation of {@link WallpaperRefresher} which refreshes wallpaper metadata
45  * asynchronously.
46  */
47 @SuppressLint("ServiceCast")
48 public class DefaultWallpaperRefresher implements WallpaperRefresher {
49 
50     private static final String TAG = "DefaultWPRefresher";
51 
52     private final Context mAppContext;
53     private final WallpaperPreferences mWallpaperPreferences;
54     private final WallpaperManager mWallpaperManager;
55     private final WallpaperStatusChecker mWallpaperStatusChecker;
56 
57     /**
58      * @param context The application's context.
59      */
DefaultWallpaperRefresher(Context context)60     public DefaultWallpaperRefresher(Context context) {
61         mAppContext = context.getApplicationContext();
62 
63         Injector injector = InjectorProvider.getInjector();
64         mWallpaperPreferences = injector.getPreferences(mAppContext);
65         mWallpaperStatusChecker = injector.getWallpaperStatusChecker(context);
66 
67         // Retrieve WallpaperManager using Context#getSystemService instead of
68         // WallpaperManager#getInstance so it can be mocked out in test.
69         mWallpaperManager = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
70     }
71 
72     @Override
refresh(RefreshListener listener)73     public void refresh(RefreshListener listener) {
74         GetWallpaperMetadataAsyncTask task = new GetWallpaperMetadataAsyncTask(listener);
75         task.execute();
76     }
77 
78     /**
79      * Retrieves the current wallpaper's thumbnail and metadata off the UI thread.
80      */
81     private class GetWallpaperMetadataAsyncTask extends
82             AsyncTask<Void, Void, List<WallpaperMetadata>> {
83 
84         private final RefreshListener mListener;
85         private final WallpaperManager mWallpaperManager;
86 
87         private long mCurrentHomeWallpaperHashCode;
88         private long mCurrentLockWallpaperHashCode;
89         private String mSystemWallpaperServiceName;
90 
91         @SuppressLint("ServiceCast")
GetWallpaperMetadataAsyncTask(RefreshListener listener)92         public GetWallpaperMetadataAsyncTask(RefreshListener listener) {
93             mListener = listener;
94             mWallpaperManager = WallpaperManager.getInstance(mAppContext);
95         }
96 
97         @Override
doInBackground(Void... unused)98         protected List<WallpaperMetadata> doInBackground(Void... unused) {
99             List<WallpaperMetadata> wallpaperMetadatas = new ArrayList<>();
100 
101             boolean isHomeScreenStatic = mWallpaperManager.getWallpaperInfo(FLAG_SYSTEM) == null;
102             if (!isHomeScreenMetadataCurrent() || (isHomeScreenStatic
103                     && isHomeScreenAttributionsEmpty())) {
104                 mWallpaperPreferences.clearHomeWallpaperMetadata();
105                 setFallbackHomeScreenWallpaperMetadata();
106             }
107 
108             boolean isLockScreenWallpaperCurrentlySet =
109                     mWallpaperStatusChecker.isLockWallpaperSet();
110 
111             if (mWallpaperManager.getWallpaperInfo() == null) {
112                 wallpaperMetadatas.add(new WallpaperMetadata(
113                         mWallpaperPreferences.getHomeWallpaperAttributions(),
114                         mWallpaperPreferences.getHomeWallpaperActionUrl(),
115                         mWallpaperPreferences.getHomeWallpaperActionLabelRes(),
116                         mWallpaperPreferences.getHomeWallpaperActionIconRes(),
117                         mWallpaperPreferences.getHomeWallpaperCollectionId(),
118                         mWallpaperPreferences.getHomeWallpaperBackingFileName(),
119                         null));
120             } else {
121                 wallpaperMetadatas.add(
122                         new LiveWallpaperMetadata(mWallpaperManager.getWallpaperInfo()));
123             }
124 
125             // Return only home metadata if pre-N device or lock screen wallpaper is not explicitly
126             // set.
127             if (!isLockScreenWallpaperCurrentlySet) {
128                 return wallpaperMetadatas;
129             }
130 
131             boolean isLockScreenStatic = mWallpaperManager.getWallpaperInfo(FLAG_LOCK) == null;
132             if (!isLockScreenMetadataCurrent() || (isLockScreenStatic
133                     && isLockScreenAttributionsEmpty())) {
134                 mWallpaperPreferences.clearLockWallpaperMetadata();
135                 setFallbackLockScreenWallpaperMetadata();
136             }
137 
138             if (mWallpaperManager.getWallpaperInfo(FLAG_LOCK) == null
139                     || !mWallpaperManager.isLockscreenLiveWallpaperEnabled()) {
140                 wallpaperMetadatas.add(new WallpaperMetadata(
141                         mWallpaperPreferences.getLockWallpaperAttributions(),
142                         mWallpaperPreferences.getLockWallpaperActionUrl(),
143                         mWallpaperPreferences.getLockWallpaperActionLabelRes(),
144                         mWallpaperPreferences.getLockWallpaperActionIconRes(),
145                         mWallpaperPreferences.getLockWallpaperCollectionId(),
146                         mWallpaperPreferences.getLockWallpaperBackingFileName(),
147                         null));
148             } else {
149                 wallpaperMetadatas.add(new LiveWallpaperMetadata(
150                         mWallpaperManager.getWallpaperInfo(FLAG_LOCK)));
151             }
152 
153             return wallpaperMetadatas;
154         }
155 
156         @Override
onPostExecute(List<WallpaperMetadata> metadatas)157         protected void onPostExecute(List<WallpaperMetadata> metadatas) {
158             if (metadatas.size() > 2) {
159                 Log.e(TAG,
160                         "Got more than 2 WallpaperMetadata objects - only home and (optionally) "
161                                 + "lock are permitted.");
162                 return;
163             }
164 
165             mListener.onRefreshed(metadatas.get(0), metadatas.size() > 1 ? metadatas.get(1) : null,
166                     mWallpaperPreferences.getWallpaperPresentationMode());
167         }
168 
169         /**
170          * Sets fallback wallpaper attributions to WallpaperPreferences when the saved metadata did
171          * not match the system wallpaper. For live wallpapers, loads the label (title) but for
172          * image wallpapers loads a generic title string.
173          */
setFallbackHomeScreenWallpaperMetadata()174         private void setFallbackHomeScreenWallpaperMetadata() {
175             android.app.WallpaperInfo wallpaperComponent = mWallpaperManager.getWallpaperInfo();
176             if (wallpaperComponent == null) { // Image wallpaper
177                 mWallpaperPreferences.setHomeWallpaperAttributions(
178                         Arrays.asList(mAppContext.getResources()
179                                 .getString(R.string.fallback_wallpaper_title)));
180 
181                 mWallpaperPreferences.setHomeWallpaperManagerId(
182                         mWallpaperManager.getWallpaperId(FLAG_SYSTEM));
183             } else { // Live wallpaper
184                 mWallpaperPreferences.setHomeWallpaperAttributions(Arrays.asList(
185                         wallpaperComponent.loadLabel(mAppContext.getPackageManager()).toString()));
186                 mWallpaperPreferences.setHomeWallpaperServiceName(mSystemWallpaperServiceName);
187             }
188 
189             // Disable rotation wallpaper when setting fallback home screen wallpaper
190             // Daily rotation wallpaper only rotates the home screen wallpaper
191             mWallpaperPreferences.setWallpaperPresentationMode(
192                     WallpaperPreferences.PRESENTATION_MODE_STATIC);
193             mWallpaperPreferences.clearDailyRotations();
194         }
195 
196         /**
197          * Sets fallback lock screen wallpaper attributions to WallpaperPreferences. This should be
198          * called when the saved lock screen wallpaper metadata does not match the currently set
199          * lock screen wallpaper.
200          */
setFallbackLockScreenWallpaperMetadata()201         private void setFallbackLockScreenWallpaperMetadata() {
202             mWallpaperPreferences.setLockWallpaperAttributions(
203                     Arrays.asList(mAppContext.getResources()
204                             .getString(R.string.fallback_wallpaper_title)));
205             mWallpaperPreferences.setLockWallpaperManagerId(mWallpaperManager.getWallpaperId(
206                     FLAG_LOCK));
207         }
208 
209         /**
210          * Returns whether the home screen metadata saved in WallpaperPreferences corresponds to the
211          * current system wallpaper.
212          */
isHomeScreenMetadataCurrent()213         private boolean isHomeScreenMetadataCurrent() {
214             return (mWallpaperManager.getWallpaperInfo() == null)
215                     ? isHomeScreenImageWallpaperCurrent()
216                     : isHomeScreenLiveWallpaperCurrent();
217         }
218 
219         /**
220          * Returns whether the home screen attributions saved in WallpaperPreferences is empty.
221          */
isHomeScreenAttributionsEmpty()222         private boolean isHomeScreenAttributionsEmpty() {
223             List<String> homeScreenAttributions =
224                     mWallpaperPreferences.getHomeWallpaperAttributions();
225             return homeScreenAttributions.get(0) == null
226                     && homeScreenAttributions.get(1) == null
227                     && homeScreenAttributions.get(2) == null;
228         }
229 
getCurrentHomeWallpaperHashCode()230         private long getCurrentHomeWallpaperHashCode() {
231             if (mCurrentHomeWallpaperHashCode == 0) {
232                 BitmapDrawable wallpaperDrawable = (BitmapDrawable) mWallpaperManager.getDrawable();
233                 // wallpaperDrawable should always be non-null, unless if there's a error in
234                 // WallpaperManager's state, in which case we'll consider the hashcode as unset.
235                 Bitmap wallpaperBitmap = wallpaperDrawable != null ? wallpaperDrawable.getBitmap()
236                         : null;
237                 mCurrentHomeWallpaperHashCode =
238                         wallpaperBitmap != null ? BitmapUtils.generateHashCode(wallpaperBitmap) : 0;
239 
240                 // Manually request that WallpaperManager loses its reference to the current
241                 // wallpaper bitmap, which can occupy a large memory allocation for the lifetime of
242                 // the app.
243                 mWallpaperManager.forgetLoadedWallpaper();
244             }
245             return mCurrentHomeWallpaperHashCode;
246         }
247 
getCurrentLockWallpaperHashCode()248         private long getCurrentLockWallpaperHashCode() {
249             if (mCurrentLockWallpaperHashCode == 0
250                     && mWallpaperStatusChecker.isLockWallpaperSet()) {
251                 Bitmap wallpaperBitmap = getLockWallpaperBitmap();
252                 // If isLockWallpaperSet() returned true, wallpaperBitmap should always be
253                 // non-null, unless if there's a error in WallpaperManager, in which case we'll
254                 // consider the hashcode as unset.
255                 mCurrentLockWallpaperHashCode =
256                         wallpaperBitmap != null ? BitmapUtils.generateHashCode(wallpaperBitmap) : 0;
257             }
258             return mCurrentLockWallpaperHashCode;
259         }
260 
261         /**
262          * Returns the lock screen wallpaper currently set on the device as a Bitmap, or null if no
263          * lock screen wallpaper is set.
264          */
getLockWallpaperBitmap()265         private Bitmap getLockWallpaperBitmap() {
266             Bitmap lockBitmap = null;
267 
268             ParcelFileDescriptor pfd = mWallpaperManager.getWallpaperFile(FLAG_LOCK);
269             // getWallpaperFile returns null if the lock screen isn't explicitly set, so need this
270             // check.
271             if (pfd != null) {
272                 InputStream fileStream = null;
273                 try {
274                     fileStream = new FileInputStream(pfd.getFileDescriptor());
275                     lockBitmap = BitmapFactory.decodeStream(fileStream);
276                     pfd.close();
277                     return lockBitmap;
278                 } catch (IOException e) {
279                     Log.e(TAG, "IO exception when closing the file descriptor.");
280                 } finally {
281                     if (fileStream != null) {
282                         try {
283                             fileStream.close();
284                         } catch (IOException e) {
285                             Log.e(TAG,
286                                     "IO exception when closing input stream for lock screen WP.");
287                         }
288                     }
289                 }
290             }
291 
292             return lockBitmap;
293         }
294 
295         /**
296          * Returns whether the image wallpaper set to the system matches the metadata in
297          * WallpaperPreferences.
298          */
isHomeScreenImageWallpaperCurrent()299         private boolean isHomeScreenImageWallpaperCurrent() {
300             return mWallpaperPreferences.getHomeWallpaperManagerId()
301                     == mWallpaperManager.getWallpaperId(FLAG_SYSTEM);
302         }
303 
304         /**
305          * Returns whether the live wallpaper set to the system's home screen matches the metadata
306          * in WallpaperPreferences.
307          */
isHomeScreenLiveWallpaperCurrent()308         private boolean isHomeScreenLiveWallpaperCurrent() {
309             mSystemWallpaperServiceName = mWallpaperManager.getWallpaperInfo().getServiceName();
310             String homeWallpaperServiceName = mWallpaperPreferences.getHomeWallpaperServiceName();
311             return mSystemWallpaperServiceName.equals(homeWallpaperServiceName);
312         }
313 
314         /**
315          * Returns whether the lock screen metadata saved in WallpaperPreferences corresponds to the
316          * current lock screen wallpaper.
317          */
isLockScreenMetadataCurrent()318         private boolean isLockScreenMetadataCurrent() {
319             return (mWallpaperManager.getWallpaperInfo(FLAG_LOCK) == null)
320                     ? isLockScreenImageWallpaperCurrent()
321                     : isLockScreenLiveWallpaperCurrent();
322         }
323 
324         /**
325          * Returns whether the image wallpaper set for the lock screen matches the metadata in
326          * WallpaperPreferences.
327          */
isLockScreenImageWallpaperCurrent()328         private boolean isLockScreenImageWallpaperCurrent() {
329             // Check for lock wallpaper image same-ness only when there is no stored lock wallpaper
330             // hash code. Otherwise if there is a lock wallpaper hash code stored in
331             // {@link WallpaperPreferences}, then check hash codes.
332             long savedLockWallpaperHash = mWallpaperPreferences.getLockWallpaperHashCode();
333 
334             if (savedLockWallpaperHash == 0) {
335                 return mWallpaperPreferences.getLockWallpaperManagerId()
336                         == mWallpaperManager.getWallpaperId(FLAG_LOCK);
337             } else {
338                 return savedLockWallpaperHash == getCurrentLockWallpaperHashCode();
339             }
340         }
341 
342         /**
343          * Returns whether the live wallpaper for the home screen matches the metadata in
344          * WallpaperPreferences.
345          */
isLockScreenLiveWallpaperCurrent()346         private boolean isLockScreenLiveWallpaperCurrent() {
347             String currentServiceName = mWallpaperManager.getWallpaperInfo(FLAG_LOCK)
348                     .getServiceName();
349             String storedServiceName = mWallpaperPreferences.getLockWallpaperServiceName();
350             return currentServiceName.equals(storedServiceName);
351         }
352 
353 
354         /**
355          * Returns whether the lock screen attributions saved in WallpaperPreferences are empty.
356          */
isLockScreenAttributionsEmpty()357         private boolean isLockScreenAttributionsEmpty() {
358             List<String> attributions = mWallpaperPreferences.getLockWallpaperAttributions();
359             return attributions.get(0) == null
360                     && attributions.get(1) == null
361                     && attributions.get(2) == null;
362         }
363     }
364 }
365