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

Commit 4c3c5e9f authored by Chris Göllner's avatar Chris Göllner Committed by Android (Google) Code Review
Browse files

Merge "Shortcut Helper - Set System as default category when launcher is open" into main

parents 20d6e3f8 c961c1ce
Loading
Loading
Loading
Loading
+18 −8
Original line number Diff line number Diff line
@@ -26,8 +26,10 @@ import android.view.WindowInsets
import androidx.activity.BackEventCompat
import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalContext
import androidx.core.view.updatePadding
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.flowWithLifecycle
@@ -36,6 +38,7 @@ import com.android.compose.theme.PlatformTheme
import com.android.systemui.keyboard.shortcut.ui.composable.ShortcutHelper
import com.android.systemui.keyboard.shortcut.ui.viewmodel.ShortcutHelperViewModel
import com.android.systemui.res.R
import com.android.systemui.settings.UserTracker
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_HIDDEN
@@ -49,6 +52,7 @@ import kotlinx.coroutines.launch
class ShortcutHelperActivity
@Inject
constructor(
    private val userTracker: UserTracker,
    private val viewModel: ShortcutHelperViewModel,
) : ComponentActivity() {

@@ -79,8 +83,10 @@ constructor(
    private fun setUpComposeView() {
        requireViewById<ComposeView>(R.id.shortcut_helper_compose_container).apply {
            setContent {
                CompositionLocalProvider(LocalContext provides userTracker.userContext) {
                    PlatformTheme {
                    val shortcutsUiState by viewModel.shortcutsUiState.collectAsStateWithLifecycle()
                        val shortcutsUiState by
                            viewModel.shortcutsUiState.collectAsStateWithLifecycle()
                        ShortcutHelper(
                            shortcutsUiState = shortcutsUiState,
                            onKeyboardSettingsClicked = ::onKeyboardSettingsClicked,
@@ -90,10 +96,14 @@ constructor(
                }
            }
        }
    }

    private fun onKeyboardSettingsClicked() {
        try {
            startActivity(Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS))
            startActivityAsUser(
                Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS),
                userTracker.userHandle
            )
        } catch (e: ActivityNotFoundException) {
            // From the Settings docs: In some cases, a matching Activity may not exist, so ensure
            // you safeguard against this.
+16 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.keyboard.shortcut.ui.viewmodel

import android.app.role.RoleManager
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperCategoriesInteractor
import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperStateInteractor
@@ -25,6 +26,7 @@ import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.CurrentApp
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutSubCategory
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutsUiState
import com.android.systemui.settings.UserTracker
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
@@ -35,10 +37,13 @@ import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext

class ShortcutHelperViewModel
@Inject
constructor(
    private val roleManager: RoleManager,
    private val userTracker: UserTracker,
    @Background private val backgroundScope: CoroutineScope,
    @Background private val backgroundDispatcher: CoroutineDispatcher,
    private val stateInteractor: ShortcutHelperStateInteractor,
@@ -72,13 +77,22 @@ constructor(
                initialValue = ShortcutsUiState.Inactive
            )

    private fun getDefaultSelectedCategory(
    private suspend fun getDefaultSelectedCategory(
        categories: List<ShortcutCategory>
    ): ShortcutCategoryType? {
        val currentAppShortcuts = categories.firstOrNull { it.type is CurrentApp }
        val currentAppShortcuts =
            categories.firstOrNull { it.type is CurrentApp && !isAppLauncher(it.type.packageName) }
        return currentAppShortcuts?.type ?: categories.firstOrNull()?.type
    }

    private suspend fun isAppLauncher(packageName: String): Boolean {
        return withContext(backgroundDispatcher) {
            roleManager
                .getRoleHoldersAsUser(RoleManager.ROLE_HOME, userTracker.userHandle)
                .firstOrNull() == packageName
        }
    }

    private fun filterCategoriesBySearchQuery(
        query: String,
        categories: List<ShortcutCategory>
+30 −5
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.keyboard.shortcut.ui.viewmodel

import android.app.role.RoleManager
import android.app.role.mockRoleManager
import android.view.KeyEvent
import android.view.KeyboardShortcutGroup
import android.view.KeyboardShortcutInfo
@@ -45,7 +47,9 @@ import com.android.systemui.kosmos.testCase
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SHORTCUT_HELPER_SHOWING
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -77,12 +81,15 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
    private val testScope = kosmos.testScope
    private val testHelper = kosmos.shortcutHelperTestHelper
    private val sysUiState = kosmos.sysUiState
    private val fakeUserTracker = kosmos.fakeUserTracker
    private val mockRoleManager = kosmos.mockRoleManager
    private val viewModel = kosmos.shortcutHelperViewModel

    @Before
    fun setUp() {
        fakeSystemSource.setGroups(TestShortcuts.systemGroups)
        fakeMultiTaskingSource.setGroups(TestShortcuts.multitaskingGroups)
        fakeCurrentAppsSource.setGroups(TestShortcuts.currentAppGroups)
    }

    @Test
@@ -216,21 +223,21 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
        }

    @Test
    fun shortcutsUiState_featureActive_emitsActiveWithFirstCategorySelectedByDefault() =
    fun shortcutsUiState_noCurrentAppCategory_defaultSelectedCategoryIsSystem() =
        testScope.runTest {
            fakeCurrentAppsSource.setGroups(emptyList())

            val uiState by collectLastValue(viewModel.shortcutsUiState)

            testHelper.showFromActivity()

            val activeUiState = uiState as ShortcutsUiState.Active
            assertThat(activeUiState.defaultSelectedCategory)
                .isEqualTo(activeUiState.shortcutCategories.first().type)
            assertThat(activeUiState.defaultSelectedCategory).isEqualTo(System)
        }

    @Test
    fun shortcutsUiState_featureActive_emitsActiveWithCurrentAppsCategorySelectedWhenPresent() =
    fun shortcutsUiState_currentAppCategoryPresent_currentAppIsDefaultSelected() =
        testScope.runTest {
            fakeCurrentAppsSource.setGroups(TestShortcuts.currentAppGroups)
            val uiState by collectLastValue(viewModel.shortcutsUiState)

            testHelper.showFromActivity()
@@ -240,6 +247,24 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
                .isEqualTo(CurrentApp(TestShortcuts.currentAppPackageName))
        }

    @Test
    fun shortcutsUiState_currentAppIsLauncher_defaultSelectedCategoryIsSystem() =
        testScope.runTest {
            whenever(
                    mockRoleManager.getRoleHoldersAsUser(
                        RoleManager.ROLE_HOME,
                        fakeUserTracker.userHandle
                    )
                )
                .thenReturn(listOf(TestShortcuts.currentAppPackageName))
            val uiState by collectLastValue(viewModel.shortcutsUiState)

            testHelper.showFromActivity()

            val activeUiState = uiState as ShortcutsUiState.Active
            assertThat(activeUiState.defaultSelectedCategory).isEqualTo(System)
        }

    @Test
    fun shortcutsUiState_userTypedQuery_filtersMatchingShortcutLabels() =
        testScope.runTest {
+24 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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 android.app.role

import com.android.systemui.kosmos.Kosmos
import com.android.systemui.util.mockito.mock

val Kosmos.mockRoleManager: RoleManager by Kosmos.Fixture { mock() }

var Kosmos.roleManager: RoleManager by Kosmos.Fixture { mockRoleManager }
+4 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.keyboard.shortcut

import android.app.role.mockRoleManager
import android.content.applicationContext
import android.content.res.mainResources
import android.hardware.input.fakeInputManager
@@ -41,6 +42,7 @@ import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
import com.android.systemui.settings.displayTracker
import com.android.systemui.settings.fakeUserTracker

var Kosmos.shortcutHelperAppCategoriesShortcutsSource: KeyboardShortcutGroupsSource by
    Kosmos.Fixture {
@@ -117,6 +119,8 @@ val Kosmos.shortcutHelperCategoriesInteractor by
val Kosmos.shortcutHelperViewModel by
    Kosmos.Fixture {
        ShortcutHelperViewModel(
            mockRoleManager,
            fakeUserTracker,
            applicationCoroutineScope,
            testDispatcher,
            shortcutHelperStateInteractor,