xref: /aosp_15_r20/frameworks/base/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1 /*
<lambda>null2  * 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.systemui.qs.panels.ui.compose
18 
19 import androidx.compose.foundation.layout.fillMaxSize
20 import androidx.compose.runtime.Composable
21 import androidx.compose.runtime.getValue
22 import androidx.compose.runtime.mutableStateOf
23 import androidx.compose.runtime.setValue
24 import androidx.compose.ui.Modifier
25 import androidx.compose.ui.test.ExperimentalTestApi
26 import androidx.compose.ui.test.click
27 import androidx.compose.ui.test.junit4.createComposeRule
28 import androidx.compose.ui.test.onNodeWithContentDescription
29 import androidx.compose.ui.test.performClick
30 import androidx.compose.ui.test.performCustomAccessibilityActionWithLabel
31 import androidx.compose.ui.test.performTouchInput
32 import androidx.compose.ui.test.swipeLeft
33 import androidx.compose.ui.test.swipeRight
34 import androidx.compose.ui.text.AnnotatedString
35 import androidx.test.ext.junit.runners.AndroidJUnit4
36 import androidx.test.filters.SmallTest
37 import com.android.systemui.SysuiTestCase
38 import com.android.systemui.common.shared.model.ContentDescription
39 import com.android.systemui.common.shared.model.Icon
40 import com.android.systemui.qs.panels.shared.model.SizedTile
41 import com.android.systemui.qs.panels.shared.model.SizedTileImpl
42 import com.android.systemui.qs.panels.ui.compose.infinitegrid.DefaultEditTileGrid
43 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
44 import com.android.systemui.qs.pipeline.shared.TileSpec
45 import com.android.systemui.qs.shared.model.TileCategory
46 import com.google.common.truth.Truth.assertThat
47 import org.junit.Rule
48 import org.junit.Test
49 import org.junit.runner.RunWith
50 
51 @OptIn(ExperimentalTestApi::class)
52 @SmallTest
53 @RunWith(AndroidJUnit4::class)
54 class ResizingTest : SysuiTestCase() {
55     @get:Rule val composeRule = createComposeRule()
56 
57     @Composable
58     private fun EditTileGridUnderTest(
59         listState: EditTileListState,
60         onResize: (TileSpec, Boolean) -> Unit,
61     ) {
62         DefaultEditTileGrid(
63             listState = listState,
64             otherTiles = listOf(),
65             columns = 4,
66             largeTilesSpan = 4,
67             modifier = Modifier.fillMaxSize(),
68             onRemoveTile = {},
69             onSetTiles = {},
70             onResize = onResize,
71             onStopEditing = {},
72             onReset = null,
73         )
74     }
75 
76     @Test
77     fun toggleIconTileWithA11yAction_shouldBeLarge() {
78         var tiles by mutableStateOf(TestEditTiles)
79         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
80         composeRule.setContent {
81             EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) }
82         }
83         composeRule.waitForIdle()
84 
85         composeRule
86             .onNodeWithContentDescription("tileA")
87             .performCustomAccessibilityActionWithLabel("Toggle size")
88 
89         assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2)
90     }
91 
92     @Test
93     fun toggleLargeTileWithA11yAction_shouldBeIcon() {
94         var tiles by mutableStateOf(TestEditTiles)
95         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
96         composeRule.setContent {
97             EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) }
98         }
99         composeRule.waitForIdle()
100 
101         composeRule
102             .onNodeWithContentDescription("tileD_large")
103             .performCustomAccessibilityActionWithLabel("Toggle size")
104 
105         assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1)
106     }
107 
108     @Test
109     fun tapOnIconResizingHandle_shouldBeLarge() {
110         var tiles by mutableStateOf(TestEditTiles)
111         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
112         composeRule.setContent {
113             EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) }
114         }
115         composeRule.waitForIdle()
116 
117         composeRule
118             .onNodeWithContentDescription("tileA")
119             .performClick() // Select
120             .performTouchInput { // Tap on resizing handle
121                 click(centerRight)
122             }
123         composeRule.waitForIdle()
124 
125         assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2)
126     }
127 
128     @Test
129     fun tapOnLargeResizingHandle_shouldBeIcon() {
130         var tiles by mutableStateOf(TestEditTiles)
131         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
132         composeRule.setContent {
133             EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) }
134         }
135         composeRule.waitForIdle()
136 
137         composeRule
138             .onNodeWithContentDescription("tileD_large")
139             .performClick() // Select
140             .performTouchInput { // Tap on resizing handle
141                 click(centerRight)
142             }
143         composeRule.waitForIdle()
144 
145         assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1)
146     }
147 
148     @Test
149     fun resizedIcon_shouldBeLarge() {
150         var tiles by mutableStateOf(TestEditTiles)
151         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
152         composeRule.setContent {
153             EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) }
154         }
155         composeRule.waitForIdle()
156 
157         composeRule
158             .onNodeWithContentDescription("tileA")
159             .performClick() // Select
160             .performTouchInput { // Resize up
161                 swipeRight(startX = right, endX = right * 2)
162             }
163         composeRule.waitForIdle()
164 
165         assertThat(tiles.find { it.tile.tileSpec.spec == "tileA" }?.width).isEqualTo(2)
166     }
167 
168     @Test
169     fun resizedLarge_shouldBeIcon() {
170         var tiles by mutableStateOf(TestEditTiles)
171         val listState = EditTileListState(tiles, columns = 4, largeTilesSpan = 2)
172         composeRule.setContent {
173             EditTileGridUnderTest(listState) { spec, toIcon -> tiles = tiles.resize(spec, toIcon) }
174         }
175         composeRule.waitForIdle()
176 
177         composeRule
178             .onNodeWithContentDescription("tileD_large")
179             .performClick() // Select
180             .performTouchInput { // Resize down
181                 swipeLeft()
182             }
183         composeRule.waitForIdle()
184 
185         assertThat(tiles.find { it.tile.tileSpec.spec == "tileD_large" }?.width).isEqualTo(1)
186     }
187 
188     companion object {
189         private fun List<SizedTile<EditTileViewModel>>.resize(
190             spec: TileSpec,
191             toIcon: Boolean,
192         ): List<SizedTile<EditTileViewModel>> {
193             return map {
194                 if (it.tile.tileSpec == spec) {
195                     SizedTileImpl(it.tile, width = if (toIcon) 1 else 2)
196                 } else {
197                     it
198                 }
199             }
200         }
201 
202         private fun createEditTile(tileSpec: String): SizedTile<EditTileViewModel> {
203             return SizedTileImpl(
204                 EditTileViewModel(
205                     tileSpec = TileSpec.create(tileSpec),
206                     icon =
207                         Icon.Resource(
208                             android.R.drawable.star_on,
209                             ContentDescription.Loaded(tileSpec),
210                         ),
211                     label = AnnotatedString(tileSpec),
212                     appName = null,
213                     isCurrent = true,
214                     availableEditActions = emptySet(),
215                     category = TileCategory.UNKNOWN,
216                 ),
217                 getWidth(tileSpec),
218             )
219         }
220 
221         private fun getWidth(tileSpec: String): Int {
222             return if (tileSpec.endsWith("large")) {
223                 2
224             } else {
225                 1
226             }
227         }
228 
229         private val TestEditTiles =
230             listOf(
231                 createEditTile("tileA"),
232                 createEditTile("tileB"),
233                 createEditTile("tileC"),
234                 createEditTile("tileD_large"),
235                 createEditTile("tileE"),
236             )
237     }
238 }
239