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 android.app.WallpaperManager;
19 import android.content.ComponentName;
20 import android.content.Context;
21 import android.graphics.Point;
22 
23 import androidx.annotation.Nullable;
24 
25 import com.android.wallpaper.config.BaseFlags;
26 import com.android.wallpaper.model.CreativeWallpaperInfo;
27 import com.android.wallpaper.model.CurrentWallpaperInfo;
28 import com.android.wallpaper.model.DefaultWallpaperInfo;
29 import com.android.wallpaper.model.LiveWallpaperMetadata;
30 import com.android.wallpaper.model.WallpaperInfo;
31 import com.android.wallpaper.model.WallpaperMetadata;
32 import com.android.wallpaper.module.WallpaperPreferences.PresentationMode;
33 import com.android.wallpaper.picker.customization.data.content.WallpaperClient;
34 import com.android.wallpaper.util.DisplayUtils;
35 
36 import java.util.HashMap;
37 import java.util.List;
38 
39 /**
40  * Default implementation of {@link CurrentWallpaperInfoFactory} which actually constructs
41  * {@link WallpaperInfo} instances representing the wallpapers currently set to the device.
42  */
43 public class DefaultCurrentWallpaperInfoFactory implements CurrentWallpaperInfoFactory {
44 
45     private final WallpaperRefresher mWallpaperRefresher;
46     private final LiveWallpaperInfoFactory mLiveWallpaperInfoFactory;
47 
48     // Cached copies of the currently-set WallpaperInfo(s) and presentation mode.
49     private WallpaperInfo mHomeWallpaper;
50     @Nullable
51     private WallpaperInfo mLockWallpaper;
52     @PresentationMode
53     private int mPresentationMode;
54 
DefaultCurrentWallpaperInfoFactory(WallpaperRefresher wallpaperRefresher, LiveWallpaperInfoFactory liveWallpaperInfoFactory)55     public DefaultCurrentWallpaperInfoFactory(WallpaperRefresher wallpaperRefresher,
56             LiveWallpaperInfoFactory liveWallpaperInfoFactory) {
57         mWallpaperRefresher = wallpaperRefresher;
58         mLiveWallpaperInfoFactory = liveWallpaperInfoFactory;
59     }
60 
61     @Override
createCurrentWallpaperInfos(Context context, boolean forceRefresh, WallpaperInfoCallback callback)62     public synchronized void createCurrentWallpaperInfos(Context context, boolean forceRefresh,
63             WallpaperInfoCallback callback) {
64 
65         BaseFlags flags = InjectorProvider.getInjector().getFlags();
66         final boolean isMultiCropEnabled = flags.isMultiCropEnabled();
67 
68         boolean isHomeWallpaperSynced  = homeWallpaperSynced(context);
69         boolean isLockWallpaperSynced  = lockWallpaperSynced(context);
70         if (!forceRefresh && isHomeWallpaperSynced && isLockWallpaperSynced
71                 && mPresentationMode != WallpaperPreferences.PRESENTATION_MODE_ROTATING) {
72             // Update wallpaper crop hints for static wallpaper even if home & lock wallpaper are
73             // considered synced because wallpaper info are considered synced as long as both are
74             // static
75             if (isMultiCropEnabled) {
76                 DisplayUtils displayUtils = InjectorProvider.getInjector().getDisplayUtils(context);
77                 WallpaperClient wallpaperClient = InjectorProvider.getInjector().getWallpaperClient(
78                         context);
79                 List<Point> displaySizes = displayUtils
80                         .getInternalDisplaySizes(/* allDimensions= */ true);
81                 if (mHomeWallpaper != null) {
82                     boolean isHomeWallpaperStatic = mHomeWallpaper.getWallpaperComponent() == null
83                             || mHomeWallpaper.getWallpaperComponent().getComponent() == null;
84                     if (isHomeWallpaperStatic) {
85                         mHomeWallpaper.setWallpaperCropHints(
86                                 wallpaperClient.getCurrentCropHints(displaySizes,
87                                         WallpaperManager.FLAG_SYSTEM));
88                     } else {
89                         mHomeWallpaper.setWallpaperCropHints(new HashMap<>());
90                     }
91                 }
92                 if (mLockWallpaper != null) {
93                     boolean isLockWallpaperStatic = mLockWallpaper.getWallpaperComponent() == null
94                             || mLockWallpaper.getWallpaperComponent().getComponent() == null;
95                     if (isLockWallpaperStatic) {
96                         mLockWallpaper.setWallpaperCropHints(
97                                 wallpaperClient.getCurrentCropHints(displaySizes,
98                                         WallpaperManager.FLAG_LOCK));
99                     } else {
100                         mLockWallpaper.setWallpaperCropHints(new HashMap<>());
101                     }
102                 }
103             } else {
104                 if (mHomeWallpaper != null) mHomeWallpaper.setWallpaperCropHints(null);
105                 if (mLockWallpaper != null) mLockWallpaper.setWallpaperCropHints(null);
106             }
107             callback.onWallpaperInfoCreated(mHomeWallpaper, mLockWallpaper, mPresentationMode);
108             return;
109         }
110 
111         // Clear cached copies if we are refreshing the currently-set WallpaperInfo(s) from the
112         // Refresher so that multiple calls to this method after a call with forceRefresh=true don't
113         // provide old cached copies.
114         if (forceRefresh) {
115             clearCurrentWallpaperInfos();
116         }
117 
118         mWallpaperRefresher.refresh(
119                 (homeWallpaperMetadata, lockWallpaperMetadata, presentationMode) -> {
120                     WallpaperInfo homeWallpaper;
121                     if (homeWallpaperMetadata instanceof LiveWallpaperMetadata) {
122                         homeWallpaper = mLiveWallpaperInfoFactory.getLiveWallpaperInfo(
123                                 homeWallpaperMetadata.getWallpaperComponent());
124                         updateIfCreative(homeWallpaper, homeWallpaperMetadata);
125                     } else {
126                         homeWallpaper = new CurrentWallpaperInfo(
127                                 homeWallpaperMetadata.getAttributions(),
128                                 homeWallpaperMetadata.getActionUrl(),
129                                 homeWallpaperMetadata.getCollectionId(),
130                                 WallpaperManager.FLAG_SYSTEM);
131                         if (isMultiCropEnabled) {
132                             homeWallpaper.setWallpaperCropHints(
133                                     homeWallpaperMetadata.getWallpaperCropHints());
134                         }
135                     }
136 
137                     WallpaperInfo lockWallpaper = null;
138 
139                     if (lockWallpaperMetadata != null) {
140 
141                         if (lockWallpaperMetadata instanceof LiveWallpaperMetadata) {
142                             lockWallpaper = mLiveWallpaperInfoFactory.getLiveWallpaperInfo(
143                                     lockWallpaperMetadata.getWallpaperComponent());
144                             updateIfCreative(lockWallpaper, lockWallpaperMetadata);
145                         } else {
146                             if (isLockWallpaperBuiltIn(context)) {
147                                 lockWallpaper = new DefaultWallpaperInfo();
148                             } else {
149                                 lockWallpaper = new CurrentWallpaperInfo(
150                                         lockWallpaperMetadata.getAttributions(),
151                                         lockWallpaperMetadata.getActionUrl(),
152                                         lockWallpaperMetadata.getCollectionId(),
153                                         WallpaperManager.FLAG_LOCK);
154                             }
155 
156                             if (isMultiCropEnabled) {
157                                 lockWallpaper.setWallpaperCropHints(
158                                         lockWallpaperMetadata.getWallpaperCropHints());
159                             }
160                         }
161                     }
162 
163                     mHomeWallpaper = homeWallpaper;
164                     mLockWallpaper = lockWallpaper;
165                     mPresentationMode = presentationMode;
166 
167                     callback.onWallpaperInfoCreated(homeWallpaper, lockWallpaper, presentationMode);
168                 });
169     }
170 
updateIfCreative(WallpaperInfo info, WallpaperMetadata metadata)171     private void updateIfCreative(WallpaperInfo info, WallpaperMetadata metadata) {
172         if ((info instanceof CreativeWallpaperInfo)
173                 && (metadata instanceof LiveWallpaperMetadata)) {
174             ((CreativeWallpaperInfo) info).setConfigPreviewUri(
175                     ((LiveWallpaperMetadata) metadata).getPreviewUri());
176         }
177     }
178 
isLockWallpaperBuiltIn(Context context)179     private boolean isLockWallpaperBuiltIn(Context context) {
180         WallpaperManager manager =
181                 (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
182 
183         return manager.lockScreenWallpaperExists()
184                 && manager.getWallpaperInfo(WallpaperManager.FLAG_LOCK) == null
185                 && manager.getWallpaperFile(WallpaperManager.FLAG_LOCK) == null;
186     }
187 
188     /**
189      * We check 2 things in this function:
190      * 1. If mHomeWallpaper is null, the wallpaper is not initialized. Return false.
191      * 2. In the case when mHomeWallpaper is not null, we check if mHomeWallpaper is synced with the
192      *    one from the wallpaper manager.
193      */
homeWallpaperSynced(Context context)194     private boolean homeWallpaperSynced(Context context) {
195         if (mHomeWallpaper == null) {
196             return false;
197         }
198         return wallpaperSynced(context, mHomeWallpaper, WallpaperManager.FLAG_SYSTEM);
199     }
200 
201     /**
202      * mLockWallpaper can be null even after initialization. We only check the case if the
203      * lockscreen wallpaper is synced.
204      */
lockWallpaperSynced(Context context)205     private boolean lockWallpaperSynced(Context context) {
206         return wallpaperSynced(context, mLockWallpaper, WallpaperManager.FLAG_LOCK);
207     }
208 
209     /**
210      * Check if the given wallpaper info is synced with the one from the wallpaper manager. We only
211      * try to get the underlying ComponentName from both sides.
212      * If both are null, it means both are static image wallpapers, or both are not set,
213      * which we consider synced and return true.
214      * If only of the them is null, it means one is static image wallpaper and another is live
215      * wallpaper. We should return false.
216      * If both are not null, we check if the two ComponentName(s) are equal.
217      */
wallpaperSynced(Context context, @Nullable WallpaperInfo wallpaperInfo, int which)218     private boolean wallpaperSynced(Context context, @Nullable WallpaperInfo wallpaperInfo,
219             int which) {
220         android.app.WallpaperInfo currentWallpaperInfo = WallpaperManager.getInstance(context)
221                 .getWallpaperInfo(which);
222         ComponentName currentComponentName = currentWallpaperInfo != null
223                 ? currentWallpaperInfo.getComponent() : null;
224         android.app.WallpaperInfo info = wallpaperInfo != null
225                 ? wallpaperInfo.getWallpaperComponent() : null;
226         ComponentName homeComponentName = info != null
227                 ? info.getComponent() : null;
228         if (currentComponentName == null) {
229             // If both are null, it might not be synced for LOCK (param which is 2):
230             // When previous LOCK is default static then homeComponentName will be null, and current
231             // wallpaper is live for both home and lock then currentComponentName will be null.
232             if (homeComponentName == null) {
233                 return which != WallpaperManager.FLAG_LOCK;
234             } else {
235                 return false;
236             }
237         } else if (homeComponentName == null) {
238             // currentComponentName not null and homeComponentName null. It's not synced.
239             return false;
240         } else {
241             return currentComponentName.equals(homeComponentName);
242         }
243     }
244 
245     @Override
clearCurrentWallpaperInfos()246     public void clearCurrentWallpaperInfos() {
247         mHomeWallpaper = null;
248         mLockWallpaper = null;
249     }
250 }
251