• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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