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

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

Merge "Add key event handling to Flexiglass" into main

parents 118f8cd1 d925e4a0
Loading
Loading
Loading
Loading
+69 −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.scene.ui.view

import android.view.KeyEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.fakeFalsingCollector
import com.android.systemui.keyevent.domain.interactor.mockSysUIKeyEventHandler
import com.android.systemui.kosmos.runTest
import com.android.systemui.testKosmos
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.verify

@SmallTest
@RunWith(AndroidJUnit4::class)
class WindowRootViewKeyEventHandlerTest : SysuiTestCase() {
    private val kosmos = testKosmos()
    private val underTest: WindowRootViewKeyEventHandler = kosmos.windowRootViewKeyEventHandler

    @Test
    fun dispatchKeyEvent_forwardsDispatchKeyEvent() =
        kosmos.runTest {
            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
            underTest.dispatchKeyEvent(keyEvent)
            verify(mockSysUIKeyEventHandler).dispatchKeyEvent(keyEvent)
        }

    @Test
    fun dispatchKeyEventPreIme_forwardsDispatchKeyEventPreIme() =
        kosmos.runTest {
            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
            underTest.dispatchKeyEventPreIme(keyEvent)
            verify(mockSysUIKeyEventHandler).dispatchKeyEventPreIme(keyEvent)
        }

    @Test
    fun interceptMediaKey_forwardsInterceptMediaKey() =
        kosmos.runTest {
            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
            underTest.interceptMediaKey(keyEvent)
            verify(mockSysUIKeyEventHandler).interceptMediaKey(keyEvent)
        }

    @Test
    fun collectKeyEvent_forwardsCollectKeyEvent() =
        kosmos.runTest {
            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A)
            underTest.collectKeyEvent(keyEvent)
            assertEquals(keyEvent, fakeFalsingCollector.lastKeyEvent)
        }
}
+5 −4
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.res.R
import com.android.systemui.scene.ui.view.WindowRootViewKeyEventHandler
import com.android.systemui.settings.brightness.data.repository.BrightnessMirrorShowingRepository
import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractorPassThrough
import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
@@ -69,7 +70,6 @@ import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
import com.android.systemui.window.ui.viewmodel.WindowRootViewModel
@@ -85,12 +85,12 @@ import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock

@RunWith(AndroidJUnit4::class)
@RunWithLooper(setAsMainLooper = true)
@@ -175,13 +175,14 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
        featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
        mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES)
        testScope = TestScope()
        val falsingCollector = FalsingCollectorFake()
        controller =
            NotificationShadeWindowViewController(
                blurUtils,
                windowRootViewModelFactory,
                choreographer,
                lockscreenShadeTransitionController,
                FalsingCollectorFake(),
                falsingCollector,
                statusBarStateController,
                dockManager,
                notificationShadeDepthController,
@@ -212,7 +213,7 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
                NotificationLaunchAnimationInteractor(NotificationLaunchAnimationRepository()),
                featureFlags,
                FakeSystemClock(),
                Mockito.mock(SysUIKeyEventHandler::class.java),
                WindowRootViewKeyEventHandler({ mock<SysUIKeyEventHandler>() }, falsingCollector),
                quickSettingsController,
                primaryBouncerInteractor,
                alternateBouncerInteractor,
+2 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ class SceneWindowRootView(context: Context, attrs: AttributeSet?) : WindowRootVi
        sceneDataSourceDelegator: SceneDataSourceDelegator,
        qsSceneAdapter: Provider<QSSceneAdapter>,
        sceneJankMonitorFactory: SceneJankMonitor.Factory,
        windowRootViewKeyEventHandler: WindowRootViewKeyEventHandler,
    ) {
        setLayoutInsetsController(layoutInsetController)
        SceneWindowRootViewBinder.bind(
@@ -53,6 +54,7 @@ class SceneWindowRootView(context: Context, attrs: AttributeSet?) : WindowRootVi
            qsSceneAdapter = qsSceneAdapter,
            sceneJankMonitorFactory = sceneJankMonitorFactory,
        )
        setWindowRootViewKeyEventHandler(windowRootViewKeyEventHandler)
    }

    override fun setVisibility(visibility: Int) {
+24 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.Context
import android.util.AttributeSet
import android.util.Pair
import android.view.DisplayCutout
import android.view.KeyEvent
import android.view.View
import android.view.WindowInsets
import android.widget.FrameLayout
@@ -37,6 +38,11 @@ open class WindowRootView(context: Context, attrs: AttributeSet?) : FrameLayout(
    private var rightInset = 0

    private var previousInsets: WindowInsets? = null
    private lateinit var windowRootViewKeyEventHandler: WindowRootViewKeyEventHandler

    fun setWindowRootViewKeyEventHandler(wrvkeh: WindowRootViewKeyEventHandler) {
        windowRootViewKeyEventHandler = wrvkeh
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
@@ -137,6 +143,24 @@ open class WindowRootView(context: Context, attrs: AttributeSet?) : FrameLayout(
        return parent.let { it !is View || it.id == android.R.id.content }
    }

    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
        windowRootViewKeyEventHandler.collectKeyEvent(event)

        if (windowRootViewKeyEventHandler.interceptMediaKey(event)) {
            return true
        }

        if (super.dispatchKeyEvent(event)) {
            return true
        }

        return windowRootViewKeyEventHandler.dispatchKeyEvent(event)
    }

    override fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
        return windowRootViewKeyEventHandler.dispatchKeyEventPreIme(event) ?: false
    }

    /** Controller responsible for calculating insets for the shade window. */
    interface LayoutInsetsController {

+49 −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.scene.ui.view

import android.view.KeyEvent
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler
import dagger.Lazy
import javax.inject.Inject

@SysUISingleton
class WindowRootViewKeyEventHandler
@Inject
constructor(
    val sysUIKeyEventHandlerLazy: Lazy<SysUIKeyEventHandler>,
    val falsingCollector: FalsingCollector,
) {
    fun dispatchKeyEvent(event: KeyEvent): Boolean {
        return sysUIKeyEventHandlerLazy.get().dispatchKeyEvent(event)
    }

    fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
        return sysUIKeyEventHandlerLazy.get().dispatchKeyEventPreIme(event)
    }

    fun interceptMediaKey(event: KeyEvent): Boolean {
        return sysUIKeyEventHandlerLazy.get().interceptMediaKey(event)
    }

    /** Collects the KeyEvent without intercepting it. */
    fun collectKeyEvent(event: KeyEvent) {
        falsingCollector.onKeyEvent(event)
    }
}
Loading