1 /* <lambda>null2 * Copyright (C) 2023 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.customization.picker.color.ui.fragment 17 18 import android.app.WallpaperManager 19 import android.os.Bundle 20 import android.view.LayoutInflater 21 import android.view.View 22 import android.view.ViewGroup 23 import android.view.ViewGroup.MarginLayoutParams 24 import android.widget.FrameLayout 25 import androidx.cardview.widget.CardView 26 import androidx.core.content.ContextCompat 27 import androidx.core.view.ViewCompat 28 import androidx.core.view.WindowInsetsCompat 29 import androidx.core.view.isVisible 30 import androidx.core.view.updateLayoutParams 31 import androidx.lifecycle.ViewModelProvider 32 import androidx.lifecycle.get 33 import androidx.lifecycle.lifecycleScope 34 import androidx.transition.Transition 35 import androidx.transition.doOnStart 36 import com.android.customization.model.mode.DarkModeSectionController 37 import com.android.customization.module.ThemePickerInjector 38 import com.android.customization.picker.color.ui.binder.ColorPickerBinder 39 import com.android.themepicker.R 40 import com.android.wallpaper.model.Screen 41 import com.android.wallpaper.module.InjectorProvider 42 import com.android.wallpaper.picker.AppbarFragment 43 import com.android.wallpaper.picker.customization.data.repository.WallpaperColorsRepository 44 import com.android.wallpaper.picker.customization.shared.model.WallpaperColorsModel 45 import com.android.wallpaper.picker.customization.ui.binder.ScreenPreviewBinder 46 import com.android.wallpaper.picker.customization.ui.viewmodel.ScreenPreviewViewModel 47 import com.android.wallpaper.util.DisplayUtils 48 import com.android.wallpaper.util.PreviewUtils 49 import kotlinx.coroutines.Dispatchers 50 import kotlinx.coroutines.ExperimentalCoroutinesApi 51 import kotlinx.coroutines.launch 52 import kotlinx.coroutines.suspendCancellableCoroutine 53 import kotlinx.coroutines.withContext 54 55 @OptIn(ExperimentalCoroutinesApi::class) 56 class ColorPickerFragment : AppbarFragment() { 57 private var binding: ColorPickerBinder.Binding? = null 58 59 companion object { 60 @JvmStatic 61 fun newInstance(): ColorPickerFragment { 62 return ColorPickerFragment() 63 } 64 } 65 66 override fun onCreateView( 67 inflater: LayoutInflater, 68 container: ViewGroup?, 69 savedInstanceState: Bundle? 70 ): View { 71 val view = 72 inflater.inflate( 73 R.layout.fragment_color_picker, 74 container, 75 false, 76 ) 77 ViewCompat.setOnApplyWindowInsetsListener(view) { v, windowInsets -> 78 val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 79 v.updateLayoutParams<MarginLayoutParams> { 80 topMargin = insets.top 81 bottomMargin = insets.bottom 82 } 83 WindowInsetsCompat.CONSUMED 84 } 85 setUpToolbar(view) 86 87 val injector = InjectorProvider.getInjector() as ThemePickerInjector 88 val lockScreenView: CardView = view.requireViewById(R.id.lock_preview) 89 val homeScreenView: CardView = view.requireViewById(R.id.home_preview) 90 val wallpaperInfoFactory = injector.getCurrentWallpaperInfoFactory(requireContext()) 91 val displayUtils: DisplayUtils = injector.getDisplayUtils(requireContext()) 92 val wallpaperColorsRepository = injector.getWallpaperColorsRepository() 93 val wallpaperManager = WallpaperManager.getInstance(requireContext()) 94 95 binding = 96 ColorPickerBinder.bind( 97 view = view, 98 viewModel = 99 ViewModelProvider( 100 requireActivity(), 101 injector.getColorPickerViewModelFactory(requireContext()), 102 ) 103 .get(), 104 lifecycleOwner = this, 105 ) 106 107 savedInstanceState?.let { binding?.restoreInstanceState(it) } 108 109 val lockScreenPreviewBinder = 110 ScreenPreviewBinder.bind( 111 activity = requireActivity(), 112 previewView = lockScreenView, 113 viewModel = 114 ScreenPreviewViewModel( 115 previewUtils = 116 PreviewUtils( 117 context = requireContext(), 118 authority = 119 requireContext() 120 .getString( 121 com.android.wallpaper.R.string 122 .lock_screen_preview_provider_authority, 123 ), 124 ), 125 wallpaperInfoProvider = { forceReload -> 126 suspendCancellableCoroutine { continuation -> 127 wallpaperInfoFactory.createCurrentWallpaperInfos( 128 context, 129 forceReload, 130 ) { homeWallpaper, lockWallpaper, _ -> 131 lifecycleScope.launch { 132 if ( 133 wallpaperColorsRepository.lockWallpaperColors.value 134 is WallpaperColorsModel.Loading 135 ) { 136 loadInitialColors( 137 wallpaperManager, 138 wallpaperColorsRepository, 139 Screen.LOCK_SCREEN 140 ) 141 } 142 } 143 continuation.resume(lockWallpaper ?: homeWallpaper, null) 144 } 145 } 146 }, 147 onWallpaperColorChanged = { colors -> 148 wallpaperColorsRepository.setLockWallpaperColors(colors) 149 }, 150 wallpaperInteractor = injector.getWallpaperInteractor(requireContext()), 151 screen = Screen.LOCK_SCREEN, 152 ), 153 lifecycleOwner = this, 154 offsetToStart = 155 displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(requireActivity()), 156 onWallpaperPreviewDirty = { activity?.recreate() }, 157 ) 158 val shouldMirrorHomePreview = 159 wallpaperManager.getWallpaperInfo(WallpaperManager.FLAG_SYSTEM) != null && 160 wallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK) < 0 161 val mirrorSurface = if (shouldMirrorHomePreview) lockScreenPreviewBinder.surface() else null 162 ScreenPreviewBinder.bind( 163 activity = requireActivity(), 164 previewView = homeScreenView, 165 viewModel = 166 ScreenPreviewViewModel( 167 previewUtils = 168 PreviewUtils( 169 context = requireContext(), 170 authorityMetadataKey = 171 requireContext() 172 .getString( 173 com.android.wallpaper.R.string.grid_control_metadata_name, 174 ), 175 ), 176 wallpaperInfoProvider = { forceReload -> 177 suspendCancellableCoroutine { continuation -> 178 wallpaperInfoFactory.createCurrentWallpaperInfos( 179 context, 180 forceReload, 181 ) { homeWallpaper, lockWallpaper, _ -> 182 lifecycleScope.launch { 183 if ( 184 wallpaperColorsRepository.homeWallpaperColors.value 185 is WallpaperColorsModel.Loading 186 ) { 187 loadInitialColors( 188 wallpaperManager, 189 wallpaperColorsRepository, 190 Screen.HOME_SCREEN 191 ) 192 } 193 } 194 continuation.resume(homeWallpaper ?: lockWallpaper, null) 195 } 196 } 197 }, 198 onWallpaperColorChanged = { colors -> 199 wallpaperColorsRepository.setHomeWallpaperColors(colors) 200 }, 201 wallpaperInteractor = injector.getWallpaperInteractor(requireContext()), 202 screen = Screen.HOME_SCREEN, 203 ), 204 lifecycleOwner = this, 205 offsetToStart = 206 displayUtils.isSingleDisplayOrUnfoldedHorizontalHinge(requireActivity()), 207 onWallpaperPreviewDirty = { activity?.recreate() }, 208 mirrorSurface = mirrorSurface, 209 ) 210 val darkModeToggleContainerView: FrameLayout = 211 view.requireViewById(R.id.dark_mode_toggle_container) 212 val darkModeSectionView = 213 DarkModeSectionController( 214 context, 215 lifecycle, 216 injector.getDarkModeSnapshotRestorer(requireContext()), 217 injector.uiModeManager.get(), 218 injector.getUserEventLogger(), 219 ) 220 .createView(requireContext()) 221 darkModeSectionView.background = null 222 darkModeToggleContainerView.addView(darkModeSectionView) 223 224 (returnTransition as? Transition)?.doOnStart { 225 lockScreenView.isVisible = false 226 homeScreenView.isVisible = false 227 } 228 229 return view 230 } 231 232 private suspend fun loadInitialColors( 233 wallpaperManager: WallpaperManager, 234 colorViewModel: WallpaperColorsRepository, 235 screen: Screen, 236 ) { 237 withContext(Dispatchers.IO) { 238 val colors = 239 wallpaperManager.getWallpaperColors( 240 if (screen == Screen.LOCK_SCREEN) { 241 WallpaperManager.FLAG_LOCK 242 } else { 243 WallpaperManager.FLAG_SYSTEM 244 } 245 ) 246 withContext(Dispatchers.Main) { 247 if (screen == Screen.LOCK_SCREEN) { 248 colorViewModel.setLockWallpaperColors(colors) 249 } else { 250 colorViewModel.setHomeWallpaperColors(colors) 251 } 252 } 253 } 254 } 255 256 override fun onSaveInstanceState(savedInstanceState: Bundle) { 257 super.onSaveInstanceState(savedInstanceState) 258 binding?.saveInstanceState(savedInstanceState) 259 } 260 261 override fun getDefaultTitle(): CharSequence { 262 return requireContext().getString(R.string.color_picker_title) 263 } 264 265 override fun getToolbarTextColor(): Int { 266 return ContextCompat.getColor( 267 requireContext(), 268 com.android.wallpaper.R.color.system_on_surface 269 ) 270 } 271 } 272