• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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 
17 package com.android.systemui.bouncer.ui.composable
18 
19 import androidx.annotation.VisibleForTesting
20 import androidx.compose.material3.windowsizeclass.WindowHeightSizeClass
21 import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
22 import androidx.compose.runtime.Composable
23 import com.android.compose.windowsizeclass.LocalWindowSizeClass
24 
25 /**
26  * Returns the [BouncerOverlayLayout] that should be used by the bouncer scene. If
27  * [isOneHandedModeSupported] is `false`, then [BouncerOverlayLayout.BESIDE_USER_SWITCHER] is
28  * replaced by [BouncerOverlayLayout.STANDARD_BOUNCER].
29  */
30 @Composable
calculateLayoutnull31 fun calculateLayout(isOneHandedModeSupported: Boolean): BouncerOverlayLayout {
32     val windowSizeClass = LocalWindowSizeClass.current
33 
34     return calculateLayoutInternal(
35         width = windowSizeClass.widthSizeClass.toEnum(),
36         height = windowSizeClass.heightSizeClass.toEnum(),
37         isOneHandedModeSupported = isOneHandedModeSupported,
38     )
39 }
40 
WindowWidthSizeClassnull41 private fun WindowWidthSizeClass.toEnum(): SizeClass {
42     return when (this) {
43         WindowWidthSizeClass.Compact -> SizeClass.COMPACT
44         WindowWidthSizeClass.Medium -> SizeClass.MEDIUM
45         WindowWidthSizeClass.Expanded -> SizeClass.EXPANDED
46         else -> error("Unsupported WindowWidthSizeClass \"$this\"")
47     }
48 }
49 
WindowHeightSizeClassnull50 private fun WindowHeightSizeClass.toEnum(): SizeClass {
51     return when (this) {
52         WindowHeightSizeClass.Compact -> SizeClass.COMPACT
53         WindowHeightSizeClass.Medium -> SizeClass.MEDIUM
54         WindowHeightSizeClass.Expanded -> SizeClass.EXPANDED
55         else -> error("Unsupported WindowHeightSizeClass \"$this\"")
56     }
57 }
58 
59 /** Enumerates all known adaptive layout configurations. */
60 enum class BouncerOverlayLayout {
61     /** The default UI with the bouncer laid out normally. */
62     STANDARD_BOUNCER,
63     /** The bouncer is displayed vertically stacked with the user switcher. */
64     BELOW_USER_SWITCHER,
65     /** The bouncer is displayed side-by-side with the user switcher or an empty space. */
66     BESIDE_USER_SWITCHER,
67     /** The bouncer is split in two with both sides shown side-by-side. */
68     SPLIT_BOUNCER,
69 }
70 
71 /** Enumerates the supported window size classes. */
72 enum class SizeClass {
73     COMPACT,
74     MEDIUM,
75     EXPANDED,
76 }
77 
78 /**
79  * Internal version of `calculateLayout` in the System UI Compose library, extracted here to allow
80  * for testing that's not dependent on Compose.
81  */
82 @VisibleForTesting
calculateLayoutInternalnull83 fun calculateLayoutInternal(
84     width: SizeClass,
85     height: SizeClass,
86     isOneHandedModeSupported: Boolean,
87 ): BouncerOverlayLayout {
88     return when (height) {
89         SizeClass.COMPACT -> BouncerOverlayLayout.SPLIT_BOUNCER
90         SizeClass.MEDIUM ->
91             when (width) {
92                 SizeClass.COMPACT -> BouncerOverlayLayout.STANDARD_BOUNCER
93                 SizeClass.MEDIUM -> BouncerOverlayLayout.STANDARD_BOUNCER
94                 SizeClass.EXPANDED -> BouncerOverlayLayout.BESIDE_USER_SWITCHER
95             }
96         SizeClass.EXPANDED ->
97             when (width) {
98                 SizeClass.COMPACT -> BouncerOverlayLayout.STANDARD_BOUNCER
99                 SizeClass.MEDIUM -> BouncerOverlayLayout.BELOW_USER_SWITCHER
100                 SizeClass.EXPANDED -> BouncerOverlayLayout.BESIDE_USER_SWITCHER
101             }
102     }.takeIf { it != BouncerOverlayLayout.BESIDE_USER_SWITCHER || isOneHandedModeSupported }
103         ?: BouncerOverlayLayout.STANDARD_BOUNCER
104 }
105