1 /* 2 * Copyright (C) 2024 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 package com.android.wallpaper.customization.ui.util 18 19 import android.content.Context 20 import android.view.LayoutInflater 21 import android.view.View 22 import android.view.ViewGroup 23 import android.widget.FrameLayout 24 import android.widget.LinearLayout 25 import androidx.compose.ui.platform.ComposeView 26 import com.android.customization.picker.mode.shared.util.DarkModeLifecycleUtil 27 import com.android.themepicker.R 28 import com.android.wallpaper.config.BaseFlags 29 import com.android.wallpaper.customization.ui.compose.ColorFloatingSheet 30 import com.android.wallpaper.model.Screen 31 import com.android.wallpaper.model.Screen.HOME_SCREEN 32 import com.android.wallpaper.model.Screen.LOCK_SCREEN 33 import com.android.wallpaper.picker.customization.ui.util.CustomizationOptionUtil 34 import com.android.wallpaper.picker.customization.ui.util.DefaultCustomizationOptionUtil 35 import dagger.hilt.android.qualifiers.ActivityContext 36 import dagger.hilt.android.scopes.ActivityScoped 37 import javax.inject.Inject 38 39 @ActivityScoped 40 class ThemePickerCustomizationOptionUtil 41 @Inject 42 constructor( 43 private val defaultCustomizationOptionUtil: DefaultCustomizationOptionUtil, 44 @ActivityContext private val context: Context, 45 ) : CustomizationOptionUtil { 46 47 // Instantiate DarkModeLifecycleUtil for it to observe lifecycle and update DarkModeRepository 48 @Inject lateinit var darkModeLifecycleUtil: DarkModeLifecycleUtil 49 50 enum class ThemePickerLockCustomizationOption : CustomizationOptionUtil.CustomizationOption { 51 CLOCK, 52 SHORTCUTS, 53 LOCK_SCREEN_NOTIFICATIONS, 54 MORE_LOCK_SCREEN_SETTINGS, 55 } 56 57 enum class ThemePickerHomeCustomizationOption : CustomizationOptionUtil.CustomizationOption { 58 PACK_THEME, 59 COLORS, 60 THEMED_ICONS, 61 APP_SHAPE_GRID, 62 COLOR_CONTRAST, 63 } 64 getOptionEntriesnull65 override fun getOptionEntries( 66 screen: Screen, 67 optionContainer: LinearLayout, 68 layoutInflater: LayoutInflater, 69 ): List<Pair<CustomizationOptionUtil.CustomizationOption, View>> { 70 val defaultOptionEntries = 71 defaultCustomizationOptionUtil.getOptionEntries(screen, optionContainer, layoutInflater) 72 return when (screen) { 73 LOCK_SCREEN -> 74 buildList { 75 addAll(defaultOptionEntries) 76 if (BaseFlags.get().isPackThemeEnabled()) { 77 add( 78 ThemePickerHomeCustomizationOption.PACK_THEME to 79 layoutInflater.inflate( 80 R.layout.customization_option_entry_pack_theme, 81 optionContainer, 82 false, 83 ) 84 ) 85 } 86 add( 87 ThemePickerLockCustomizationOption.CLOCK to 88 layoutInflater.inflate( 89 R.layout.customization_option_entry_clock, 90 optionContainer, 91 false, 92 ) 93 ) 94 add( 95 ThemePickerLockCustomizationOption.SHORTCUTS to 96 layoutInflater.inflate( 97 R.layout.customization_option_entry_keyguard_quick_affordance, 98 optionContainer, 99 false, 100 ) 101 ) 102 add( 103 ThemePickerLockCustomizationOption.LOCK_SCREEN_NOTIFICATIONS to 104 layoutInflater.inflate( 105 R.layout.customization_option_entry_lock_screen_notifications, 106 optionContainer, 107 false, 108 ) 109 ) 110 add( 111 ThemePickerLockCustomizationOption.MORE_LOCK_SCREEN_SETTINGS to 112 layoutInflater.inflate( 113 R.layout.customization_option_entry_more_lock_settings, 114 optionContainer, 115 false, 116 ) 117 ) 118 } 119 HOME_SCREEN -> 120 buildList { 121 addAll(defaultOptionEntries) 122 if (BaseFlags.get().isPackThemeEnabled()) { 123 add( 124 ThemePickerHomeCustomizationOption.PACK_THEME to 125 layoutInflater.inflate( 126 R.layout.customization_option_entry_pack_theme, 127 optionContainer, 128 false, 129 ) 130 ) 131 } 132 add( 133 ThemePickerHomeCustomizationOption.COLORS to 134 layoutInflater.inflate( 135 R.layout.customization_option_entry_colors, 136 optionContainer, 137 false, 138 ) 139 ) 140 add( 141 ThemePickerHomeCustomizationOption.THEMED_ICONS to 142 layoutInflater.inflate( 143 R.layout.customization_option_entry_themed_icons, 144 optionContainer, 145 false, 146 ) 147 ) 148 add( 149 ThemePickerHomeCustomizationOption.APP_SHAPE_GRID to 150 layoutInflater.inflate( 151 R.layout.customization_option_entry_app_shape_grid, 152 optionContainer, 153 false, 154 ) 155 ) 156 add( 157 ThemePickerHomeCustomizationOption.COLOR_CONTRAST to 158 layoutInflater.inflate( 159 R.layout.customization_option_entry_color_contrast, 160 optionContainer, 161 false, 162 ) 163 ) 164 } 165 } 166 } 167 initFloatingSheetnull168 override fun initFloatingSheet( 169 bottomSheetContainer: FrameLayout, 170 layoutInflater: LayoutInflater, 171 ): Map<CustomizationOptionUtil.CustomizationOption, View> { 172 val map = 173 defaultCustomizationOptionUtil.initFloatingSheet(bottomSheetContainer, layoutInflater) 174 val isComposeRefactorEnabled = BaseFlags.get().isComposeRefactorEnabled() 175 return buildMap { 176 putAll(map) 177 put( 178 ThemePickerLockCustomizationOption.CLOCK, 179 inflateFloatingSheet( 180 ThemePickerLockCustomizationOption.CLOCK, 181 bottomSheetContainer, 182 layoutInflater, 183 ) 184 .also { bottomSheetContainer.addView(it) }, 185 ) 186 put( 187 ThemePickerLockCustomizationOption.SHORTCUTS, 188 inflateFloatingSheet( 189 ThemePickerLockCustomizationOption.SHORTCUTS, 190 bottomSheetContainer, 191 layoutInflater, 192 ) 193 .also { bottomSheetContainer.addView(it) }, 194 ) 195 put( 196 ThemePickerHomeCustomizationOption.COLORS, 197 if (isComposeRefactorEnabled) { 198 ComposeView(context).apply { setContent { ColorFloatingSheet() } } 199 } else { 200 inflateFloatingSheet( 201 ThemePickerHomeCustomizationOption.COLORS, 202 bottomSheetContainer, 203 layoutInflater, 204 ) 205 } 206 .also { bottomSheetContainer.addView(it) }, 207 ) 208 put( 209 ThemePickerHomeCustomizationOption.APP_SHAPE_GRID, 210 inflateFloatingSheet( 211 ThemePickerHomeCustomizationOption.APP_SHAPE_GRID, 212 bottomSheetContainer, 213 layoutInflater, 214 ) 215 .also { bottomSheetContainer.addView(it) }, 216 ) 217 } 218 } 219 createClockPreviewAndAddToParentnull220 override fun createClockPreviewAndAddToParent( 221 parentView: ViewGroup, 222 layoutInflater: LayoutInflater, 223 ): View? { 224 val clockHostView = layoutInflater.inflate(R.layout.clock_host_view, parentView, false) 225 parentView.addView(clockHostView) 226 return clockHostView 227 } 228 inflateFloatingSheetnull229 private fun inflateFloatingSheet( 230 option: CustomizationOptionUtil.CustomizationOption, 231 bottomSheetContainer: FrameLayout, 232 layoutInflater: LayoutInflater, 233 ): View = 234 when (option) { 235 ThemePickerLockCustomizationOption.CLOCK -> R.layout.floating_sheet_clock 236 ThemePickerLockCustomizationOption.SHORTCUTS -> R.layout.floating_sheet_shortcut 237 ThemePickerHomeCustomizationOption.COLORS -> R.layout.floating_sheet_colors 238 ThemePickerHomeCustomizationOption.APP_SHAPE_GRID -> R.layout.floating_sheet_shape_grid 239 else -> 240 throw IllegalStateException( 241 "Customization option $option does not have a bottom sheet view" 242 ) 243 }.let { layoutInflater.inflate(it, bottomSheetContainer, false) } 244 } 245