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