diff options
4 files changed, 125 insertions, 56 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt index ef964f40dab3..8e149ac2869a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt @@ -66,3 +66,41 @@ infix fun LetterboxController.append(other: LetterboxController) = object : Lett other.dump() } } + +object LetterboxUtils { + // Utility methods about Maps usage in Letterbox. + object Maps { + /* + * Executes [onFound] on the [item] for a given [key] if present or + * [onMissed] if the [key] is not present. + */ + fun <V, K> MutableMap<K, V>.runOnItem( + key: K, + onFound: (V) -> Unit = { _ -> }, + onMissed: ( + K, + MutableMap<K, V> + ) -> Unit = { _, _ -> } + ) { + this[key]?.let { + return onFound(it) + } + return onMissed(key, this) + } + } + + // Utility methods about Transaction usage in Letterbox. + object Transactions { + // Sets position and crops in one method. + fun Transaction.moveAndCrop( + surface: SurfaceControl, + rect: Rect + ): Transaction = + setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) + .setWindowCrop( + surface, + rect.width(), + rect.height() + ) + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt index 5129d03b9dbc..6861aa3763b5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt @@ -20,6 +20,8 @@ import android.graphics.Rect import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import com.android.wm.shell.dagger.WMSingleton import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT import javax.inject.Inject @@ -101,23 +103,6 @@ class MultiSurfaceLetterboxController @Inject constructor( ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}") } - /* - * Executes [onFound] on the [LetterboxItem] if present or [onMissed] if not present. - */ - private fun MutableMap<LetterboxKey, LetterboxSurfaces>.runOnItem( - key: LetterboxKey, - onFound: (LetterboxSurfaces) -> Unit = { _ -> }, - onMissed: ( - LetterboxKey, - MutableMap<LetterboxKey, LetterboxSurfaces> - ) -> Unit = { _, _ -> } - ) { - this[key]?.let { - return onFound(it) - } - return onMissed(key, this) - } - private fun SurfaceControl?.remove( tx: Transaction ) = this?.let { @@ -131,17 +116,6 @@ class MultiSurfaceLetterboxController @Inject constructor( tx.setVisibility(this, visible) } - private fun Transaction.moveAndCrop( - surface: SurfaceControl, - rect: Rect - ): Transaction = - setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) - .setWindowCrop( - surface, - rect.width(), - rect.height() - ) - private fun LetterboxSurfaces.updateSurfacesBounds( tx: Transaction, taskBounds: Rect, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt index a67f6082c892..8e1cdee0c862 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt @@ -20,6 +20,8 @@ import android.graphics.Rect import android.view.SurfaceControl import android.view.SurfaceControl.Transaction import com.android.internal.protolog.ProtoLog +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import com.android.wm.shell.dagger.WMSingleton import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_APP_COMPAT import javax.inject.Inject @@ -106,32 +108,4 @@ class SingleSurfaceLetterboxController @Inject constructor( override fun dump() { ProtoLog.v(WM_SHELL_APP_COMPAT, "%s: %s", TAG, "${letterboxMap.keys}") } - - /* - * Executes [onFound] on the [SurfaceControl] if present or [onMissed] if not present. - */ - private fun MutableMap<LetterboxKey, SurfaceControl>.runOnItem( - key: LetterboxKey, - onFound: (SurfaceControl) -> Unit = { _ -> }, - onMissed: ( - LetterboxKey, - MutableMap<LetterboxKey, SurfaceControl> - ) -> Unit = { _, _ -> } - ) { - this[key]?.let { - return onFound(it) - } - return onMissed(key, this) - } - - private fun Transaction.moveAndCrop( - surface: SurfaceControl, - rect: Rect - ): Transaction = - setPosition(surface, rect.left.toFloat(), rect.top.toFloat()) - .setWindowCrop( - surface, - rect.width(), - rect.height() - ) } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt index 06b805233ee7..667511288bfa 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt @@ -19,9 +19,14 @@ package com.android.wm.shell.compatui.letterbox import android.content.Context import android.graphics.Rect import android.testing.AndroidTestingRunner +import android.view.SurfaceControl import androidx.test.filters.SmallTest import com.android.wm.shell.ShellTestCase +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Maps.runOnItem +import com.android.wm.shell.compatui.letterbox.LetterboxUtils.Transactions.moveAndCrop import java.util.function.Consumer +import kotlin.test.assertEquals +import kotlin.test.assertNull import org.junit.Test import org.junit.runner.RunWith import org.mockito.kotlin.any @@ -100,6 +105,35 @@ class LetterboxUtilsTest : ShellTestCase() { } } + @Test + fun `runOnItem executes onFound when an item has been found for a key`() { + runTestScenario { r -> + r.initMap(1 to 2, 3 to 4) + r.runOnItem<Int>(1) + r.verifyOnItemInvoked(expectedItem = 2) + r.verifyOnMissingNotInvoked() + } + } + + @Test + fun `runOnItem executes onMissing when an item has not been found for a key`() { + runTestScenario { r -> + r.initMap(1 to 2, 3 to 4) + r.runOnItem<Int>(8) + r.verifyOnItemNotInvoked() + r.verifyOnMissingInvoked(expectedKey = 8) + } + } + + @Test + fun `moveAndCrop invoked Move and then Crop`() { + runTestScenario { r -> + r.invoke(Rect(1, 2, 51, 62)) + r.verifySetPosition(expectedX = 1f, expectedY = 2f) + r.verifySetWindowCrop(expectedWidth = 50, expectedHeight = 60) + } + } + /** * Runs a test scenario providing a Robot. */ @@ -113,6 +147,14 @@ class LetterboxUtilsTest : ShellTestCase() { builder: (LetterboxSurfaceBuilder) -> LetterboxController ) : LetterboxControllerRobotTest(ctx, builder) { + private var testableMap = mutableMapOf<Int, Int>() + private var onItemState: Int? = null + private var onMissingStateKey: Int? = null + private var onMissingStateMap: MutableMap<Int, Int>? = null + + private val transaction = getTransactionMock() + private val surface = SurfaceControl() + fun verifyCreateSurfaceInvokedWithRequest( target: LetterboxController, times: Int = 1 @@ -147,5 +189,46 @@ class LetterboxUtilsTest : ShellTestCase() { ) { verify(target, times(times)).dump() } + + fun initMap(vararg values: Pair<Int, Int>) = testableMap.putAll(values.toMap()) + + fun <T> runOnItem(key: Int) { + testableMap.runOnItem(key, onFound = { item -> + onItemState = item + }, onMissed = { k, m -> + onMissingStateKey = k + onMissingStateMap = m + }) + } + + fun verifyOnItemInvoked(expectedItem: Int) { + assertEquals(expectedItem, onItemState) + } + + fun verifyOnItemNotInvoked() { + assertNull(onItemState) + } + + fun verifyOnMissingInvoked(expectedKey: Int) { + assertEquals(expectedKey, onMissingStateKey) + assertEquals(onMissingStateMap, testableMap) + } + + fun verifyOnMissingNotInvoked() { + assertNull(onMissingStateKey) + assertNull(onMissingStateMap) + } + + fun invoke(rect: Rect) { + transaction.moveAndCrop(surface, rect) + } + + fun verifySetPosition(expectedX: Float, expectedY: Float) { + verify(transaction).setPosition(surface, expectedX, expectedY) + } + + fun verifySetWindowCrop(expectedWidth: Int, expectedHeight: Int) { + verify(transaction).setWindowCrop(surface, expectedWidth, expectedHeight) + } } } |