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

Commit 7e7e2cc7 authored by Josh's avatar Josh
Browse files

Shortcut helper should not show up on Locked Screen

We are now only triggering shortcut helper after keyguard has been
dismissed so the user is forced to authenticate(enter
pin/password/biometric) if available, before shortcut helper opens. The
reason for this is that with the shortcut customizer feature, it is now
unsafe for shortcut helper to be accessed from the lock screen as a
random person could  pick up a device, and change shortcuts without the
owner's consent

Test: atest ShortcutHelperCoreStartableTest
Flag: com.android.systemui.keyboard_shortcut_helper_shortcut_customizer
Fix: 381246414
Change-Id: I347e54a7ca81e87cc0b772f99f69df3267ea1f0a
parent 21d892de
Loading
Loading
Loading
Loading
+82 −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 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.kosmos.testScope
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.activityStarter
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.doNothing
import org.mockito.kotlin.eq
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
@OptIn(ExperimentalCoroutinesApi::class)
class ShortcutHelperCoreStartableTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val repo = kosmos.shortcutHelperStateRepository
    private val helper = kosmos.shortcutHelperTestHelper
    private val testScope = kosmos.testScope
    private val activityStarter = kosmos.activityStarter

    @Test
    fun shortcutHelperState_whenToggled_doesNotBecomeActive_ifDeviceIsLocked() {
        testScope.runTest {
            assumedKeyguardIsNotDismissed()

            val state by collectLastValue(repo.state)
            helper.toggle(deviceId = 456)

            assertThat(state).isEqualTo(ShortcutHelperState.Inactive)
        }
    }

    @Test
    fun shortcutHelperState_whenToggled_becomesActive_ifDeviceIsUnlocked() {
        testScope.runTest {
            assumeKeyguardIsDismissed()

            val state by collectLastValue(repo.state)
            helper.toggle(deviceId = 456)

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

    private fun assumeKeyguardIsDismissed(){
        whenever(activityStarter.dismissKeyguardThenExecute(any(), any(), eq(true))).then {
            (it.arguments[0] as ActivityStarter.OnDismissAction).onDismiss()
        }
    }

    private fun assumedKeyguardIsNotDismissed(){
        // Do nothing, simulating keyguard not being dismissed and action not being not executed
        doNothing().whenever(activityStarter).dismissKeyguardThenExecute(any(), any(), eq(true))
    }
}
+34 −15
Original line number Diff line number Diff line
@@ -26,34 +26,34 @@ import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.keyboard.shortcut.data.repository.ShortcutHelperStateRepository
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.CommandQueue
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject


@SysUISingleton
class ShortcutHelperCoreStartable
@Inject constructor(
@Inject
constructor(
    private val commandQueue: CommandQueue,
    private val broadcastDispatcher: BroadcastDispatcher,
    private val stateRepository: ShortcutHelperStateRepository,
    private val activityStarter: ActivityStarter,
    @Background private val backgroundScope: CoroutineScope,
) : CoreStartable {
    override fun start() {
        registerBroadcastReceiver(
            action = Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS,
            onReceive = {
                backgroundScope.launch { stateRepository.show() }
            }
            onReceive = { showShortcutHelper() },
        )
        registerBroadcastReceiver(
            action = Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS,
            onReceive = { stateRepository.hide() }
            onReceive = { stateRepository.hide() },
        )
        registerBroadcastReceiver(
            action = Intent.ACTION_CLOSE_SYSTEM_DIALOGS,
            onReceive = { stateRepository.hide() }
            onReceive = { stateRepository.hide() },
        )
        commandQueue.addCallback(
            object : CommandQueue.Callbacks {
@@ -62,7 +62,7 @@ class ShortcutHelperCoreStartable
                }

                override fun toggleKeyboardShortcutsMenu(deviceId: Int) {
                    backgroundScope.launch { stateRepository.toggle(deviceId) }
                    toggleShortcutHelper(deviceId)
                }
            }
        )
@@ -81,4 +81,23 @@ class ShortcutHelperCoreStartable
            user = UserHandle.ALL,
        )
    }

    private fun showShortcutHelper() {
        dismissKeyguardThenPerformShortcutHelperAction { stateRepository.show() }
    }

    private fun toggleShortcutHelper(deviceId: Int? = null) {
        dismissKeyguardThenPerformShortcutHelperAction { stateRepository.toggle(deviceId) }
    }

    private fun dismissKeyguardThenPerformShortcutHelperAction(action: suspend () -> Unit) {
        activityStarter.dismissKeyguardThenExecute(
            /* action= */ {
                backgroundScope.launch { action() }
                false
            },
            /* cancel= */ {},
            /* afterKeyguardGone= */ true,
        )
    }
}
+12 −14
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import com.android.systemui.kosmos.backgroundScope
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.model.sysUiState
import com.android.systemui.plugins.activityStarter
import com.android.systemui.settings.displayTracker
import com.android.systemui.settings.userTracker
import com.android.systemui.statusbar.phone.systemUIDialogFactory
@@ -67,12 +68,7 @@ var Kosmos.shortcutHelperMultiTaskingShortcutsSource: KeyboardShortcutGroupsSour
    Kosmos.Fixture { MultitaskingShortcutsSource(mainResources, applicationContext) }

val Kosmos.shortcutHelperStateRepository by
    Kosmos.Fixture {
        ShortcutHelperStateRepository(
            fakeInputManager.inputManager,
            testDispatcher,
        )
    }
    Kosmos.Fixture { ShortcutHelperStateRepository(fakeInputManager.inputManager, testDispatcher) }

var Kosmos.shortcutHelperInputShortcutsSource: KeyboardShortcutGroupsSource by
    Kosmos.Fixture {
@@ -156,6 +152,7 @@ val Kosmos.shortcutHelperCoreStartable by
            fakeCommandQueue,
            broadcastDispatcher,
            shortcutHelperStateRepository,
            activityStarter,
            testScope,
        )
    }
@@ -168,6 +165,7 @@ val Kosmos.shortcutHelperTestHelper by
            broadcastDispatcher,
            fakeCommandQueue,
            fakeInputManager,
            activityStarter,
            windowManager,
        )
    }
+10 −11
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@ import android.view.WindowManager.KeyboardShortcutsReceiver
import com.android.systemui.broadcast.FakeBroadcastDispatcher
import com.android.systemui.keyboard.shortcut.ShortcutHelperCoreStartable
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import org.mockito.kotlin.eq

class ShortcutHelperTestHelper(
    coreStartable: ShortcutHelperCoreStartable,
@@ -34,13 +36,9 @@ class ShortcutHelperTestHelper(
    private val fakeBroadcastDispatcher: FakeBroadcastDispatcher,
    private val fakeCommandQueue: FakeCommandQueue,
    private val fakeInputManager: FakeInputManager,
    windowManager: WindowManager
    private val activityStarter: ActivityStarter,
    windowManager: WindowManager,
) {

    companion object {
        const val DEFAULT_DEVICE_ID = 123
    }

    private var imeShortcuts: List<KeyboardShortcutGroup> = emptyList()
    private var currentAppsShortcuts: List<KeyboardShortcutGroup> = emptyList()

@@ -48,12 +46,13 @@ class ShortcutHelperTestHelper(
        whenever(windowManager.requestImeKeyboardShortcuts(any(), any())).thenAnswer {
            val keyboardShortcutReceiver = it.getArgument<KeyboardShortcutsReceiver>(0)
            keyboardShortcutReceiver.onKeyboardShortcutsReceived(imeShortcuts)
            return@thenAnswer Unit
        }
        whenever(windowManager.requestAppKeyboardShortcuts(any(), any())).thenAnswer {
            val keyboardShortcutReceiver = it.getArgument<KeyboardShortcutsReceiver>(0)
            keyboardShortcutReceiver.onKeyboardShortcutsReceived(currentAppsShortcuts)
            return@thenAnswer Unit
        }
        whenever(activityStarter.dismissKeyguardThenExecute(any(), any(), eq(true))).then {
            (it.arguments[0] as ActivityStarter.OnDismissAction).onDismiss()
        }
        coreStartable.start()
    }
@@ -77,21 +76,21 @@ class ShortcutHelperTestHelper(
    fun hideThroughCloseSystemDialogs() {
        fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
            context,
            Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
            Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS),
        )
    }

    fun hideFromActivity() {
        fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
            context,
            Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS)
            Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS),
        )
    }

    fun showFromActivity() {
        fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
            context,
            Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS)
            Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS),
        )
    }