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

Commit 15ae1670 authored by Lingyu Feng's avatar Lingyu Feng Committed by Android (Google) Code Review
Browse files

Merge "Add test scenarios for the mirror build-in display switch" into main

parents 13da0b98 0d4f2f2d
Loading
Loading
Loading
Loading
+27 −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.functional

import android.platform.test.annotations.Postsubmit
import com.android.wm.shell.scenarios.DisableDisplayMirroringSwitch
import org.junit.runner.RunWith
import org.junit.runners.BlockJUnit4ClassRunner

/* Functional test for [DisableDisplayMirroringSwitch]. */
@RunWith(BlockJUnit4ClassRunner::class)
@Postsubmit
class DisableDisplayMirroringSwitchTest : DisableDisplayMirroringSwitch()
 No newline at end of file
+27 −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.functional

import android.platform.test.annotations.Postsubmit
import com.android.wm.shell.scenarios.EnableDisplayMirroringSwitch
import org.junit.runner.RunWith
import org.junit.runners.BlockJUnit4ClassRunner

/* Functional test for [EnableDisplayMirroringSwitch]. */
@RunWith(BlockJUnit4ClassRunner::class)
@Postsubmit
class EnableDisplayMirroringSwitchTest : EnableDisplayMirroringSwitch()
 No newline at end of file
+73 −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.scenarios

import android.app.Instrumentation
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.provider.Settings
import android.tools.NavBar
import android.tools.Rotation
import android.tools.traces.parsers.WindowManagerStateHelper
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT
import com.android.systemui.shared.Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS
import com.android.window.flags.Flags.FLAG_ENABLE_TASKBAR_CONNECTED_DISPLAYS
import com.android.wm.shell.Utils
import org.junit.Assume
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import platform.test.desktop.SimulatedConnectedDisplayTestRule

@RequiresFlagsEnabled(
    FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT,
    FLAG_CONNECTED_DISPLAY_SETTINGS,
    FLAG_ENABLE_TASKBAR_CONNECTED_DISPLAYS,
    FLAG_STATUS_BAR_CONNECTED_DISPLAYS
)
abstract class DisableDisplayMirroringSwitch : TestScenarioBase() {
    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
    private val wmHelper = WindowManagerStateHelper(instrumentation)
    private val tapl = LauncherInstrumentation()

    @get:Rule(order = 0) val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
    @get:Rule(order = 1) val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL,
        Rotation.ROTATION_0)
    @get:Rule(order = 2) val connectedDisplayRule = SimulatedConnectedDisplayTestRule()

    @Before
    fun setup() {
        Assume.assumeTrue("isTablet", tapl.isTablet)
        // Ensure mirroring is enabled.
        Settings.Secure.putInt(instrumentation.context.contentResolver, MIRROR_SETTING, 1)
        connectedDisplayRule.setupTestDisplay()
    }

    @Test
    open fun disableMirrorBuiltInDisplaySwitch() {
        Utils.toggleMirroringSwitchViaSettingsApp()

        // TODO(b/420573458): Move assertions to flicker test
        wmHelper.StateSyncBuilder().withDesktopModeOnDisplay(connectedDisplayRule.addedDisplays[0])
            .waitForAndVerify()
    }
    private companion object {
        const val MIRROR_SETTING = Settings.Secure.MIRROR_BUILT_IN_DISPLAY
    }
}
 No newline at end of file
+77 −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.scenarios

import android.app.Instrumentation
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.DeviceFlagsValueProvider
import android.provider.Settings
import android.tools.NavBar
import android.tools.Rotation
import android.tools.traces.parsers.WindowManagerStateHelper
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.tapl.LauncherInstrumentation
import com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT
import com.android.systemui.shared.Flags.FLAG_STATUS_BAR_CONNECTED_DISPLAYS
import com.android.window.flags.Flags.FLAG_ENABLE_TASKBAR_CONNECTED_DISPLAYS
import com.android.wm.shell.Utils
import org.junit.Assume
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import platform.test.desktop.SimulatedConnectedDisplayTestRule

const val FLAG_CONNECTED_DISPLAY_SETTINGS: String =
    "com.android.settings.flags.display_topology_pane_in_display_list"

@RequiresFlagsEnabled(
    FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT,
    FLAG_CONNECTED_DISPLAY_SETTINGS,
    FLAG_ENABLE_TASKBAR_CONNECTED_DISPLAYS,
    FLAG_STATUS_BAR_CONNECTED_DISPLAYS
)
abstract class EnableDisplayMirroringSwitch : TestScenarioBase() {
    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
    private val wmHelper = WindowManagerStateHelper(instrumentation)
    private val tapl = LauncherInstrumentation()

    @get:Rule(order = 0) val checkFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
    @get:Rule(order = 1) val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL,
        Rotation.ROTATION_0)
    @get:Rule(order = 2) val connectedDisplayRule = SimulatedConnectedDisplayTestRule()

    @Before
    fun setup() {
        Assume.assumeTrue("isTablet", tapl.isTablet)
        // Ensure the mirroring is disabled.
        Settings.Secure.putInt(instrumentation.context.contentResolver,MIRROR_SETTING, 0)
        connectedDisplayRule.setupTestDisplay()
    }

    @Test
    open fun enableMirrorBuiltInDisplaySwitch() {
        Utils.toggleMirroringSwitchViaSettingsApp()

        // TODO(b/420573458): Move assertions to flicker test
        wmHelper.StateSyncBuilder().withEmptyDisplay(connectedDisplayRule.addedDisplays[0])
            .waitForAndVerify()
    }

    private companion object {
        const val MIRROR_SETTING = Settings.Secure.MIRROR_BUILT_IN_DISPLAY
    }
}
 No newline at end of file
+49 −2
Original line number Diff line number Diff line
@@ -17,10 +17,12 @@
package com.android.wm.shell

import android.app.Instrumentation
import android.content.Intent
import android.platform.test.rule.EnsureDeviceSettingsRule
import android.platform.test.rule.NavigationModeRule
import android.platform.test.rule.PressHomeRule
import android.platform.test.rule.UnlockScreenRule
import android.provider.Settings
import android.tools.NavBar
import android.tools.Rotation
import android.tools.device.apphelpers.MessagingAppHelper
@@ -30,12 +32,22 @@ import android.tools.flicker.rules.LaunchAppRule
import android.tools.flicker.rules.RemoveAllTasksButHomeRule
import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By.res
import androidx.test.uiautomator.By.text
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.Until.findObject
import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
import java.io.IOException
import org.junit.rules.RuleChain

object Utils {
    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
    private val device = UiDevice.getInstance(instrumentation)

    private val settingsResources = instrumentation.context.packageManager
        .getResourcesForApplication(SETTINGS_PACKAGE_NAME)

    private val externalDisplaySettings = getSettingsString(EXTERNAL_DISPLAY_SETTING)

    fun testSetupRule(navigationMode: NavBar, rotation: Rotation): RuleChain {
        return RuleChain.outerRule(ArtifactSaverRule())
@@ -62,10 +74,45 @@ object Utils {
     */
    fun resetFreezeRecentTaskList() {
        try {
            UiDevice.getInstance(instrumentation)
                .executeShellCommand("wm reset-freeze-recent-tasks")
            device.executeShellCommand("wm reset-freeze-recent-tasks")
        } catch (e: IOException) {
            Log.e("TestUtils", "Failed to reset frozen recent tasks list", e)
        }
    }

    fun toggleMirroringSwitchViaSettingsApp() {
        // Launch the Settings app and open the "External Display" settings list
        instrumentation.context
            .startActivity(
                Intent(Settings.ACTION_BLUETOOTH_SETTINGS)
                    .addCategory(Intent.CATEGORY_DEFAULT)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
            )
        waitFindObject(text(externalDisplaySettings)).click()

        // Maximize Settings app's window to avoid scrolling on the display topology settings panel
        // when looking for the mirroring switch
        val maximizeButton = device.wait(findObject(res(SETTINGS_MAXIMIZE_BUTTON_ID)),
            SETTINGS_UPDATE_TIME_OUT)
        maximizeButton?.click()

        // Find the mirroring switch and toggle it
        val switch = checkNotNull(device.wait(findObject(res(MIRROR_BUILT_IN_DISPLAY_SWITCH_ID)),
            SETTINGS_UPDATE_TIME_OUT))
        switch.click()
        device.waitForWindowUpdate(SETTINGS_PACKAGE_NAME,SETTINGS_UPDATE_TIME_OUT)
        device.waitForIdle()
    }

    private fun getSettingsString(resName: String): String {
        val identifier = settingsResources.getIdentifier(resName, "string",
            SETTINGS_PACKAGE_NAME)
        return settingsResources.getString(identifier)
    }

    private const val SETTINGS_PACKAGE_NAME = "com.android.settings"
    private const val EXTERNAL_DISPLAY_SETTING = "external_display_settings_title"
    private const val SETTINGS_MAXIMIZE_BUTTON_ID = "com.android.systemui:id/maximize_window"
    private const val MIRROR_BUILT_IN_DISPLAY_SWITCH_ID = "com.android.settings:id/switchWidget"
    private const val SETTINGS_UPDATE_TIME_OUT: Long = 2000
}