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

Commit 8e1449eb authored by Massimo Carli's avatar Massimo Carli
Browse files

[68/n] Add isTranslucent to LetterboxLifecycleEvent

LetterboxLifecycleEvent might contain information about
transparency to be used as a criteria for the multiple
or single letterbox surfaces.

LetterboxLifecycleEventUtils has been created accordingly and
dependent tests improved.

Flag: EXEMPT Refactoring
Bug: 377875146
Test: atest WMShellUnitTests:TaskInfoLetterboxLifecycleEventFactoryTest
Test: atest WMShellUnitTests:ActivityLetterboxLifecycleEventFactoryTest
Test: atest WMShellUnitTests:LetterboxLifecycleEventTest
Test: atest WMShellUnitTests:LetterboxTaskListenerAdapterTest

Change-Id: I86e7f1beb398abf6893fd5dfa838e6c7b0898dd0
parent 6aa4dd37
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -64,7 +64,8 @@ class ActivityLetterboxLifecycleEventFactory(
                taskBounds = taskBounds,
                letterboxBounds = letterboxBounds,
                taskLeash = taskItem.containerLeash,
                containerToken = taskItem.containerToken
                containerToken = taskItem.containerToken,
                isTranslucent = change.isTranslucent()
            )
        }
        ProtoLog.w(WM_SHELL_APP_COMPAT, "$TAG: Task not found for taskId: $taskId")
+8 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.wm.shell.compatui.letterbox.lifecycle
import android.graphics.Rect
import android.view.SurfaceControl
import android.window.TransitionInfo.Change
import android.window.TransitionInfo.FLAG_TRANSLUCENT
import android.window.WindowContainerToken
import com.android.wm.shell.compatui.letterbox.LetterboxKey
import com.android.wm.shell.compatui.letterbox.lifecycle.LetterboxLifecycleEventType.CLOSE
@@ -44,7 +45,8 @@ data class LetterboxLifecycleEvent(
    val letterboxBounds: Rect? = null,
    val containerToken: WindowContainerToken? = null,
    val taskLeash: SurfaceControl? = null,
    val isBubble: Boolean = false
    val isBubble: Boolean = false,
    val isTranslucent: Boolean = false
)

/**
@@ -80,6 +82,11 @@ fun Change.shouldSkipForLetterbox(): Boolean =
 */
fun Change.isActivityChange(): Boolean = activityTransitionInfo != null

/**
 * Returns [true] if the [Change] is related to a translucent container.
 */
fun Change.isTranslucent() = hasFlags(FLAG_TRANSLUCENT)

/** Returns [true] if the Task hosts Activities */
fun Change.isChangeForALeafTask(): Boolean =
    taskInfo?.appCompatTaskInfo?.isLeafTask() ?: false
+2 −1
Original line number Diff line number Diff line
@@ -50,7 +50,8 @@ class TaskInfoLetterboxLifecycleEventFactory : LetterboxLifecycleEventFactory {
                letterboxBounds = letterboxBounds,
                containerToken = ti.token,
                taskLeash = change.leash,
                isBubble = ti.isAppBubble
                isBubble = ti.isAppBubble,
                isTranslucent = change.isTranslucent()
            )
        }
        return null
+30 −22
Original line number Diff line number Diff line
@@ -25,10 +25,14 @@ import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.compatui.letterbox.state.LetterboxTaskInfoRepository
import com.android.wm.shell.compatui.letterbox.state.LetterboxTaskInfoState
import com.android.wm.shell.util.testLetterboxLifecycleEventFactory
import java.util.function.Consumer
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import java.util.function.Consumer
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNull
import kotlin.test.assertTrue

/**
 * Tests for [ActivityLetterboxLifecycleEventFactory].
@@ -48,7 +52,7 @@ class ActivityLetterboxLifecycleEventFactoryTest : ShellTestCase() {
                    // Empty Change
                }
                validateCanHandle { canHandle ->
                    assert(canHandle == false)
                    assertFalse(canHandle)
                }
            }
        }
@@ -58,14 +62,20 @@ class ActivityLetterboxLifecycleEventFactoryTest : ShellTestCase() {
    fun `Read Task bounds from endAbsBounds in Change`() {
        runTestScenario { r ->
            testLetterboxLifecycleEventFactory(r.getLetterboxLifecycleEventFactory()) {
                val testLeash = mock<SurfaceControl>()
                val testToken = mock<WindowContainerToken>()
                inputChange {
                    activityTransitionInfo {
                        taskId = 10
                    }
                    endAbsBounds = Rect(100, 50, 2000, 1500)
                }
                r.addToTaskRepository(10, LetterboxTaskInfoState(testToken, testLeash))
                validateCanHandle { canHandle ->
                    assert(canHandle == false)
                    assertTrue(canHandle)
                }
                validateCreateLifecycleEvent { event ->
                    assert(event?.taskBounds == Rect(0, 0, 1900, 1450))
                    assertEquals(Rect(0, 0, 1900, 1450), event?.taskBounds)
                }
            }
        }
@@ -75,20 +85,24 @@ class ActivityLetterboxLifecycleEventFactoryTest : ShellTestCase() {
    fun `Read Letterbox bounds from activityTransitionInfo and endAbsBounds in Change`() {
        runTestScenario { r ->
            testLetterboxLifecycleEventFactory(r.getLetterboxLifecycleEventFactory()) {
                val testLeash = mock<SurfaceControl>()
                val testToken = mock<WindowContainerToken>()
                inputChange {
                    endAbsBounds = Rect(100, 50, 2000, 1500)
                    activityTransitionInfo {
                        taskId = 10
                        appCompatTransitionInfo {
                            letterboxBounds = Rect(500, 50, 1500, 800)
                        }
                    }
                }
                r.addToTaskRepository(10, LetterboxTaskInfoState(testToken, testLeash))
                validateCanHandle { canHandle ->
                    assert(canHandle == false)
                    assertTrue(canHandle)
                }
                validateCreateLifecycleEvent { event ->
                    assert(event?.taskBounds == Rect(0, 0, 1900, 1450))
                    assert(event?.letterboxBounds == Rect(400, 0, 1400, 750))
                    assertEquals(Rect(0, 0, 1900, 1450), event?.taskBounds)
                    assertEquals(Rect(400, 0, 1400, 750), event?.letterboxBounds)
                }
            }
        }
@@ -102,18 +116,16 @@ class ActivityLetterboxLifecycleEventFactoryTest : ShellTestCase() {
                val testToken = mock<WindowContainerToken>()
                r.addToTaskRepository(10, LetterboxTaskInfoState(testToken, testLeash))
                inputChange {
                    leash { testLeash }
                    token { testToken }
                    runningTaskInfo { ti ->
                        ti.taskId = 10
                    activityTransitionInfo {
                        taskId = 10
                    }
                }
                validateCanHandle { canHandle ->
                    assert(canHandle == false)
                    assertTrue(canHandle)
                }
                validateCreateLifecycleEvent { event ->
                    assert(event?.taskLeash == testLeash)
                    assert(event?.containerToken == testToken)
                    assertEquals(testLeash, event?.taskLeash)
                    assertEquals(testToken, event?.containerToken)
                }
            }
        }
@@ -123,20 +135,16 @@ class ActivityLetterboxLifecycleEventFactoryTest : ShellTestCase() {
    fun `Event is null if repository has no task data`() {
        runTestScenario { r ->
            testLetterboxLifecycleEventFactory(r.getLetterboxLifecycleEventFactory()) {
                val testLeash = mock<SurfaceControl>()
                val testToken = mock<WindowContainerToken>()
                inputChange {
                    leash { testLeash }
                    token { testToken }
                    runningTaskInfo { ti ->
                        ti.taskId = 10
                    activityTransitionInfo {
                        taskId = 10
                    }
                }
                validateCanHandle { canHandle ->
                    assert(canHandle == false)
                    assertTrue(canHandle)
                }
                validateCreateLifecycleEvent { event ->
                    assert(event == null)
                    assertNull(event)
                }
            }
        }
+154 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.wm.shell.compatui.letterbox.lifecycle

import android.testing.AndroidTestingRunner
import android.view.WindowManager
import android.window.TransitionInfo.FLAG_TRANSLUCENT
import androidx.test.filters.SmallTest
import com.android.wm.shell.compatui.letterbox.lifecycle.LetterboxLifecycleEventType.CLOSE
import com.android.wm.shell.compatui.letterbox.lifecycle.LetterboxLifecycleEventType.OPEN
import com.android.wm.shell.util.testLetterboxLifecycleEvent
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import org.junit.Test
import org.junit.runner.RunWith

/**
 * Tests for [LetterboxLifecycleEvent].
 *
 * Build/Install/Run:
 *  atest WMShellUnitTests:LetterboxLifecycleEventTest
 */
@RunWith(AndroidTestingRunner::class)
@SmallTest
class LetterboxLifecycleEventTest {

    @Test
    fun `asLetterboxLifecycleEventType returns the right type for OPEN modes`() {
        testLetterboxLifecycleEvent {
            inputChange {
                mode = WindowManager.TRANSIT_OPEN
            }
            useChange { change ->
                assertEquals(OPEN, change.asLetterboxLifecycleEventType())
            }
            inputChange {
                mode = WindowManager.TRANSIT_TO_FRONT
            }
            useChange { change ->
                assertEquals(OPEN, change.asLetterboxLifecycleEventType())
            }
            inputChange {
                mode = WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION
            }
            useChange { change ->
                assertEquals(OPEN, change.asLetterboxLifecycleEventType())
            }
        }
    }

    @Test
    fun `asLetterboxLifecycleEventType returns the right type for CLOSE modes`() {
        testLetterboxLifecycleEvent {
            inputChange {
                mode = WindowManager.TRANSIT_CLOSE
            }
            useChange { change ->
                assertEquals(CLOSE, change.asLetterboxLifecycleEventType())
            }
            inputChange {
                mode = WindowManager.TRANSIT_TO_BACK
            }
            useChange { change ->
                assertEquals(CLOSE, change.asLetterboxLifecycleEventType())
            }
        }
    }

    @Test
    fun `isActivityChange returns true if activityTransitionInfo is present`() {
        testLetterboxLifecycleEvent {
            inputChange {
            }
            useChange { change ->
                assertFalse(change.isActivityChange())
            }
            inputChange {
                activityTransitionInfo { }
            }
            useChange { change ->
                assertTrue(change.isActivityChange())
            }
        }
    }

    @Test
    fun `isChangeForALeafTask returns true if the task is a leaf`() {
        testLetterboxLifecycleEvent {
            inputChange {
            }
            useChange { change ->
                assertFalse(change.isChangeForALeafTask())
            }

            inputChange {
                runningTaskInfo { }
            }
            useChange { change ->
                assertFalse(change.isChangeForALeafTask())
            }

            inputChange {
                runningTaskInfo { ti ->
                    activityTransitionInfo {
                    }
                }
            }
            useChange { change ->
                assertFalse(change.isChangeForALeafTask())
            }

            inputChange {
                runningTaskInfo { ti ->
                    ti.appCompatTaskInfo.setIsLeafTask(true)
                }
            }
            useChange { change ->
                assertTrue(change.isChangeForALeafTask())
            }
        }
    }

    @Test
    fun `isTranslucent returns true if the FLAG_TRANSLUCENT flag is present in Change`() {
        testLetterboxLifecycleEvent {
            inputChange { }
            useChange { change ->
                assert(!change.isTranslucent())
            }

            inputChange {
                flags = FLAG_TRANSLUCENT
            }
            useChange { change ->
                assert(!change.isTranslucent())
            }
        }
    }
}
Loading