1 /* 2 * 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.ui.text.AnnotatedString 20 import androidx.test.ext.junit.runners.AndroidJUnit4 21 import androidx.test.filters.SmallTest 22 import com.android.systemui.SysuiTestCase 23 import com.android.systemui.common.shared.model.Icon 24 import com.android.systemui.qs.panels.shared.model.SizedTile 25 import com.android.systemui.qs.panels.shared.model.SizedTileImpl 26 import com.android.systemui.qs.panels.ui.compose.selection.PlacementEvent 27 import com.android.systemui.qs.panels.ui.model.GridCell 28 import com.android.systemui.qs.panels.ui.model.TileGridCell 29 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel 30 import com.android.systemui.qs.pipeline.shared.TileSpec 31 import com.android.systemui.qs.shared.model.TileCategory 32 import com.google.common.truth.Truth.assertThat 33 import org.junit.Test 34 import org.junit.runner.RunWith 35 36 @SmallTest 37 @RunWith(AndroidJUnit4::class) 38 class EditTileListStateTest : SysuiTestCase() { 39 private val underTest = EditTileListState(TestEditTiles, columns = 4, largeTilesSpan = 2) 40 41 @Test startDrag_listHasSpacersnull42 fun startDrag_listHasSpacers() { 43 underTest.onStarted(TestEditTiles[0], DragType.Add) 44 45 // [ a ] [ b ] [ c ] [ X ] 46 // [ Large D ] [ e ] [ X ] 47 assertThat(underTest.tiles.toStrings()) 48 .isEqualTo(listOf("a", "b", "c", "spacer", "d", "e", "spacer")) 49 assertThat(underTest.isMoving(TestEditTiles[0].tile.tileSpec)).isTrue() 50 assertThat(underTest.dragInProgress).isTrue() 51 } 52 53 @Test moveDrag_listChangesnull54 fun moveDrag_listChanges() { 55 underTest.onStarted(TestEditTiles[4], DragType.Add) 56 underTest.onTargeting(3, false) 57 58 // Tile E goes to index 3 59 // [ a ] [ b ] [ c ] [ e ] 60 // [ Large D ] [ X ] [ X ] 61 assertThat(underTest.tiles.toStrings()) 62 .isEqualTo(listOf("a", "b", "c", "e", "d", "spacer", "spacer")) 63 } 64 65 @Test moveDragOnSidesOfLargeTile_listChangesnull66 fun moveDragOnSidesOfLargeTile_listChanges() { 67 val draggedCell = TestEditTiles[4] 68 69 underTest.onStarted(draggedCell, DragType.Add) 70 underTest.onTargeting(4, true) 71 72 // Tile E goes to the right side of tile D, list is unchanged 73 // [ a ] [ b ] [ c ] [ X ] 74 // [ Large D ] [ e ] [ X ] 75 assertThat(underTest.tiles.toStrings()) 76 .isEqualTo(listOf("a", "b", "c", "spacer", "d", "e", "spacer")) 77 78 underTest.onTargeting(4, false) 79 80 // Tile E goes to the left side of tile D, they swap positions 81 // [ a ] [ b ] [ c ] [ e ] 82 // [ Large D ] [ X ] [ X ] 83 assertThat(underTest.tiles.toStrings()) 84 .isEqualTo(listOf("a", "b", "c", "e", "d", "spacer", "spacer")) 85 } 86 87 @Test moveNewTile_tileIsAddednull88 fun moveNewTile_tileIsAdded() { 89 val newTile = createEditTile("newTile", 2) 90 91 underTest.onStarted(newTile, DragType.Add) 92 underTest.onTargeting(5, false) 93 94 // New tile goes to index 5 95 // [ a ] [ b ] [ c ] [ X ] 96 // [ Large D ] [ newTile ] 97 // [ e ] [ X ] [ X ] [ X ] 98 assertThat(underTest.tiles.toStrings()) 99 .isEqualTo( 100 listOf("a", "b", "c", "spacer", "d", "newTile", "e", "spacer", "spacer", "spacer") 101 ) 102 } 103 104 @Test movedTileOutOfBounds_tileDisappearsnull105 fun movedTileOutOfBounds_tileDisappears() { 106 underTest.onStarted(TestEditTiles[0], DragType.Add) 107 underTest.movedOutOfBounds() 108 109 assertThat(underTest.tiles.toStrings()).doesNotContain(TestEditTiles[0].tile.tileSpec.spec) 110 } 111 112 @Test targetIndexForPlacementToTileSpec_returnsCorrectIndexnull113 fun targetIndexForPlacementToTileSpec_returnsCorrectIndex() { 114 val placementEvent = 115 PlacementEvent.PlaceToTileSpec( 116 movingSpec = TestEditTiles[0].tile.tileSpec, 117 targetSpec = TestEditTiles[3].tile.tileSpec, 118 ) 119 val index = underTest.targetIndexForPlacement(placementEvent) 120 121 assertThat(index).isEqualTo(3) 122 } 123 124 @Test targetIndexForPlacementToIndex_indexOutOfBounds_returnsCorrectIndexnull125 fun targetIndexForPlacementToIndex_indexOutOfBounds_returnsCorrectIndex() { 126 val placementEventTooLow = 127 PlacementEvent.PlaceToIndex( 128 movingSpec = TestEditTiles[0].tile.tileSpec, 129 targetIndex = -1, 130 ) 131 val index1 = underTest.targetIndexForPlacement(placementEventTooLow) 132 133 assertThat(index1).isEqualTo(0) 134 135 val placementEventTooHigh = 136 PlacementEvent.PlaceToIndex( 137 movingSpec = TestEditTiles[0].tile.tileSpec, 138 targetIndex = 10, 139 ) 140 val index2 = underTest.targetIndexForPlacement(placementEventTooHigh) 141 assertThat(index2).isEqualTo(TestEditTiles.size) 142 } 143 144 @Test targetIndexForPlacementToIndex_movingBack_returnsCorrectIndexnull145 fun targetIndexForPlacementToIndex_movingBack_returnsCorrectIndex() { 146 /** 147 * With the grid: [ a ] [ b ] [ c ] [ Large D ] [ e ] [ f ] 148 * 149 * Moving 'e' to the spacer at index 3 will result in the tilespec order: a, b, c, e, d, f 150 * 151 * 'e' is now at index 3 152 */ 153 val placementEvent = 154 PlacementEvent.PlaceToIndex( 155 movingSpec = TestEditTiles[4].tile.tileSpec, 156 targetIndex = 3, 157 ) 158 val index = underTest.targetIndexForPlacement(placementEvent) 159 160 assertThat(index).isEqualTo(3) 161 } 162 163 @Test targetIndexForPlacementToIndex_movingForward_returnsCorrectIndexnull164 fun targetIndexForPlacementToIndex_movingForward_returnsCorrectIndex() { 165 /** 166 * With the grid: [ a ] [ b ] [ c ] [ Large D ] [ e ] [ f ] 167 * 168 * Moving '1' to the spacer at index 3 will result in the tilespec order: b, c, a, d, e, f 169 * 170 * 'a' is now at index 2 171 */ 172 val placementEvent = 173 PlacementEvent.PlaceToIndex( 174 movingSpec = TestEditTiles[0].tile.tileSpec, 175 targetIndex = 3, 176 ) 177 val index = underTest.targetIndexForPlacement(placementEvent) 178 179 assertThat(index).isEqualTo(2) 180 } 181 toStringsnull182 private fun List<GridCell>.toStrings(): List<String> { 183 return map { 184 if (it is TileGridCell) { 185 it.tile.tileSpec.spec 186 } else { 187 "spacer" 188 } 189 } 190 } 191 192 companion object { createEditTilenull193 private fun createEditTile(tileSpec: String, width: Int): SizedTile<EditTileViewModel> { 194 return SizedTileImpl( 195 EditTileViewModel( 196 tileSpec = TileSpec.create(tileSpec), 197 icon = Icon.Resource(0, null), 198 label = AnnotatedString("unused"), 199 appName = null, 200 isCurrent = true, 201 availableEditActions = emptySet(), 202 category = TileCategory.UNKNOWN, 203 ), 204 width, 205 ) 206 } 207 208 // [ a ] [ b ] [ c ] 209 // [ Large D ] [ e ] [ f ] 210 private val TestEditTiles = 211 listOf( 212 createEditTile("a", 1), 213 createEditTile("b", 1), 214 createEditTile("c", 1), 215 createEditTile("d", 2), 216 createEditTile("e", 1), 217 ) 218 } 219 } 220