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