Skip to content

Actions to launch assistant, settings apps do not work when the device is locked (no keyguard trampoline) #2268

Description

@andrew-ahlfield

What happens

The Open device assistant and Open voice assistant actions do nothing when the device is locked. On a locked or screen-off device the key map fires, but no assistant ever appears.

The key map itself is fine. I confirmed this by pointing the same trigger at a toggle flashlight action, which fires reliably with the screen off. So detection and action dispatch both work in that state; it is specifically the assistant actions that produce nothing.

Why

launchDeviceAssistant() and launchVoiceAssistant() start an activity with no keyguard handling at all:

https://github.com/keymapperorg/KeyMapper/blob/master/system/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt#L163-L174

override fun launchDeviceAssistant(): KMResult<*> {
    try {
        Intent(Intent.ACTION_ASSIST).apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK
            ctx.startActivity(this)
        }
        ...

launchVoiceAssistant() is the same shape with ACTION_VOICE_COMMAND.

Compare openApp() about ninety lines further down in the same file, which handles exactly this case:

https://github.com/keymapperorg/KeyMapper/blob/master/system/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt#L259-L281

// Use a trampoline activity that will dismiss the keyguard when it is locked.
val intent = if (keyguardManager.isKeyguardLocked) {
    Intent(ctx, TrampolineActivity::class.java).apply {
        putExtra(TrampolineActivity.EXTRA_INTENT, packageIntent)
    }
} else {
    packageIntent
}

val pendingIntent = PendingIntent.getActivity(ctx, 0, intent, PendingIntent.FLAG_IMMUTABLE)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
    val bundle = ActivityOptions.makeBasic()
        .setPendingIntentBackgroundActivityStartMode(
            ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED,
        )
        .toBundle()
    pendingIntent.send(bundle)
} else {
    pendingIntent.send()
}

That machinery came from #1788 ("dismiss lockscreen when launching app action from lockscreen") and was never extended to the assistant actions. With the keyguard up, the assist activity starts behind the lock screen and nothing is visible. With the screen off there is the additional problem that a plain activity start does not wake the display.

Suggested fix

Route the assistant actions through the same TrampolineActivity plus PendingIntent path that openApp() uses. That should be a small change and would reuse code that already exists in the file.

One thing worth considering beyond the trampoline: for users who have Expert Mode connected, injecting the key event may be a better implementation than starting an activity. The system bridge runs as the shell user and holds INJECT_EVENTS, and AOSP's KEYCODE_ASSIST handling in PhoneWindowManager.interceptKeyBeforeQueueing has no keyguard check at all, which is why long-pressing the power button shows the assistant on a locked phone. Injection reaches the assistant where startActivity cannot.

Workaround for anyone who finds this

A Shell command action with Execution Mode ADB (so it runs through the system bridge):

input keyevent --longpress 26

26 is KEYCODE_POWER and --longpress makes the system treat it as a held button, so it takes the same path a physical long press does and carries INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS with it. This requires Settings > System > Gestures > Press and hold power button to be set to Digital assistant, since the command simulates that gesture.

This launches the assistant over the lock screen from a fully dark screen, and importantly it opens listening. Two alternatives that fall short, for comparison:

Command Result
input keyevent --longpress 26 Works. Launches over the lock screen and cues audio input
input keyevent 219 (KEYCODE_ASSIST) Launches over the lock screen, but does not cue audio input
input keyevent 231 (KEYCODE_VOICE_ASSIST) Does not work through the lock screen

The difference between the first two looks like the invocation type: the power long press path passes INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS, which appears to be what makes the assistant open listening rather than merely open.

Setup

  • Google Pixel 5a
  • Key Mapper 4.5.0 from Google Play
  • Expert Mode connected
  • Trigger is a Bluetooth HID remote sending Volume Up, scoped to that device
  • Assistant is Gemini, with "Use Gemini without unlocking" enabled

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions