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