Add interactors for KeyEvents
This is in preparation to swap over to using the KeyEventInteractor instead of calling methods on CentralSurfaces. However, this is NOT and ideal way for the interactors themselves to be structured. In the future the interactors should be updated to reflect true modern architecture patterns. The logic in these interactors match logic from NotificationShadeWindowViewController and CentralSurfacesImpl. Test: atest KeyEventInteractorTest Test: atest KeyguardKeyEventInteractorTest Bug: 295927655 Change-Id: Id5c5659a4a19a0b0feb45d6ee391930c2063a9b1
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.keyevent.domain.interactor
|
||||
|
||||
import android.view.KeyEvent
|
||||
import com.android.systemui.back.domain.interactor.BackActionInteractor
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Sends key events to the appropriate interactors and then acts upon key events that haven't
|
||||
* already been handled but should be handled by SystemUI.
|
||||
*/
|
||||
@SysUISingleton
|
||||
class KeyEventInteractor
|
||||
@Inject
|
||||
constructor(
|
||||
private val backActionInteractor: BackActionInteractor,
|
||||
private val keyguardKeyEventInteractor: KeyguardKeyEventInteractor,
|
||||
) {
|
||||
fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
if (keyguardKeyEventInteractor.dispatchKeyEvent(event)) {
|
||||
return true
|
||||
}
|
||||
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_BACK -> {
|
||||
if (event.handleAction()) {
|
||||
backActionInteractor.onBackRequested()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun interceptMediaKey(event: KeyEvent): Boolean {
|
||||
return keyguardKeyEventInteractor.interceptMediaKey(event)
|
||||
}
|
||||
|
||||
fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
|
||||
return keyguardKeyEventInteractor.dispatchKeyEventPreIme(event)
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Most actions shouldn't be handled on the down event and instead handled on subsequent
|
||||
// key events like ACTION_UP.
|
||||
fun KeyEvent.handleAction(): Boolean {
|
||||
return action != KeyEvent.ACTION_DOWN
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.keyguard.domain.interactor
|
||||
|
||||
import android.content.Context
|
||||
import android.media.AudioManager
|
||||
import android.view.KeyEvent
|
||||
import com.android.systemui.back.domain.interactor.BackActionInteractor
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.keyevent.domain.interactor.KeyEventInteractor.Companion.handleAction
|
||||
import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.ShadeController
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Handles key events arriving when the keyguard is showing or device is dozing. */
|
||||
@SysUISingleton
|
||||
class KeyguardKeyEventInteractor
|
||||
@Inject
|
||||
constructor(
|
||||
private val context: Context,
|
||||
private val statusBarStateController: StatusBarStateController,
|
||||
private val keyguardInteractor: KeyguardInteractor,
|
||||
private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
|
||||
private val shadeController: ShadeController,
|
||||
private val mediaSessionLegacyHelperWrapper: MediaSessionLegacyHelperWrapper,
|
||||
private val backActionInteractor: BackActionInteractor,
|
||||
) {
|
||||
|
||||
fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
if (statusBarStateController.isDozing) {
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN,
|
||||
KeyEvent.KEYCODE_VOLUME_UP -> return dispatchVolumeKeyEvent(event)
|
||||
}
|
||||
}
|
||||
|
||||
if (event.handleAction()) {
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_MENU -> return dispatchMenuKeyEvent()
|
||||
KeyEvent.KEYCODE_SPACE -> return dispatchSpaceEvent()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* While IME is active and a BACK event is detected, check with {@link
|
||||
* StatusBarKeyguardViewManager#dispatchBackKeyEventPreIme()} to see if the event should be
|
||||
* handled before routing to IME, in order to prevent the user from having to hit back twice to
|
||||
* exit bouncer.
|
||||
*/
|
||||
fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
|
||||
when (event.keyCode) {
|
||||
KeyEvent.KEYCODE_BACK ->
|
||||
if (
|
||||
statusBarStateController.state == StatusBarState.KEYGUARD &&
|
||||
statusBarKeyguardViewManager.dispatchBackKeyEventPreIme()
|
||||
) {
|
||||
return backActionInteractor.onBackRequested()
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun interceptMediaKey(event: KeyEvent): Boolean {
|
||||
return statusBarStateController.state == StatusBarState.KEYGUARD &&
|
||||
statusBarKeyguardViewManager.interceptMediaKey(event)
|
||||
}
|
||||
|
||||
private fun dispatchMenuKeyEvent(): Boolean {
|
||||
val shouldUnlockOnMenuPressed =
|
||||
isDeviceInteractive() &&
|
||||
(statusBarStateController.state != StatusBarState.SHADE) &&
|
||||
statusBarKeyguardViewManager.shouldDismissOnMenuPressed()
|
||||
if (shouldUnlockOnMenuPressed) {
|
||||
shadeController.animateCollapseShadeForced()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun dispatchSpaceEvent(): Boolean {
|
||||
if (isDeviceInteractive() && statusBarStateController.state != StatusBarState.SHADE) {
|
||||
shadeController.animateCollapseShadeForced()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun dispatchVolumeKeyEvent(event: KeyEvent): Boolean {
|
||||
mediaSessionLegacyHelperWrapper
|
||||
.getHelper(context)
|
||||
.sendVolumeKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE, true)
|
||||
return true
|
||||
}
|
||||
|
||||
private fun isDeviceInteractive(): Boolean {
|
||||
return keyguardInteractor.wakefulnessModel.value.isDeviceInteractive()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.media.controls.util
|
||||
|
||||
import android.content.Context
|
||||
import android.media.session.MediaSessionLegacyHelper
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import javax.inject.Inject
|
||||
|
||||
/** Injectable wrapper around `MediaSessionLegacyHelper` functions */
|
||||
@SysUISingleton
|
||||
class MediaSessionLegacyHelperWrapper @Inject constructor() {
|
||||
fun getHelper(context: Context): MediaSessionLegacyHelper {
|
||||
return MediaSessionLegacyHelper.getHelper(context)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.keyevent.domain.interactor
|
||||
|
||||
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.back.domain.interactor.BackActionInteractor
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardKeyEventInteractor
|
||||
import com.android.systemui.util.mockito.eq
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class KeyEventInteractorTest : SysuiTestCase() {
|
||||
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
|
||||
|
||||
private lateinit var keyguardInteractorWithDependencies:
|
||||
KeyguardInteractorFactory.WithDependencies
|
||||
@Mock private lateinit var keyguardKeyEventInteractor: KeyguardKeyEventInteractor
|
||||
@Mock private lateinit var backActionInteractor: BackActionInteractor
|
||||
|
||||
private lateinit var underTest: KeyEventInteractor
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
keyguardInteractorWithDependencies = KeyguardInteractorFactory.create()
|
||||
underTest =
|
||||
KeyEventInteractor(
|
||||
backActionInteractor,
|
||||
keyguardKeyEventInteractor,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchBackKey_notHandledByKeyguardKeyEventInteractor_handledByBackActionInteractor() {
|
||||
val backKeyEventActionDown = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK)
|
||||
val backKeyEventActionUp = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)
|
||||
|
||||
// GIVEN back key ACTION_DOWN and ACTION_UP aren't handled by the keyguardKeyEventInteractor
|
||||
whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionDown))
|
||||
.thenReturn(false)
|
||||
whenever(keyguardKeyEventInteractor.dispatchKeyEvent(backKeyEventActionUp))
|
||||
.thenReturn(false)
|
||||
|
||||
// WHEN back key event ACTION_DOWN, the event is handled even though back isn't requested
|
||||
assertThat(underTest.dispatchKeyEvent(backKeyEventActionDown)).isTrue()
|
||||
// THEN back event isn't handled on ACTION_DOWN
|
||||
verify(backActionInteractor, never()).onBackRequested()
|
||||
|
||||
// WHEN back key event ACTION_UP
|
||||
assertThat(underTest.dispatchKeyEvent(backKeyEventActionUp)).isTrue()
|
||||
// THEN back event is handled on ACTION_UP
|
||||
verify(backActionInteractor).onBackRequested()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEvent_isNotHandledByKeyguardKeyEventInteractor() {
|
||||
val keyEvent =
|
||||
KeyEvent(
|
||||
KeyEvent.ACTION_UP,
|
||||
KeyEvent.KEYCODE_SPACE,
|
||||
)
|
||||
whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(false)
|
||||
assertThat(underTest.dispatchKeyEvent(keyEvent)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEvent_handledByKeyguardKeyEventInteractor() {
|
||||
val keyEvent =
|
||||
KeyEvent(
|
||||
KeyEvent.ACTION_UP,
|
||||
KeyEvent.KEYCODE_SPACE,
|
||||
)
|
||||
whenever(keyguardKeyEventInteractor.dispatchKeyEvent(eq(keyEvent))).thenReturn(true)
|
||||
assertThat(underTest.dispatchKeyEvent(keyEvent)).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun interceptMediaKey_isNotHandledByKeyguardKeyEventInteractor() {
|
||||
val keyEvent =
|
||||
KeyEvent(
|
||||
KeyEvent.ACTION_UP,
|
||||
KeyEvent.KEYCODE_SPACE,
|
||||
)
|
||||
whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(false)
|
||||
assertThat(underTest.interceptMediaKey(keyEvent)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun interceptMediaKey_handledByKeyguardKeyEventInteractor() {
|
||||
val keyEvent =
|
||||
KeyEvent(
|
||||
KeyEvent.ACTION_UP,
|
||||
KeyEvent.KEYCODE_SPACE,
|
||||
)
|
||||
whenever(keyguardKeyEventInteractor.interceptMediaKey(eq(keyEvent))).thenReturn(true)
|
||||
assertThat(underTest.interceptMediaKey(keyEvent)).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEventPreIme_isNotHandledByKeyguardKeyEventInteractor() {
|
||||
val keyEvent =
|
||||
KeyEvent(
|
||||
KeyEvent.ACTION_UP,
|
||||
KeyEvent.KEYCODE_SPACE,
|
||||
)
|
||||
whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(false)
|
||||
assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isFalse()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEventPreIme_handledByKeyguardKeyEventInteractor() {
|
||||
val keyEvent =
|
||||
KeyEvent(
|
||||
KeyEvent.ACTION_UP,
|
||||
KeyEvent.KEYCODE_SPACE,
|
||||
)
|
||||
whenever(keyguardKeyEventInteractor.dispatchKeyEventPreIme(eq(keyEvent))).thenReturn(true)
|
||||
assertThat(underTest.dispatchKeyEventPreIme(keyEvent)).isTrue()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Copyright (C) 2023 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.keyguard.domain.interactor
|
||||
|
||||
import android.media.AudioManager
|
||||
import android.media.session.MediaSessionLegacyHelper
|
||||
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.back.domain.interactor.BackActionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.WakeSleepReason
|
||||
import com.android.systemui.keyguard.shared.model.WakefulnessModel
|
||||
import com.android.systemui.keyguard.shared.model.WakefulnessState
|
||||
import com.android.systemui.media.controls.util.MediaSessionLegacyHelperWrapper
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.shade.ShadeController
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
|
||||
import com.android.systemui.util.mockito.any
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentMatchers.eq
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.junit.MockitoJUnit
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class KeyguardKeyEventInteractorTest : SysuiTestCase() {
|
||||
@JvmField @Rule var mockitoRule = MockitoJUnit.rule()
|
||||
|
||||
private val actionDownVolumeDownKeyEvent =
|
||||
KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_DOWN)
|
||||
private val actionDownVolumeUpKeyEvent =
|
||||
KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
|
||||
private val backKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK)
|
||||
private val awakeWakefulnessMode =
|
||||
WakefulnessModel(WakefulnessState.AWAKE, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
|
||||
private val asleepWakefulnessMode =
|
||||
WakefulnessModel(WakefulnessState.ASLEEP, WakeSleepReason.OTHER, WakeSleepReason.OTHER)
|
||||
|
||||
private lateinit var keyguardInteractorWithDependencies:
|
||||
KeyguardInteractorFactory.WithDependencies
|
||||
@Mock private lateinit var statusBarStateController: StatusBarStateController
|
||||
@Mock private lateinit var statusBarKeyguardViewManager: StatusBarKeyguardViewManager
|
||||
@Mock private lateinit var shadeController: ShadeController
|
||||
@Mock private lateinit var mediaSessionLegacyHelperWrapper: MediaSessionLegacyHelperWrapper
|
||||
@Mock private lateinit var mediaSessionLegacyHelper: MediaSessionLegacyHelper
|
||||
@Mock private lateinit var backActionInteractor: BackActionInteractor
|
||||
|
||||
private lateinit var underTest: KeyguardKeyEventInteractor
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
whenever(mediaSessionLegacyHelperWrapper.getHelper(any()))
|
||||
.thenReturn(mediaSessionLegacyHelper)
|
||||
keyguardInteractorWithDependencies = KeyguardInteractorFactory.create()
|
||||
underTest =
|
||||
KeyguardKeyEventInteractor(
|
||||
context,
|
||||
statusBarStateController,
|
||||
keyguardInteractorWithDependencies.keyguardInteractor,
|
||||
statusBarKeyguardViewManager,
|
||||
shadeController,
|
||||
mediaSessionLegacyHelperWrapper,
|
||||
backActionInteractor,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEvent_volumeKey_dozing_handlesEvents() {
|
||||
whenever(statusBarStateController.isDozing).thenReturn(true)
|
||||
|
||||
assertThat(underTest.dispatchKeyEvent(actionDownVolumeDownKeyEvent)).isTrue()
|
||||
verify(mediaSessionLegacyHelper)
|
||||
.sendVolumeKeyEvent(
|
||||
eq(actionDownVolumeDownKeyEvent),
|
||||
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
|
||||
eq(true)
|
||||
)
|
||||
|
||||
assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isTrue()
|
||||
verify(mediaSessionLegacyHelper)
|
||||
.sendVolumeKeyEvent(
|
||||
eq(actionDownVolumeUpKeyEvent),
|
||||
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
|
||||
eq(true)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEvent_volumeKey_notDozing_doesNotHandleEvents() {
|
||||
whenever(statusBarStateController.isDozing).thenReturn(false)
|
||||
|
||||
assertThat(underTest.dispatchKeyEvent(actionDownVolumeDownKeyEvent)).isFalse()
|
||||
verify(mediaSessionLegacyHelper, never())
|
||||
.sendVolumeKeyEvent(
|
||||
eq(actionDownVolumeDownKeyEvent),
|
||||
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
|
||||
eq(true)
|
||||
)
|
||||
|
||||
assertThat(underTest.dispatchKeyEvent(actionDownVolumeUpKeyEvent)).isFalse()
|
||||
verify(mediaSessionLegacyHelper, never())
|
||||
.sendVolumeKeyEvent(
|
||||
eq(actionDownVolumeUpKeyEvent),
|
||||
eq(AudioManager.USE_DEFAULT_STREAM_TYPE),
|
||||
eq(true)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEvent_menuActionUp_interactiveKeyguard_collapsesShade() {
|
||||
keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
|
||||
|
||||
val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
|
||||
assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
|
||||
verify(shadeController).animateCollapseShadeForced()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEvent_menuActionUp_interactiveShadeLocked_collapsesShade() {
|
||||
keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE_LOCKED)
|
||||
whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
|
||||
|
||||
// action down: does NOT collapse the shade
|
||||
val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)
|
||||
assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
|
||||
verify(shadeController, never()).animateCollapseShadeForced()
|
||||
|
||||
// action up: collapses the shade
|
||||
val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
|
||||
assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
|
||||
verify(shadeController).animateCollapseShadeForced()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEvent_menuActionUp_nonInteractiveKeyguard_neverCollapsesShade() {
|
||||
keyguardInteractorWithDependencies.repository.setWakefulnessModel(asleepWakefulnessMode)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(statusBarKeyguardViewManager.shouldDismissOnMenuPressed()).thenReturn(true)
|
||||
|
||||
val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU)
|
||||
assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isFalse()
|
||||
verify(shadeController, never()).animateCollapseShadeForced()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEvent_spaceActionUp_interactiveKeyguard_collapsesShade() {
|
||||
keyguardInteractorWithDependencies.repository.setWakefulnessModel(awakeWakefulnessMode)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
|
||||
// action down: does NOT collapse the shade
|
||||
val actionDownMenuKeyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)
|
||||
assertThat(underTest.dispatchKeyEvent(actionDownMenuKeyEvent)).isFalse()
|
||||
verify(shadeController, never()).animateCollapseShadeForced()
|
||||
|
||||
// action up: collapses the shade
|
||||
val actionUpMenuKeyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SPACE)
|
||||
assertThat(underTest.dispatchKeyEvent(actionUpMenuKeyEvent)).isTrue()
|
||||
verify(shadeController).animateCollapseShadeForced()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEventPreIme_back_keyguard_onBackRequested() {
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(statusBarKeyguardViewManager.dispatchBackKeyEventPreIme()).thenReturn(true)
|
||||
|
||||
whenever(backActionInteractor.onBackRequested()).thenReturn(false)
|
||||
assertThat(underTest.dispatchKeyEventPreIme(backKeyEvent)).isFalse()
|
||||
verify(backActionInteractor).onBackRequested()
|
||||
clearInvocations(backActionInteractor)
|
||||
|
||||
whenever(backActionInteractor.onBackRequested()).thenReturn(true)
|
||||
assertThat(underTest.dispatchKeyEventPreIme(backKeyEvent)).isTrue()
|
||||
verify(backActionInteractor).onBackRequested()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEventPreIme_back_keyguard_SBKVMdoesNotHandle_neverOnBackRequested() {
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(statusBarKeyguardViewManager.dispatchBackKeyEventPreIme()).thenReturn(false)
|
||||
whenever(backActionInteractor.onBackRequested()).thenReturn(true)
|
||||
|
||||
assertThat(underTest.dispatchKeyEventPreIme(backKeyEvent)).isFalse()
|
||||
verify(backActionInteractor, never()).onBackRequested()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dispatchKeyEventPreIme_back_shade_neverOnBackRequested() {
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
|
||||
whenever(statusBarKeyguardViewManager.dispatchBackKeyEventPreIme()).thenReturn(true)
|
||||
whenever(backActionInteractor.onBackRequested()).thenReturn(true)
|
||||
|
||||
assertThat(underTest.dispatchKeyEventPreIme(backKeyEvent)).isFalse()
|
||||
verify(backActionInteractor, never()).onBackRequested()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun interceptMediaKey_keyguard_SBKVMdoesNotHandle_doesNotHandleMediaKey() {
|
||||
val keyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_UP)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(statusBarKeyguardViewManager.interceptMediaKey(eq(keyEvent))).thenReturn(false)
|
||||
|
||||
assertThat(underTest.interceptMediaKey(keyEvent)).isFalse()
|
||||
verify(statusBarKeyguardViewManager).interceptMediaKey(eq(keyEvent))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun interceptMediaKey_keyguard_handleMediaKey() {
|
||||
val keyEvent = KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_UP)
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(statusBarKeyguardViewManager.interceptMediaKey(eq(keyEvent))).thenReturn(true)
|
||||
|
||||
assertThat(underTest.interceptMediaKey(keyEvent)).isTrue()
|
||||
verify(statusBarKeyguardViewManager).interceptMediaKey(eq(keyEvent))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun interceptMediaKey_shade_doesNotHandleMediaKey() {
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
|
||||
|
||||
assertThat(
|
||||
underTest.interceptMediaKey(
|
||||
KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_VOLUME_UP)
|
||||
)
|
||||
)
|
||||
.isFalse()
|
||||
verify(statusBarKeyguardViewManager, never()).interceptMediaKey(any())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user