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

Commit 92cdc169 authored by Josh's avatar Josh
Browse files

Added multi-display support for shortcut helper

Shortcut helper will now be triggered on the currently focused display.

Flag: com.android.systemui.shortcut_helper_multi_display_support
Test: ShortcutHelperViewModelTest
Fix: 406740115
Change-Id: If7ee3fdab1d5a27660ab41b9893d77325a4e207b
parent 5e3a355a
Loading
Loading
Loading
Loading
+23 −5
Original line number Diff line number Diff line
@@ -22,10 +22,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutHelperState.Active
import com.android.systemui.keyboard.shortcut.shortcutHelperStateRepository
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.shade.data.repository.fakeFocusedDisplayRepository
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
@@ -51,7 +54,7 @@ class ShortcutHelperStateRepositoryTest : SysuiTestCase() {

            helper.toggle(deviceId)

            assertThat(state).isEqualTo(ShortcutHelperState.Active(deviceId))
            assertThat(state).isEqualTo(Active(deviceId))
        }

    @Test
@@ -61,7 +64,7 @@ class ShortcutHelperStateRepositoryTest : SysuiTestCase() {

            helper.showFromActivity()

            assertThat(state).isEqualTo(ShortcutHelperState.Active(VIRTUAL_KEYBOARD))
            assertThat(state).isEqualTo(Active(VIRTUAL_KEYBOARD))
        }

    @Test
@@ -73,7 +76,7 @@ class ShortcutHelperStateRepositoryTest : SysuiTestCase() {
            fakeInputManager.addPhysicalKeyboard(deviceId)
            helper.showFromActivity()

            assertThat(state).isEqualTo(ShortcutHelperState.Active(deviceId))
            assertThat(state).isEqualTo(Active(deviceId))
        }

    @Test
@@ -86,6 +89,21 @@ class ShortcutHelperStateRepositoryTest : SysuiTestCase() {
            fakeInputManager.inputManager.disableInputDevice(deviceId)
            helper.showFromActivity()

            assertThat(state).isEqualTo(ShortcutHelperState.Active(VIRTUAL_KEYBOARD))
            assertThat(state).isEqualTo(Active(VIRTUAL_KEYBOARD))
        }

    @Test
    fun activeStateDisplayId_isFocusedDisplay() =
        kosmos.runTest {
            val state by collectLastValue(repo.state)

            fakeFocusedDisplayRepository.setDisplayId(DISPLAY_ID)
            helper.showFromActivity()

            assertThat((state as Active).displayId).isEqualTo(DISPLAY_ID)
        }

    private companion object {
        const val DISPLAY_ID = 5
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.systemui.keyboard.shortcut.ui

import android.content.Context
import android.content.Context.INPUT_SERVICE
import android.content.applicationContext
import android.hardware.input.fakeInputManager
import androidx.test.annotation.UiThreadTest
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -83,10 +84,12 @@ class ShortcutHelperDialogStarterTest : SysuiTestCase() {
        with(kosmos) {
            ShortcutHelperDialogStarter(
                coroutineScope,
                applicationContext,
                viewModel,
                shortcutCustomizationDialogStarterFactory,
                dialogFactory,
                activityStarter,
                testDispatcher,
            )
        }

+45 −0
Original line number Diff line number Diff line
@@ -19,9 +19,11 @@ package com.android.systemui.keyboard.shortcut.ui.viewmodel
import android.app.role.RoleManager
import android.app.role.mockRoleManager
import android.content.Context
import android.content.applicationContext
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.NameNotFoundException
import android.view.Display
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Tv
import androidx.compose.material.icons.filled.VerticalSplit
@@ -42,18 +44,24 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import com.android.systemui.keyboard.shortcut.shared.model.shortcut
import com.android.systemui.keyboard.shortcut.shortcutHelperCategoriesInteractor
import com.android.systemui.keyboard.shortcut.shortcutHelperCustomizationModeInteractor
import com.android.systemui.keyboard.shortcut.shortcutHelperStateInteractor
import com.android.systemui.keyboard.shortcut.shortcutHelperTestHelper
import com.android.systemui.keyboard.shortcut.shortcutHelperViewModel
import com.android.systemui.keyboard.shortcut.ui.model.IconSource
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCategoryUi
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel.Companion.EXTENDED_APPS_SHORTCUT_CUSTOMIZATION_LIMIT
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.model.sysUiState
import com.android.systemui.settings.FakeUserTracker
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.settings.userTracker
import com.android.systemui.shade.data.repository.fakeFocusedDisplayRepository
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SHORTCUT_HELPER_SHOWING
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
@@ -89,6 +97,20 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
    private val fakeUserTracker = kosmos.fakeUserTracker
    private val mockRoleManager = kosmos.mockRoleManager
    private val underTest = kosmos.shortcutHelperViewModel
    private val secondaryDisplayViewModel =
        with(kosmos) {
            ShortcutHelperViewModel(
                applicationContext,
                mockRoleManager,
                userTracker,
                applicationCoroutineScope,
                testDispatcher,
                shortcutHelperStateInteractor,
                shortcutHelperCategoriesInteractor,
                shortcutHelperCustomizationModeInteractor,
                displayId = SECONDARY_DISPLAY,
            )
        }
    private val fakeDefaultShortcutCategoriesRepository =
        kosmos.fakeDefaultShortcutCategoriesRepository
    private val fakeCustomShortcutCategoriesRepository =
@@ -199,6 +221,28 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
            assertThat(shouldShowNew).isEqualTo(shouldShow)
        }

    @Test
    fun shouldShow_falseWhenShortcutHelperTriggeredFromDifferentDisplay() =
        testScope.runTest {
            kosmos.fakeFocusedDisplayRepository.setDisplayId(Display.DEFAULT_DISPLAY)
            val shouldShow by collectLastValue(secondaryDisplayViewModel.shouldShow)

            testHelper.showFromActivity()

            assertThat(shouldShow).isFalse()
        }

    @Test
    fun shouldShow_TrueWhenShortcutHelperTriggeredFromSameDisplay() =
        testScope.runTest {
            kosmos.fakeFocusedDisplayRepository.setDisplayId(SECONDARY_DISPLAY)
            val shouldShow by collectLastValue(secondaryDisplayViewModel.shouldShow)

            testHelper.showFromActivity()

            assertThat(shouldShow).isTrue()
        }

    @Test
    fun sysUiStateFlag_disabledByDefault() =
        testScope.runTest {
@@ -664,5 +708,6 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
        const val FIRST_SIMPLE_GROUP_LABEL = "simple group 1"
        const val SECOND_SIMPLE_GROUP_LABEL = "simple group 2"
        const val TEST_PACKAGE = "test.package.name"
        const val SECONDARY_DISPLAY = 5
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -110,5 +110,9 @@ interface SystemUIDisplaySubcomponent {
         * removed, and the component will be destroyed.
         */
        fun stop() {}

        companion object {
            val NOP: LifecycleListener = object : LifecycleListener {}
        }
    }
}
+69 −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.systemui.keyboard.shortcut

import android.view.Display
import com.android.systemui.Flags
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.DisplayAware
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.PerDisplaySingleton
import com.android.systemui.keyboard.shortcut.ui.ShortcutHelperDialogStarter
import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel
import dagger.Binds
import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.multibindings.IntoSet

/**
 * Contains bindings that are [SystemUIDisplaySubcomponent.DisplayAware] related to the shortcut
 * helper.
 */
@Module
interface ShortcutHelperDisplayModule {

    @Binds
    @PerDisplaySingleton
    @DisplayAware
    fun shortcutHelperViewModel(impl: ShortcutHelperViewModel): ShortcutHelperViewModel

    @Binds
    @PerDisplaySingleton
    @DisplayAware
    fun provideShortcutHelperDialogStarter(
        impl: ShortcutHelperDialogStarter
    ): ShortcutHelperDialogStarter

    companion object {
        @Provides
        @PerDisplaySingleton
        @DisplayAware
        @IntoSet
        fun provideShortcutHelperDialogStarterLifeCycleObserver(
            @DisplayAware implLazy: Lazy<ShortcutHelperDialogStarter>,
            @DisplayAware displayId: Int,
        ): SystemUIDisplaySubcomponent.LifecycleListener {
            return if (
                displayId == Display.DEFAULT_DISPLAY || Flags.shortcutHelperMultiDisplaySupport()
            ) {
                implLazy.get()
            } else {
                SystemUIDisplaySubcomponent.LifecycleListener.NOP
            }
        }
    }
}
Loading