1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 * 14 */ 15 package com.android.systemui.common.ui 16 17 import android.content.Context 18 import android.view.LayoutInflater 19 import android.view.View 20 import android.view.ViewGroup 21 import androidx.annotation.AttrRes 22 import androidx.annotation.ColorInt 23 import androidx.annotation.DimenRes 24 import androidx.annotation.LayoutRes 25 import com.android.settingslib.Utils 26 import com.android.systemui.dagger.qualifiers.Application 27 import com.android.systemui.statusbar.policy.ConfigurationController 28 import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged 29 import com.android.systemui.statusbar.policy.onThemeChanged 30 import com.android.systemui.util.kotlin.emitOnStart 31 import javax.inject.Inject 32 import kotlinx.coroutines.flow.Flow 33 import kotlinx.coroutines.flow.map 34 import kotlinx.coroutines.flow.merge 35 36 /** Configuration-aware-state-tracking utilities. */ 37 class ConfigurationState 38 @Inject 39 constructor( 40 private val configurationController: ConfigurationController, 41 @Application private val context: Context, 42 private val layoutInflater: LayoutInflater, 43 ) { 44 /** 45 * Returns a [Flow] that emits a dimension pixel size that is kept in sync with the device 46 * configuration. 47 * 48 * @see android.content.res.Resources.getDimensionPixelSize 49 */ getDimensionPixelSizenull50 fun getDimensionPixelSize(@DimenRes id: Int): Flow<Int> { 51 return configurationController.onDensityOrFontScaleChanged.emitOnStart().map { 52 context.resources.getDimensionPixelSize(id) 53 } 54 } 55 56 /** 57 * Returns a [Flow] that emits a dimension pixel size that is kept in sync with the device 58 * configuration. 59 * 60 * @see android.content.res.Resources.getDimensionPixelSize 61 */ getDimensionPixelOffsetnull62 fun getDimensionPixelOffset(@DimenRes id: Int): Flow<Int> { 63 return configurationController.onDensityOrFontScaleChanged.emitOnStart().map { 64 context.resources.getDimensionPixelOffset(id) 65 } 66 } 67 68 /** 69 * Returns a [Flow] that emits a color that is kept in sync with the device theme. 70 * 71 * @see Utils.getColorAttrDefaultColor 72 */ getColorAttrnull73 fun getColorAttr(@AttrRes id: Int, @ColorInt defaultValue: Int): Flow<Int> { 74 return configurationController.onThemeChanged.emitOnStart().map { 75 Utils.getColorAttrDefaultColor(context, id, defaultValue) 76 } 77 } 78 79 /** 80 * Returns a [Flow] that emits a [View] that is re-inflated as necessary to remain in sync with 81 * the device configuration. 82 * 83 * @see LayoutInflater.inflate 84 */ 85 @Suppress("UNCHECKED_CAST") inflateLayoutnull86 fun <T : View> inflateLayout( 87 @LayoutRes id: Int, 88 root: ViewGroup?, 89 attachToRoot: Boolean, 90 ): Flow<T> { 91 // TODO(b/305930747): This may lead to duplicate invocations if both flows emit, find a 92 // solution to only emit one event. 93 return merge( 94 configurationController.onThemeChanged, 95 configurationController.onDensityOrFontScaleChanged, 96 ) 97 .emitOnStart() 98 .map { layoutInflater.inflate(id, root, attachToRoot) as T } 99 } 100 } 101