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) +        }      }  }  |