Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5dd92350 authored by Massimo Carli's avatar Massimo Carli
Browse files

[18/n] Add common code to Letterboxutils

Moving common code to LetterboxUtils.

Flag: com.android.window.flags.app_compat_refactoring
Bug: 382423480
Fix: 381228823
Test: atest WMShellUnitTests:LetterboxUtilsTest
Test: atest WMShellUnitTests:SingleSurfaceLetterboxControllerTest
Test: atest WMShellUnitTests:MultiSurfaceLetterboxControllerTest

Change-Id: Ia1ad1b6a2aa0d5b680bb7a1419ec84e1e3f65cee
parent 255e687c
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -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()
                )
    }
}
+2 −28
Original line number Diff line number Diff line
@@ -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,
+2 −28
Original line number Diff line number Diff line
@@ -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()
            )
}
+83 −0
Original line number Diff line number Diff line
@@ -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)
        }
    }
}