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

Commit 111afe00 authored by Wes Okuhara's avatar Wes Okuhara
Browse files

Screen capture: Esc keypress closes the window

Implements the key event handling on the top-level Composable by making
the component focusable. The window and its view were not chosen to
handle the key events as making them focusable led to undesired focus
shadows and behavior.

Bug: 438561227
Test: Manual
Flag: com.android.systemui.large_screen_screencapture
Change-Id: I97f3f7bbc91db15cb390b35c350bb6a1888d80ab
parent 8d3d3165
Loading
Loading
Loading
Loading
+28 −33
Original line number Diff line number Diff line
@@ -19,9 +19,6 @@ package com.android.systemui.screencapture.ui
import android.annotation.SuppressLint
import android.content.Context
import android.view.Display
import android.view.KeyEvent
import android.view.View
import android.view.View.OnKeyListener
import android.view.Window
import android.window.OnBackInvokedCallback
import android.window.WindowOnBackInvokedDispatcher
@@ -31,6 +28,7 @@ import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.safeDrawing
@@ -44,6 +42,16 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.KeyEvent
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.isAltPressed
import androidx.compose.ui.input.key.isCtrlPressed
import androidx.compose.ui.input.key.isMetaPressed
import androidx.compose.ui.input.key.isShiftPressed
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.key.onKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.platform.ComposeView
import com.android.compose.theme.PlatformTheme
import com.android.systemui.compose.ComposeInitializer
@@ -113,13 +121,11 @@ constructor(
                    // Wait until parameters are passed down to Compose
                    val parameters = parametersState ?: return@setContent

                    LaunchedEffect(viewModel) {
                        window.decorView.observeKeyUpEvents { keyCode: Int, event: KeyEvent ->
                            onKeyUp(viewModel = viewModel, keyCode = keyCode, event = event)
                        }
                    }
                    LaunchedEffect(viewModel) { window.observeBack { viewModel.dismiss() } }

                    // Focus the view on initial render so it can receive key events.
                    LaunchedEffect(Unit) { window.decorView.requestFocus() }

                    PlatformTheme {
                        val visibleState = remember { MutableTransitionState(false) }
                        visibleState.targetState = viewModel.state is ScreenCaptureUiState.Visible
@@ -147,7 +153,13 @@ constructor(
                                        .setDisplay(display)
                                        .build()
                                }
                            Box(modifier = Modifier.windowInsetsPadding(WindowInsets.safeDrawing)) {

                            Box(
                                modifier =
                                    Modifier.windowInsetsPadding(WindowInsets.safeDrawing)
                                        .focusable()
                                        .onKeyEvent { event -> handleKeyEvent(event, viewModel) }
                            ) {
                                component.screenCaptureContent.Content()
                            }
                        }
@@ -163,18 +175,19 @@ constructor(
        composeRoot = null
    }

    private fun onKeyUp(
        viewModel: ScreenCaptureUiViewModel,
        keyCode: Int,
        event: KeyEvent,
    ): Boolean {
    private fun handleKeyEvent(event: KeyEvent, viewModel: ScreenCaptureUiViewModel): Boolean {
        if (event.type != KeyEventType.KeyUp) {
            return false
        }

        val noModifierKeys =
            !event.isShiftPressed &&
                !event.isCtrlPressed &&
                !event.isAltPressed &&
                !event.isMetaPressed

        return when {
            (keyCode == KeyEvent.KEYCODE_ESCAPE && noModifierKeys) -> {
            (event.key == Key.Escape && noModifierKeys) -> {
                viewModel.dismiss()
                true
            }
@@ -200,21 +213,3 @@ private suspend fun Window.observeBack(onBack: OnBackInvokedCallback) {
        onBackInvokedDispatcher.unregisterOnBackInvokedCallback(onBack)
    }
}

private suspend fun View.observeKeyUpEvents(onKeyUp: (keyCode: Int, event: KeyEvent) -> Boolean) {
    val listener =
        object : OnKeyListener {
            override fun onKey(v: View?, keyCode: Int, event: KeyEvent?): Boolean {
                if (event?.action == KeyEvent.ACTION_UP) {
                    return onKeyUp(keyCode, event)
                }
                return false
            }
        }
    setOnKeyListener(listener)
    try {
        awaitCancellation()
    } finally {
        setOnKeyListener(null)
    }
}