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

Commit 60654dd6 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Added logic for limiting extra apps shortcut customization" into main

parents b9a80dfa 75314ea1
Loading
Loading
Loading
Loading
+99 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.systemui.keyboard.shortcut.defaultShortcutCategoriesRepositor
import com.android.systemui.keyboard.shortcut.fakeCustomShortcutCategoriesRepository
import com.android.systemui.keyboard.shortcut.fakeDefaultShortcutCategoriesRepository
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
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.ShortcutCategoryType.MultiTasking
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.System
@@ -46,6 +47,7 @@ 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.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.model.sysUiState
@@ -468,6 +470,78 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
        }
    }

    @Test
    fun allowExtendedAppShortcutsCustomization_true_WhenExtraAppsShortcutsCustomizedIsBelowLimit() {
        testScope.runTest {
            setupShortcutHelperWithExtendedAppsShortcutCustomizations(
                numberOfDefaultAppsShortcuts = 3,
                numberOfCustomShortcutsForDefaultApps = 3,
                numberOfCustomShortcutsForExtendedApps = 3,
            )

            underTest.toggleCustomizationMode(true)
            val uiState by collectLastValue(underTest.shortcutsUiState)

            val activeUiState = uiState as ShortcutsUiState.Active

            assertThat(activeUiState.allowExtendedAppShortcutsCustomization).isTrue()
        }
    }

    @Test
    fun allowExtendedAppShortcutsCustomization_false_WhenExtraAppsShortcutsCustomizedIsAtLimit() {
        testScope.runTest {
            setupShortcutHelperWithExtendedAppsShortcutCustomizations(
                numberOfDefaultAppsShortcuts = 3,
                numberOfCustomShortcutsForDefaultApps = 3,
                numberOfCustomShortcutsForExtendedApps = EXTENDED_APPS_SHORTCUT_CUSTOMIZATION_LIMIT,
            )

            underTest.toggleCustomizationMode(true)
            val uiState by collectLastValue(underTest.shortcutsUiState)

            val activeUiState = uiState as ShortcutsUiState.Active

            assertThat(activeUiState.allowExtendedAppShortcutsCustomization).isFalse()
        }
    }

    @Test
    fun allowExtendedAppShortcutsCustomization_false_WhenExtraAppsShortcutsCustomizedIsAboveLimit() {
        testScope.runTest {
            setupShortcutHelperWithExtendedAppsShortcutCustomizations(
                numberOfDefaultAppsShortcuts = 3,
                numberOfCustomShortcutsForDefaultApps = 3,
                numberOfCustomShortcutsForExtendedApps =
                    EXTENDED_APPS_SHORTCUT_CUSTOMIZATION_LIMIT + 3,
            )

            underTest.toggleCustomizationMode(true)
            val uiState by collectLastValue(underTest.shortcutsUiState)

            val activeUiState = uiState as ShortcutsUiState.Active

            assertThat(activeUiState.allowExtendedAppShortcutsCustomization).isFalse()
        }
    }

    private fun setupShortcutHelperWithExtendedAppsShortcutCustomizations(
        numberOfDefaultAppsShortcuts: Int,
        numberOfCustomShortcutsForDefaultApps: Int,
        numberOfCustomShortcutsForExtendedApps: Int,
    ) {
        testHelper.showFromActivity()
        fakeDefaultShortcutCategoriesRepository.setShortcutCategories(
            buildAppShortcutsCategory(numberOfDefaultAppsShortcuts)
        )
        fakeCustomShortcutCategoriesRepository.setShortcutCategories(
            buildAppShortcutsCategory(
                numberOfCustomShortcutsForDefaultApps,
                numberOfCustomShortcutsForExtendedApps,
            )
        )
    }

    private fun openHelperAndSearchForFooString() {
        testHelper.showFromActivity()
        underTest.onSearchQueryChanged("foo")
@@ -488,6 +562,18 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
            shortcuts = shortcutLabels.map { simpleShortcut(it, isCustomShortcut) },
        )

    private fun subCategoryWithShortcutLabels(
        defaultShortcutLabels: List<String>,
        customShortcutLabels: List<String>,
        subCategoryLabel: String = FIRST_SIMPLE_GROUP_LABEL,
    ) =
        ShortcutSubCategory(
            label = subCategoryLabel,
            shortcuts =
                defaultShortcutLabels.map { simpleShortcut(it) } +
                    customShortcutLabels.map { simpleShortcut(it, isCustom = true) },
        )

    private fun setShortcutsCategoriesForSearchQuery() {
        fakeDefaultShortcutCategoriesRepository.setShortcutCategories(
            ShortcutCategory(
@@ -516,6 +602,19 @@ class ShortcutHelperViewModelTest : SysuiTestCase() {
            contentDescription { "$label, Press key Ctrl plus A" }
        }

    private fun buildAppShortcutsCategory(
        numberOfDefaultAppsShortcuts: Int = 0,
        numberOfCustomAppsShortcuts: Int = 0,
    ): ShortcutCategory {
        val defaultAppLabels = (1..numberOfDefaultAppsShortcuts).map { "default app $it" }
        val customAppLabels = (1..numberOfCustomAppsShortcuts).map { "custom app $it" }

        return ShortcutCategory(
            type = ShortcutCategoryType.AppCategories,
            subCategories = listOf(subCategoryWithShortcutLabels(defaultAppLabels, customAppLabels)),
        )
    }

    private companion object {
        const val FIRST_SIMPLE_GROUP_LABEL = "simple group 1"
        const val SECOND_SIMPLE_GROUP_LABEL = "simple group 2"
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ data class Shortcut(
    val className: String = "",
) {
    val containsCustomShortcutCommands: Boolean = commands.any { it.isCustom }
    val containsDefaultShortcutCommands: Boolean = commands.any { !it.isCustom }
}

class ShortcutBuilder(private val label: String) {
+16 −3
Original line number Diff line number Diff line
@@ -198,6 +198,7 @@ private fun ActiveShortcutHelper(
            shortcutsUiState.isCustomizationModeEnabled,
            onCustomizationModeToggled,
            shortcutsUiState.isExtendedAppCategoryFlagEnabled,
            shortcutsUiState.allowExtendedAppShortcutsCustomization,
            modifier,
            onShortcutCustomizationRequested,
        )
@@ -392,6 +393,7 @@ private fun ShortcutHelperTwoPane(
    isCustomizationModeEnabled: Boolean,
    onCustomizationModeToggled: (isCustomizing: Boolean) -> Unit,
    isExtendedAppCategoryFlagEnabled: Boolean,
    allowExtendedAppShortcutsCustomization: Boolean,
    modifier: Modifier = Modifier,
    onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
@@ -442,8 +444,9 @@ private fun ShortcutHelperTwoPane(
                selectedCategory,
                isCustomizing = isCustomizationModeEnabled,
                isExtendedAppCategoryFlagEnabled,
                allowExtendedAppShortcutsCustomization,
                Modifier.fillMaxSize().padding(top = 8.dp).semantics { isTraversalGroup = true },
                onShortcutCustomizationRequested = onShortcutCustomizationRequested,
                onShortcutCustomizationRequested,
            )
        }
    }
@@ -514,6 +517,7 @@ private fun EndSidePanel(
    category: ShortcutCategoryUi?,
    isCustomizing: Boolean,
    isExtendedAppCategoryFlagEnabled: Boolean,
    allowExtendedAppShortcutsCustomization: Boolean,
    modifier: Modifier = Modifier,
    onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
@@ -549,13 +553,15 @@ private fun EndSidePanel(
                            onShortcutCustomizationRequested(requestInfo)
                    }
                },
                allowExtendedAppShortcutsCustomization = allowExtendedAppShortcutsCustomization,
            )
            Spacer(modifier = Modifier.height(8.dp))
        }
        if (
            category.type == ShortcutCategoryType.AppCategories &&
                !isCustomizationModeEnabled &&
                isExtendedAppCategoryFlagEnabled
                isExtendedAppCategoryFlagEnabled &&
                allowExtendedAppShortcutsCustomization
        ) {
            item {
                ShortcutHelperButton(
@@ -595,6 +601,7 @@ private fun SubCategoryContainerDualPane(
    subCategory: ShortcutSubCategory,
    isCustomizing: Boolean,
    onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit,
    allowExtendedAppShortcutsCustomization: Boolean,
) {
    Surface(
        modifier = Modifier.fillMaxWidth(),
@@ -632,6 +639,7 @@ private fun SubCategoryContainerDualPane(
                                onShortcutCustomizationRequested(requestInfo)
                        }
                    },
                    allowExtendedAppShortcutsCustomization = allowExtendedAppShortcutsCustomization,
                )
            }
        }
@@ -652,6 +660,7 @@ private fun Shortcut(
    modifier: Modifier,
    searchQuery: String,
    shortcut: ShortcutModel,
    allowExtendedAppShortcutsCustomization: Boolean = true,
    isCustomizing: Boolean = false,
    onShortcutCustomizationRequested: (ShortcutCustomizationRequestInfo) -> Unit = {},
) {
@@ -692,6 +701,7 @@ private fun Shortcut(
            modifier = Modifier.weight(.666f).semantics { hideFromAccessibility() },
            shortcut = shortcut,
            isCustomizing = isCustomizing,
            allowExtendedAppShortcutsCustomization = allowExtendedAppShortcutsCustomization,
            onAddShortcutRequested = {
                onShortcutCustomizationRequested(
                    ShortcutCustomizationRequestInfo.SingleShortcutCustomization.Add(
@@ -740,6 +750,7 @@ private fun ShortcutKeyCombinations(
    modifier: Modifier = Modifier,
    shortcut: ShortcutModel,
    isCustomizing: Boolean = false,
    allowExtendedAppShortcutsCustomization: Boolean,
    onAddShortcutRequested: () -> Unit = {},
    onDeleteShortcutRequested: () -> Unit = {},
) {
@@ -761,7 +772,9 @@ private fun ShortcutKeyCombinations(
        AnimatedVisibility(visible = isCustomizing) {
            if (shortcut.containsCustomShortcutCommands) {
                DeleteShortcutButton(onDeleteShortcutRequested)
            } else {
            } else if (
                shortcut.containsDefaultShortcutCommands || allowExtendedAppShortcutsCustomization
            ) {
                AddShortcutButton(onAddShortcutRequested)
            }
        }
+1 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ sealed interface ShortcutsUiState {
        val isExtendedAppCategoryFlagEnabled: Boolean = false,
        val shouldShowResetButton: Boolean = false,
        val isCustomizationModeEnabled: Boolean = false,
        val allowExtendedAppShortcutsCustomization: Boolean = true,
    ) : ShortcutsUiState

    data object Inactive : ShortcutsUiState
+43 −18
Original line number Diff line number Diff line
@@ -37,7 +37,12 @@ import com.android.systemui.keyboard.shortcut.domain.interactor.ShortcutHelperSt
import com.android.systemui.keyboard.shortcut.shared.model.Shortcut
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategory
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.Accessibility
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.AppCategories
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.CurrentApp
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.InputMethodEditor
import com.android.systemui.keyboard.shortcut.shared.model.ShortcutCategoryType.MultiTasking
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.ui.model.IconSource
import com.android.systemui.keyboard.shortcut.ui.model.ShortcutCategoryUi
@@ -102,6 +107,10 @@ constructor(
                        isExtendedAppCategoryFlagEnabled = extendedAppsShortcutCategory(),
                        shouldShowResetButton = shouldShowResetButton(shortcutCategoriesUi),
                        isCustomizationModeEnabled = isCustomizationModeEnabled,
                        allowExtendedAppShortcutsCustomization =
                            !isExtendedAppsShortcutCustomizationLimitReached(
                                categoriesWithLauncherExcluded
                            ),
                    )
                }
            }
@@ -111,6 +120,26 @@ constructor(
                initialValue = ShortcutsUiState.Inactive,
            )

    private fun isExtendedAppsShortcutCustomizationLimitReached(
        shortcutCategories: List<ShortcutCategory>
    ): Boolean {
        val appShortcutCategory = shortcutCategories.firstOrNull { it.type == AppCategories }
        if (appShortcutCategory == null) {
            return false
        }

        return getExtendedAppsShortcutCustomizationCount(appShortcutCategory) >=
            EXTENDED_APPS_SHORTCUT_CUSTOMIZATION_LIMIT
    }

    private fun getExtendedAppsShortcutCustomizationCount(
        appsShortcutCategory: ShortcutCategory
    ): Int {
        return appsShortcutCategory.subCategories
            .flatMap { it.shortcuts }
            .count { !it.containsDefaultShortcutCommands && it.containsCustomShortcutCommands }
    }

    private fun shouldShowResetButton(categoriesUi: List<ShortcutCategoryUi>): Boolean {
        return categoriesUi.any { it.containsCustomShortcuts }
    }
@@ -129,12 +158,10 @@ constructor(

    private fun getShortcutCategoryIcon(type: ShortcutCategoryType): IconSource {
        return when (type) {
            ShortcutCategoryType.System -> IconSource(imageVector = Icons.Default.Tv)
            ShortcutCategoryType.MultiTasking ->
                IconSource(imageVector = Icons.Default.VerticalSplit)
            ShortcutCategoryType.InputMethodEditor ->
                IconSource(imageVector = Icons.Default.Keyboard)
            ShortcutCategoryType.AppCategories -> IconSource(imageVector = Icons.Default.Apps)
            System -> IconSource(imageVector = Icons.Default.Tv)
            MultiTasking -> IconSource(imageVector = Icons.Default.VerticalSplit)
            InputMethodEditor -> IconSource(imageVector = Icons.Default.Keyboard)
            AppCategories -> IconSource(imageVector = Icons.Default.Apps)
            is CurrentApp -> {
                try {
                    val iconDrawable =
@@ -149,24 +176,18 @@ constructor(
                }
            }

            ShortcutCategoryType.Accessibility ->
                IconSource(imageVector = Icons.Default.AccessibilityNew)
            Accessibility -> IconSource(imageVector = Icons.Default.AccessibilityNew)
        }
    }

    private fun getShortcutCategoryLabel(type: ShortcutCategoryType): String =
        when (type) {
            ShortcutCategoryType.System ->
                context.getString(R.string.shortcut_helper_category_system)
            ShortcutCategoryType.MultiTasking ->
                context.getString(R.string.shortcut_helper_category_multitasking)
            ShortcutCategoryType.InputMethodEditor ->
                context.getString(R.string.shortcut_helper_category_input)
            ShortcutCategoryType.AppCategories ->
                context.getString(R.string.shortcut_helper_category_app_shortcuts)
            System -> context.getString(R.string.shortcut_helper_category_system)
            MultiTasking -> context.getString(R.string.shortcut_helper_category_multitasking)
            InputMethodEditor -> context.getString(R.string.shortcut_helper_category_input)
            AppCategories -> context.getString(R.string.shortcut_helper_category_app_shortcuts)
            is CurrentApp -> getApplicationLabelForCurrentApp(type)
            ShortcutCategoryType.Accessibility ->
                context.getString(R.string.shortcutHelper_category_accessibility)
            Accessibility -> context.getString(R.string.shortcutHelper_category_accessibility)
        }

    private fun getApplicationLabelForCurrentApp(type: CurrentApp): String {
@@ -273,4 +294,8 @@ constructor(
    private fun resetCustomizationMode() {
        customizationModeInteractor.toggleCustomizationMode(false)
    }

    companion object {
        const val EXTENDED_APPS_SHORTCUT_CUSTOMIZATION_LIMIT = 10
    }
}