Loading libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt +38 −0 Original line number Diff line number Diff line Loading @@ -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() ) } } libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt +2 −28 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading @@ -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, Loading libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt +2 −28 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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() ) } libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt +83 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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. */ Loading @@ -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 Loading Loading @@ -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) } } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/LetterboxUtils.kt +38 −0 Original line number Diff line number Diff line Loading @@ -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() ) } }
libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/MultiSurfaceLetterboxController.kt +2 −28 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading @@ -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, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/compatui/letterbox/SingleSurfaceLetterboxController.kt +2 −28 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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() ) }
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/letterbox/LetterboxUtilsTest.kt +83 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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. */ Loading @@ -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 Loading Loading @@ -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) } } }