1 /* <lambda>null2 * Copyright (C) 2022 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 */ 17 18 package com.android.wallpaper.picker.customization.ui.section 19 20 import android.annotation.SuppressLint 21 import android.app.Activity 22 import android.content.Context 23 import android.os.Bundle 24 import android.view.LayoutInflater 25 import android.view.View 26 import androidx.cardview.widget.CardView 27 import androidx.core.view.isVisible 28 import androidx.lifecycle.LifecycleOwner 29 import androidx.lifecycle.lifecycleScope 30 import com.android.systemui.shared.clocks.shared.model.ClockPreviewConstants 31 import com.android.wallpaper.R 32 import com.android.wallpaper.model.CustomizationSectionController 33 import com.android.wallpaper.model.WallpaperColorsViewModel 34 import com.android.wallpaper.model.WallpaperInfo 35 import com.android.wallpaper.module.CurrentWallpaperInfoFactory 36 import com.android.wallpaper.module.CustomizationSections 37 import com.android.wallpaper.picker.CategorySelectorFragment 38 import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor 39 import com.android.wallpaper.picker.customization.ui.binder.ScreenPreviewBinder 40 import com.android.wallpaper.picker.customization.ui.viewmodel.ScreenPreviewViewModel 41 import com.android.wallpaper.util.DisplayUtils 42 import com.android.wallpaper.util.PreviewUtils 43 import kotlinx.coroutines.Dispatchers 44 import kotlinx.coroutines.ExperimentalCoroutinesApi 45 import kotlinx.coroutines.launch 46 import kotlinx.coroutines.suspendCancellableCoroutine 47 import kotlinx.coroutines.withContext 48 49 /** Controls the screen preview section. */ 50 @OptIn(ExperimentalCoroutinesApi::class) 51 open class ScreenPreviewSectionController( 52 private val activity: Activity, 53 private val lifecycleOwner: LifecycleOwner, 54 private val initialScreen: CustomizationSections.Screen, 55 private val wallpaperInfoFactory: CurrentWallpaperInfoFactory, 56 private val colorViewModel: WallpaperColorsViewModel, 57 private val displayUtils: DisplayUtils, 58 private val navigator: CustomizationSectionController.CustomizationSectionNavigationController, 59 private val wallpaperInteractor: WallpaperInteractor, 60 ) : CustomizationSectionController<ScreenPreviewView> { 61 62 private lateinit var lockScreenBinding: ScreenPreviewBinder.Binding 63 private lateinit var homeScreenBinding: ScreenPreviewBinder.Binding 64 65 /** Override to hide the lock screen clock preview. */ 66 open val hideLockScreenClockPreview = false 67 68 override fun shouldRetainInstanceWhenSwitchingTabs(): Boolean { 69 return true 70 } 71 72 override fun isAvailable(context: Context): Boolean { 73 // Assumption is that, if this section controller is included, we are using the revamped UI 74 // so it should always be shown. 75 return true 76 } 77 78 @SuppressLint("InflateParams") 79 override fun createView(context: Context): ScreenPreviewView { 80 val view = 81 LayoutInflater.from(context) 82 .inflate( 83 R.layout.screen_preview_section, 84 /* parent= */ null, 85 ) as ScreenPreviewView 86 val onClickListener = 87 View.OnClickListener { navigator.navigateTo(CategorySelectorFragment()) } 88 view.setOnClickListener(onClickListener) 89 val lockScreenView: CardView = view.requireViewById(R.id.lock_preview) 90 val homeScreenView: CardView = view.requireViewById(R.id.home_preview) 91 92 lockScreenBinding = 93 ScreenPreviewBinder.bind( 94 activity = activity, 95 previewView = lockScreenView, 96 viewModel = 97 ScreenPreviewViewModel( 98 previewUtils = 99 PreviewUtils( 100 context = context, 101 authority = 102 context.getString( 103 R.string.lock_screen_preview_provider_authority, 104 ), 105 ), 106 wallpaperInfoProvider = { 107 suspendCancellableCoroutine { continuation -> 108 wallpaperInfoFactory.createCurrentWallpaperInfos( 109 { homeWallpaper, lockWallpaper, _ -> 110 val wallpaper = lockWallpaper ?: homeWallpaper 111 loadInitialColors( 112 context = context, 113 wallpaper = wallpaper, 114 screen = CustomizationSections.Screen.LOCK_SCREEN, 115 ) 116 continuation.resume(wallpaper, null) 117 }, 118 /* forceRefresh= */ true, 119 ) 120 } 121 }, 122 onWallpaperColorChanged = { colors -> 123 colorViewModel.setLockWallpaperColors(colors) 124 }, 125 initialExtrasProvider = { 126 Bundle().apply { 127 // Hide the clock from the system UI rendered preview so we can 128 // place the carousel on top of it. 129 putBoolean( 130 ClockPreviewConstants.KEY_HIDE_CLOCK, 131 hideLockScreenClockPreview, 132 ) 133 } 134 }, 135 wallpaperInteractor = wallpaperInteractor, 136 ), 137 lifecycleOwner = lifecycleOwner, 138 offsetToStart = displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(activity), 139 screen = CustomizationSections.Screen.LOCK_SCREEN, 140 onPreviewDirty = { 141 // only the visible binding should recreate the activity so it's not done twice 142 if (lockScreenView.isVisible) { 143 activity.recreate() 144 } 145 }, 146 ) 147 homeScreenBinding = 148 ScreenPreviewBinder.bind( 149 activity = activity, 150 previewView = homeScreenView, 151 viewModel = 152 ScreenPreviewViewModel( 153 previewUtils = 154 PreviewUtils( 155 context = context, 156 authorityMetadataKey = 157 context.getString( 158 R.string.grid_control_metadata_name, 159 ), 160 ), 161 wallpaperInfoProvider = { 162 suspendCancellableCoroutine { continuation -> 163 wallpaperInfoFactory.createCurrentWallpaperInfos( 164 { homeWallpaper, lockWallpaper, _ -> 165 val wallpaper = homeWallpaper ?: lockWallpaper 166 loadInitialColors( 167 context = context, 168 wallpaper = wallpaper, 169 screen = CustomizationSections.Screen.HOME_SCREEN 170 ) 171 continuation.resume(wallpaper, null) 172 }, 173 /* forceRefresh= */ true, 174 ) 175 } 176 }, 177 onWallpaperColorChanged = { colors -> 178 colorViewModel.setHomeWallpaperColors(colors) 179 }, 180 wallpaperInteractor = wallpaperInteractor, 181 ), 182 lifecycleOwner = lifecycleOwner, 183 offsetToStart = displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(activity), 184 screen = CustomizationSections.Screen.HOME_SCREEN, 185 onPreviewDirty = { 186 // only the visible binding should recreate the activity so it's not done twice 187 if (homeScreenView.isVisible) { 188 activity.recreate() 189 } 190 }, 191 ) 192 193 onScreenSwitched(isOnLockScreen = initialScreen == CustomizationSections.Screen.LOCK_SCREEN) 194 195 return view 196 } 197 198 override fun onScreenSwitched(isOnLockScreen: Boolean) { 199 if (isOnLockScreen) { 200 lockScreenBinding.show() 201 homeScreenBinding.hide() 202 } else { 203 lockScreenBinding.hide() 204 homeScreenBinding.show() 205 } 206 } 207 208 private fun loadInitialColors( 209 context: Context, 210 wallpaper: WallpaperInfo?, 211 screen: CustomizationSections.Screen, 212 ) { 213 lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { 214 val colors = wallpaper?.computeColorInfo(context)?.get()?.wallpaperColors 215 withContext(Dispatchers.Main) { 216 if (colors != null) { 217 if (screen == CustomizationSections.Screen.LOCK_SCREEN) { 218 colorViewModel.setLockWallpaperColors(colors) 219 } else { 220 colorViewModel.setHomeWallpaperColors(colors) 221 } 222 } 223 } 224 } 225 } 226 } 227