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.systemui.common.ui.domain.interactor 17 18 import android.content.res.Configuration 19 import android.graphics.Rect 20 import android.view.Surface 21 import com.android.systemui.common.ui.data.repository.ConfigurationRepository 22 import kotlinx.coroutines.flow.Flow 23 import kotlinx.coroutines.flow.StateFlow 24 import kotlinx.coroutines.flow.combine 25 import kotlinx.coroutines.flow.distinctUntilChanged 26 import kotlinx.coroutines.flow.map 27 import kotlinx.coroutines.flow.mapLatest 28 import kotlinx.coroutines.flow.onStart 29 30 /** Business logic related to configuration changes. */ 31 interface ConfigurationInteractor { 32 /** 33 * Returns screen size adjusted to rotation, so returned screen size is stable across all 34 * rotations 35 */ 36 val Configuration.naturalScreenBounds: Rect 37 38 /** Returns the unadjusted screen size. */ 39 val maxBounds: Flow<Rect> 40 41 /** 42 * Returns screen size adjusted to rotation, so returned screen sizes are stable across all 43 * rotations, could be useful if you need to react to screen resize (e.g. fold/unfold on 44 * foldable devices) 45 */ 46 val naturalMaxBounds: Flow<Rect> 47 48 /** 49 * The layout direction. Will be either `View#LAYOUT_DIRECTION_LTR` or 50 * `View#LAYOUT_DIRECTION_RTL`. 51 */ 52 val layoutDirection: Flow<Int> 53 54 /** Emit an event on any config change */ 55 val onAnyConfigurationChange: Flow<Unit> 56 57 /** Emits the new configuration on any configuration change */ 58 val configurationValues: Flow<Configuration> 59 60 /** Emits the current resolution scaling factor */ 61 val scaleForResolution: StateFlow<Float> 62 63 /** Given [resourceId], emit the dimension pixel size on config change */ 64 fun dimensionPixelSize(resourceId: Int): Flow<Int> 65 66 /** Emits the dimensional pixel size of the given resource, inverting it for RTL if necessary */ 67 fun directionalDimensionPixelSize(originLayoutDirection: Int, resourceId: Int): Flow<Int> 68 69 /** Given a set of [resourceId]s, emit Map<ResourceId, DimensionPixelSize> on config change */ 70 fun dimensionPixelSize(resourceIds: Set<Int>): Flow<Map<Int, Int>> 71 } 72 73 class ConfigurationInteractorImpl(private val repository: ConfigurationRepository) : 74 ConfigurationInteractor { 75 76 override val Configuration.naturalScreenBounds: Rect 77 get() { 78 val rotation = windowConfiguration.displayRotation 79 val maxBounds = windowConfiguration.maxBounds 80 return if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) { 81 Rect(0, 0, maxBounds.width(), maxBounds.height()) 82 } else { 83 Rect(0, 0, maxBounds.height(), maxBounds.width()) 84 } 85 } 86 87 override val maxBounds: Flow<Rect> = 88 repository.configurationValues <lambda>null89 .map { Rect(it.windowConfiguration.maxBounds) } 90 .distinctUntilChanged() 91 92 override val naturalMaxBounds: Flow<Rect> = <lambda>null93 repository.configurationValues.map { it.naturalScreenBounds }.distinctUntilChanged() 94 95 override val layoutDirection: Flow<Int> = <lambda>null96 repository.configurationValues.map { it.layoutDirection }.distinctUntilChanged() 97 dimensionPixelSizenull98 override fun dimensionPixelSize(resourceId: Int): Flow<Int> { 99 return onAnyConfigurationChange.mapLatest { repository.getDimensionPixelSize(resourceId) } 100 } 101 directionalDimensionPixelSizenull102 override fun directionalDimensionPixelSize( 103 originLayoutDirection: Int, 104 resourceId: Int, 105 ): Flow<Int> { 106 return dimensionPixelSize(resourceId).combine(layoutDirection) { size, direction -> 107 if (originLayoutDirection == direction) size else -size 108 } 109 } 110 dimensionPixelSizenull111 override fun dimensionPixelSize(resourceIds: Set<Int>): Flow<Map<Int, Int>> { 112 return onAnyConfigurationChange.mapLatest { 113 resourceIds.associateWith { repository.getDimensionPixelSize(it) } 114 } 115 } 116 117 override val onAnyConfigurationChange: Flow<Unit> = <lambda>null118 repository.onAnyConfigurationChange.onStart { emit(Unit) } 119 120 override val configurationValues: Flow<Configuration> = repository.configurationValues 121 122 override val scaleForResolution: StateFlow<Float> = repository.scaleForResolution 123 } 124