Loading packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt 0 → 100644 +131 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.panels.ui.compose.selection import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.qs.pipeline.shared.TileSpec import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class MutableSelectionStateTest : SysuiTestCase() { private val underTest = MutableSelectionState() @Test fun selectTile_isCorrectlySelected() { assertThat(underTest.isSelected(TEST_SPEC)).isFalse() underTest.select(TEST_SPEC) assertThat(underTest.isSelected(TEST_SPEC)).isTrue() underTest.unSelect() assertThat(underTest.isSelected(TEST_SPEC)).isFalse() val newSpec = TileSpec.create("newSpec") underTest.select(TEST_SPEC) underTest.select(newSpec) assertThat(underTest.isSelected(TEST_SPEC)).isFalse() assertThat(underTest.isSelected(newSpec)).isTrue() } @Test fun startResize_createsResizingState() { assertThat(underTest.resizingState).isNull() // Resizing starts but no tile is selected underTest.onResizingDragStart(TileWidths(0, 0, 1)) {} assertThat(underTest.resizingState).isNull() // Resizing starts with a selected tile underTest.select(TEST_SPEC) underTest.onResizingDragStart(TileWidths(0, 0, 1)) {} assertThat(underTest.resizingState).isNotNull() } @Test fun endResize_clearsResizingState() { val spec = TileSpec.create("testSpec") // Resizing starts with a selected tile underTest.select(spec) underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} assertThat(underTest.resizingState).isNotNull() underTest.onResizingDragEnd() assertThat(underTest.resizingState).isNull() } @Test fun unselect_clearsResizingState() { // Resizing starts with a selected tile underTest.select(TEST_SPEC) underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} assertThat(underTest.resizingState).isNotNull() underTest.unSelect() assertThat(underTest.resizingState).isNull() } @Test fun onResizingDrag_updatesResizingState() { // Resizing starts with a selected tile underTest.select(TEST_SPEC) underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} assertThat(underTest.resizingState).isNotNull() underTest.onResizingDrag(5f) assertThat(underTest.resizingState?.width).isEqualTo(5) underTest.onResizingDrag(2f) assertThat(underTest.resizingState?.width).isEqualTo(7) underTest.onResizingDrag(-6f) assertThat(underTest.resizingState?.width).isEqualTo(1) } @Test fun onResizingDrag_receivesResizeCallback() { var resized = false val onResize: () -> Unit = { resized = !resized } // Resizing starts with a selected tile underTest.select(TEST_SPEC) underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10), onResize) assertThat(underTest.resizingState).isNotNull() // Drag under the threshold underTest.onResizingDrag(1f) assertThat(resized).isFalse() // Drag over the threshold underTest.onResizingDrag(5f) assertThat(resized).isTrue() // Drag back under the threshold underTest.onResizingDrag(-5f) assertThat(resized).isFalse() } companion object { private val TEST_SPEC = TileSpec.create("testSpec") } } packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.panels.ui.compose.selection import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class ResizingStateTest : SysuiTestCase() { @Test fun drag_updatesStateCorrectly() { var resized = false val underTest = ResizingState(TileWidths(base = 0, min = 0, max = 10)) { resized = !resized } assertThat(underTest.width).isEqualTo(0) underTest.onDrag(2f) assertThat(underTest.width).isEqualTo(2) underTest.onDrag(1f) assertThat(underTest.width).isEqualTo(3) assertThat(resized).isTrue() underTest.onDrag(-1f) assertThat(underTest.width).isEqualTo(2) assertThat(resized).isFalse() } @Test fun dragOutOfBounds_isClampedCorrectly() { val underTest = ResizingState(TileWidths(base = 0, min = 0, max = 10)) {} assertThat(underTest.width).isEqualTo(0) underTest.onDrag(100f) assertThat(underTest.width).isEqualTo(10) underTest.onDrag(-200f) assertThat(underTest.width).isEqualTo(0) } } packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt +32 −29 Original line number Diff line number Diff line Loading @@ -17,9 +17,10 @@ package com.android.systemui.qs.panels.ui.compose import android.content.ClipData import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.draganddrop.dragAndDropSource import androidx.compose.foundation.draganddrop.dragAndDropTarget import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress import androidx.compose.foundation.lazy.grid.LazyGridItemInfo import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.runtime.Composable Loading Loading @@ -104,11 +105,10 @@ fun Modifier.dragAndDropRemoveZone( @Composable fun Modifier.dragAndDropTileList( gridState: LazyGridState, contentOffset: Offset, contentOffset: () -> Offset, dragAndDropState: DragAndDropState, onDrop: () -> Unit, onDrop: (TileSpec) -> Unit, ): Modifier { val currentContentOffset by rememberUpdatedState(contentOffset) val target = remember(dragAndDropState) { object : DragAndDropTarget { Loading @@ -118,7 +118,7 @@ fun Modifier.dragAndDropTileList( override fun onMoved(event: DragAndDropEvent) { // Drag offset relative to the list's top left corner val relativeDragOffset = event.dragOffsetRelativeTo(currentContentOffset) val relativeDragOffset = event.dragOffsetRelativeTo(contentOffset()) val targetItem = gridState.layoutInfo.visibleItemsInfo.firstOrNull { item -> // Check if the drag is on this item Loading @@ -132,7 +132,7 @@ fun Modifier.dragAndDropTileList( override fun onDrop(event: DragAndDropEvent): Boolean { return dragAndDropState.draggedCell?.let { onDrop() onDrop(it.tile.tileSpec) dragAndDropState.onDrop() true } ?: false Loading @@ -158,24 +158,26 @@ private fun insertAfter(item: LazyGridItemInfo, offset: Offset): Boolean { return item.span != 1 && offset.x > itemCenter.x } @OptIn(ExperimentalFoundationApi::class) @Composable fun Modifier.dragAndDropTileSource( sizedTile: SizedTile<EditTileViewModel>, dragAndDropState: DragAndDropState, onTap: (TileSpec) -> Unit, onDoubleTap: (TileSpec) -> Unit = {}, onDragStart: () -> Unit, ): Modifier { val state by rememberUpdatedState(dragAndDropState) return dragAndDropSource { detectTapGestures( onTap = { onTap(sizedTile.tile.tileSpec) }, onDoubleTap = { onDoubleTap(sizedTile.tile.tileSpec) }, onLongPress = { state.onStarted(sizedTile) // The tilespec from the ClipData transferred isn't actually needed as we're moving // a tile within the same application. We're using a custom MIME type to limit the // drag event to QS. val dragState by rememberUpdatedState(dragAndDropState) @Suppress("DEPRECATION") // b/368361871 return dragAndDropSource( block = { detectDragGesturesAfterLongPress( onDrag = { _, _ -> }, onDragStart = { dragState.onStarted(sizedTile) onDragStart() // The tilespec from the ClipData transferred isn't actually needed as we're // moving a tile within the same application. We're using a custom MIME type to // limit the drag event to QS. startTransfer( DragAndDropTransferData( ClipData( Loading @@ -188,6 +190,7 @@ fun Modifier.dragAndDropTileSource( }, ) } ) } private object QsDragAndDrop { Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt +4 −5 Original line number Diff line number Diff line Loading @@ -42,10 +42,8 @@ fun rememberEditListState( } /** Holds the temporary state of the tile list during a drag movement where we move tiles around. */ class EditTileListState( tiles: List<SizedTile<EditTileViewModel>>, private val columns: Int, ) : DragAndDropState { class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val columns: Int) : DragAndDropState { private val _draggedCell = mutableStateOf<SizedTile<EditTileViewModel>?>(null) override val draggedCell get() = _draggedCell.value Loading Loading @@ -91,7 +89,8 @@ class EditTileListState( regenerateGrid(includeSpacers = true) _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell) } else { // Add the tile with a temporary row which will get reassigned when regenerating spacers // Add the tile with a temporary row which will get reassigned when // regenerating spacers _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0)) } Loading packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt +3 −2 Original line number Diff line number Diff line Loading @@ -127,13 +127,14 @@ fun LargeTileContent( } @Composable private fun LargeTileLabels( fun LargeTileLabels( label: String, secondaryLabel: String?, colors: TileColors, modifier: Modifier = Modifier, accessibilityUiState: AccessibilityUiState? = null, ) { Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) { Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) { Text(label, color = colors.label, modifier = Modifier.tileMarquee()) if (!TextUtils.isEmpty(secondaryLabel)) { Text( Loading Loading
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/MutableSelectionStateTest.kt 0 → 100644 +131 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.panels.ui.compose.selection import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.qs.pipeline.shared.TileSpec import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class MutableSelectionStateTest : SysuiTestCase() { private val underTest = MutableSelectionState() @Test fun selectTile_isCorrectlySelected() { assertThat(underTest.isSelected(TEST_SPEC)).isFalse() underTest.select(TEST_SPEC) assertThat(underTest.isSelected(TEST_SPEC)).isTrue() underTest.unSelect() assertThat(underTest.isSelected(TEST_SPEC)).isFalse() val newSpec = TileSpec.create("newSpec") underTest.select(TEST_SPEC) underTest.select(newSpec) assertThat(underTest.isSelected(TEST_SPEC)).isFalse() assertThat(underTest.isSelected(newSpec)).isTrue() } @Test fun startResize_createsResizingState() { assertThat(underTest.resizingState).isNull() // Resizing starts but no tile is selected underTest.onResizingDragStart(TileWidths(0, 0, 1)) {} assertThat(underTest.resizingState).isNull() // Resizing starts with a selected tile underTest.select(TEST_SPEC) underTest.onResizingDragStart(TileWidths(0, 0, 1)) {} assertThat(underTest.resizingState).isNotNull() } @Test fun endResize_clearsResizingState() { val spec = TileSpec.create("testSpec") // Resizing starts with a selected tile underTest.select(spec) underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} assertThat(underTest.resizingState).isNotNull() underTest.onResizingDragEnd() assertThat(underTest.resizingState).isNull() } @Test fun unselect_clearsResizingState() { // Resizing starts with a selected tile underTest.select(TEST_SPEC) underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} assertThat(underTest.resizingState).isNotNull() underTest.unSelect() assertThat(underTest.resizingState).isNull() } @Test fun onResizingDrag_updatesResizingState() { // Resizing starts with a selected tile underTest.select(TEST_SPEC) underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10)) {} assertThat(underTest.resizingState).isNotNull() underTest.onResizingDrag(5f) assertThat(underTest.resizingState?.width).isEqualTo(5) underTest.onResizingDrag(2f) assertThat(underTest.resizingState?.width).isEqualTo(7) underTest.onResizingDrag(-6f) assertThat(underTest.resizingState?.width).isEqualTo(1) } @Test fun onResizingDrag_receivesResizeCallback() { var resized = false val onResize: () -> Unit = { resized = !resized } // Resizing starts with a selected tile underTest.select(TEST_SPEC) underTest.onResizingDragStart(TileWidths(base = 0, min = 0, max = 10), onResize) assertThat(underTest.resizingState).isNotNull() // Drag under the threshold underTest.onResizingDrag(1f) assertThat(resized).isFalse() // Drag over the threshold underTest.onResizingDrag(5f) assertThat(resized).isTrue() // Drag back under the threshold underTest.onResizingDrag(-5f) assertThat(resized).isFalse() } companion object { private val TEST_SPEC = TileSpec.create("testSpec") } }
packages/SystemUI/multivalentTests/src/com/android/systemui/qs/panels/ui/compose/selection/ResizingStateTest.kt 0 → 100644 +62 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.systemui.qs.panels.ui.compose.selection import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.google.common.truth.Truth.assertThat import org.junit.Test import org.junit.runner.RunWith @SmallTest @RunWith(AndroidJUnit4::class) class ResizingStateTest : SysuiTestCase() { @Test fun drag_updatesStateCorrectly() { var resized = false val underTest = ResizingState(TileWidths(base = 0, min = 0, max = 10)) { resized = !resized } assertThat(underTest.width).isEqualTo(0) underTest.onDrag(2f) assertThat(underTest.width).isEqualTo(2) underTest.onDrag(1f) assertThat(underTest.width).isEqualTo(3) assertThat(resized).isTrue() underTest.onDrag(-1f) assertThat(underTest.width).isEqualTo(2) assertThat(resized).isFalse() } @Test fun dragOutOfBounds_isClampedCorrectly() { val underTest = ResizingState(TileWidths(base = 0, min = 0, max = 10)) {} assertThat(underTest.width).isEqualTo(0) underTest.onDrag(100f) assertThat(underTest.width).isEqualTo(10) underTest.onDrag(-200f) assertThat(underTest.width).isEqualTo(0) } }
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/DragAndDropState.kt +32 −29 Original line number Diff line number Diff line Loading @@ -17,9 +17,10 @@ package com.android.systemui.qs.panels.ui.compose import android.content.ClipData import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.draganddrop.dragAndDropSource import androidx.compose.foundation.draganddrop.dragAndDropTarget import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectDragGesturesAfterLongPress import androidx.compose.foundation.lazy.grid.LazyGridItemInfo import androidx.compose.foundation.lazy.grid.LazyGridState import androidx.compose.runtime.Composable Loading Loading @@ -104,11 +105,10 @@ fun Modifier.dragAndDropRemoveZone( @Composable fun Modifier.dragAndDropTileList( gridState: LazyGridState, contentOffset: Offset, contentOffset: () -> Offset, dragAndDropState: DragAndDropState, onDrop: () -> Unit, onDrop: (TileSpec) -> Unit, ): Modifier { val currentContentOffset by rememberUpdatedState(contentOffset) val target = remember(dragAndDropState) { object : DragAndDropTarget { Loading @@ -118,7 +118,7 @@ fun Modifier.dragAndDropTileList( override fun onMoved(event: DragAndDropEvent) { // Drag offset relative to the list's top left corner val relativeDragOffset = event.dragOffsetRelativeTo(currentContentOffset) val relativeDragOffset = event.dragOffsetRelativeTo(contentOffset()) val targetItem = gridState.layoutInfo.visibleItemsInfo.firstOrNull { item -> // Check if the drag is on this item Loading @@ -132,7 +132,7 @@ fun Modifier.dragAndDropTileList( override fun onDrop(event: DragAndDropEvent): Boolean { return dragAndDropState.draggedCell?.let { onDrop() onDrop(it.tile.tileSpec) dragAndDropState.onDrop() true } ?: false Loading @@ -158,24 +158,26 @@ private fun insertAfter(item: LazyGridItemInfo, offset: Offset): Boolean { return item.span != 1 && offset.x > itemCenter.x } @OptIn(ExperimentalFoundationApi::class) @Composable fun Modifier.dragAndDropTileSource( sizedTile: SizedTile<EditTileViewModel>, dragAndDropState: DragAndDropState, onTap: (TileSpec) -> Unit, onDoubleTap: (TileSpec) -> Unit = {}, onDragStart: () -> Unit, ): Modifier { val state by rememberUpdatedState(dragAndDropState) return dragAndDropSource { detectTapGestures( onTap = { onTap(sizedTile.tile.tileSpec) }, onDoubleTap = { onDoubleTap(sizedTile.tile.tileSpec) }, onLongPress = { state.onStarted(sizedTile) // The tilespec from the ClipData transferred isn't actually needed as we're moving // a tile within the same application. We're using a custom MIME type to limit the // drag event to QS. val dragState by rememberUpdatedState(dragAndDropState) @Suppress("DEPRECATION") // b/368361871 return dragAndDropSource( block = { detectDragGesturesAfterLongPress( onDrag = { _, _ -> }, onDragStart = { dragState.onStarted(sizedTile) onDragStart() // The tilespec from the ClipData transferred isn't actually needed as we're // moving a tile within the same application. We're using a custom MIME type to // limit the drag event to QS. startTransfer( DragAndDropTransferData( ClipData( Loading @@ -188,6 +190,7 @@ fun Modifier.dragAndDropTileSource( }, ) } ) } private object QsDragAndDrop { Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/EditTileListState.kt +4 −5 Original line number Diff line number Diff line Loading @@ -42,10 +42,8 @@ fun rememberEditListState( } /** Holds the temporary state of the tile list during a drag movement where we move tiles around. */ class EditTileListState( tiles: List<SizedTile<EditTileViewModel>>, private val columns: Int, ) : DragAndDropState { class EditTileListState(tiles: List<SizedTile<EditTileViewModel>>, private val columns: Int) : DragAndDropState { private val _draggedCell = mutableStateOf<SizedTile<EditTileViewModel>?>(null) override val draggedCell get() = _draggedCell.value Loading Loading @@ -91,7 +89,8 @@ class EditTileListState( regenerateGrid(includeSpacers = true) _tiles.add(insertionIndex.coerceIn(0, _tiles.size), cell) } else { // Add the tile with a temporary row which will get reassigned when regenerating spacers // Add the tile with a temporary row which will get reassigned when // regenerating spacers _tiles.add(insertionIndex.coerceIn(0, _tiles.size), TileGridCell(draggedTile, 0)) } Loading
packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt +3 −2 Original line number Diff line number Diff line Loading @@ -127,13 +127,14 @@ fun LargeTileContent( } @Composable private fun LargeTileLabels( fun LargeTileLabels( label: String, secondaryLabel: String?, colors: TileColors, modifier: Modifier = Modifier, accessibilityUiState: AccessibilityUiState? = null, ) { Column(verticalArrangement = Arrangement.Center, modifier = Modifier.fillMaxHeight()) { Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) { Text(label, color = colors.label, modifier = Modifier.tileMarquee()) if (!TextUtils.isEmpty(secondaryLabel)) { Text( Loading