diff options
| author | 2024-06-20 19:38:46 +0000 | |
|---|---|---|
| committer | 2024-06-20 19:38:46 +0000 | |
| commit | b20088f23654f883876706b14d40cf4c1e74b2f0 (patch) | |
| tree | 65c20c601e23367a5c10f5abbf95be2b65f03c02 | |
| parent | 2d71ada13e77c5ee02fec79023bc7bcf75496c5d (diff) | |
| parent | 73ca0f6cfa3ef941d39133ae401b6d84a6d5a59d (diff) | |
Merge "Ensure alt bouncer view is removed" into main
6 files changed, 274 insertions, 20 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt index 303548131788..68cfa28dabd7 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorTest.kt @@ -29,7 +29,6 @@ import com.android.systemui.biometrics.data.repository.fingerprintPropertyReposi import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository import com.android.systemui.coroutines.collectLastValue import com.android.systemui.deviceentry.domain.interactor.deviceUnlockedInteractor -import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor import com.android.systemui.flags.DisableSceneContainer import com.android.systemui.flags.EnableSceneContainer import com.android.systemui.keyguard.data.repository.biometricSettingsRepository @@ -223,23 +222,14 @@ class AlternateBouncerInteractorTest : SysuiTestCase() { } private fun givenAlternateBouncerSupported() { - if (DeviceEntryUdfpsRefactor.isEnabled) { - kosmos.fingerprintPropertyRepository.supportsUdfps() - } else { - kosmos.keyguardBouncerRepository.setAlternateBouncerUIAvailable(true) - } + kosmos.givenAlternateBouncerSupported() } private fun givenCanShowAlternateBouncer() { - givenAlternateBouncerSupported() - kosmos.keyguardBouncerRepository.setPrimaryShow(false) - kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) - kosmos.biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true) - whenever(kosmos.keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false) - whenever(kosmos.keyguardStateController.isUnlocked).thenReturn(false) + kosmos.givenCanShowAlternateBouncer() } private fun givenCannotShowAlternateBouncer() { - kosmos.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) + kosmos.givenCannotShowAlternateBouncer() } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt index f8063c92124d..db33acb93dc6 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt @@ -115,13 +115,28 @@ constructor( } private fun removeViewFromWindowManager() { - if (alternateBouncerView == null || !alternateBouncerView!!.isAttachedToWindow) { - return - } + alternateBouncerView?.let { + alternateBouncerView = null + if (it.isAttachedToWindow) { + it.removeOnAttachStateChangeListener(onAttachAddBackGestureHandler) + Log.d(TAG, "Removing alternate bouncer view immediately") + windowManager.get().removeView(it) + } else { + // once the view is attached, remove it + it.addOnAttachStateChangeListener( + object : View.OnAttachStateChangeListener { + override fun onViewAttachedToWindow(view: View) { + it.removeOnAttachStateChangeListener(this) + it.removeOnAttachStateChangeListener(onAttachAddBackGestureHandler) + Log.d(TAG, "Removing alternate bouncer view on attached") + windowManager.get().removeView(it) + } - windowManager.get().removeView(alternateBouncerView) - alternateBouncerView!!.removeOnAttachStateChangeListener(onAttachAddBackGestureHandler) - alternateBouncerView = null + override fun onViewDetachedFromWindow(view: View) {} + } + ) + } + } } private val onAttachAddBackGestureHandler = @@ -151,7 +166,7 @@ constructor( } private fun addViewToWindowManager() { - if (alternateBouncerView?.isAttachedToWindow == true) { + if (alternateBouncerView != null) { return } @@ -159,6 +174,7 @@ constructor( layoutInflater.get().inflate(R.layout.alternate_bouncer, null, false) as ConstraintLayout + Log.d(TAG, "Adding alternate bouncer view") windowManager.get().addView(alternateBouncerView, layoutParams) alternateBouncerView!!.addOnAttachStateChangeListener(onAttachAddBackGestureHandler) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt new file mode 100644 index 000000000000..c4eabd84e031 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderTest.kt @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2024 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.ui.binder + +import android.platform.test.annotations.EnableFlags +import android.testing.TestableLooper +import android.view.View +import android.view.layoutInflater +import android.view.mockedLayoutInflater +import android.view.windowManager +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.systemui.Flags.FLAG_DEVICE_ENTRY_UDFPS_REFACTOR +import com.android.systemui.SysuiTestCase +import com.android.systemui.bouncer.domain.interactor.givenCanShowAlternateBouncer +import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository +import com.android.systemui.keyguard.shared.model.KeyguardState +import com.android.systemui.kosmos.testScope +import com.android.systemui.res.R +import com.android.systemui.testKosmos +import com.android.systemui.util.mockito.eq +import com.android.systemui.util.mockito.whenever +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.ArgumentCaptor +import org.mockito.Mockito.any +import org.mockito.Mockito.anyBoolean +import org.mockito.Mockito.atLeastOnce +import org.mockito.Mockito.never +import org.mockito.Mockito.spy +import org.mockito.Mockito.verify +import org.mockito.kotlin.isNull + +@SmallTest +@RunWith(AndroidJUnit4::class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +class AlternateBouncerViewBinderTest : SysuiTestCase() { + private val kosmos = testKosmos() + private val testScope = kosmos.testScope + + private val mockedAltBouncerView = + spy(kosmos.layoutInflater.inflate(R.layout.alternate_bouncer, null, false)) + + @Before + fun setup() { + whenever( + kosmos.mockedLayoutInflater.inflate( + eq(R.layout.alternate_bouncer), + isNull(), + anyBoolean() + ) + ) + .thenReturn(mockedAltBouncerView) + kosmos.alternateBouncerViewBinder.start() + } + + @Test + @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + fun addViewToWindowManager() { + testScope.runTest { + kosmos.givenCanShowAlternateBouncer() + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.ALTERNATE_BOUNCER, + testScope, + ) + verify(kosmos.windowManager).addView(any(), any()) + } + } + + @Test + @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + fun viewRemovedImmediatelyIfAlreadyAttachedToWindow() { + testScope.runTest { + kosmos.givenCanShowAlternateBouncer() + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.ALTERNATE_BOUNCER, + testScope, + ) + verify(kosmos.windowManager).addView(any(), any()) + whenever(mockedAltBouncerView.isAttachedToWindow).thenReturn(true) + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.ALTERNATE_BOUNCER, + to = KeyguardState.LOCKSCREEN, + testScope, + ) + verify(kosmos.windowManager).removeView(any()) + } + } + + @Test + @EnableFlags(FLAG_DEVICE_ENTRY_UDFPS_REFACTOR) + fun viewNotRemovedUntilAttachedToWindow() { + testScope.runTest { + kosmos.givenCanShowAlternateBouncer() + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.LOCKSCREEN, + to = KeyguardState.ALTERNATE_BOUNCER, + testScope, + ) + verify(kosmos.windowManager).addView(any(), any()) + + kosmos.fakeKeyguardTransitionRepository.sendTransitionSteps( + from = KeyguardState.ALTERNATE_BOUNCER, + to = KeyguardState.LOCKSCREEN, + testScope, + ) + + verify(kosmos.windowManager, never()).removeView(any()) + givenAltBouncerViewAttachedToWindow() + verify(kosmos.windowManager).removeView(any()) + } + } + + private fun givenAltBouncerViewAttachedToWindow() { + val attachStateChangeListenerCaptor = + ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java) + verify(mockedAltBouncerView, atLeastOnce()) + .addOnAttachStateChangeListener(attachStateChangeListenerCaptor.capture()) + attachStateChangeListenerCaptor.allValues.onEach { + it.onViewAttachedToWindow(mockedAltBouncerView) + } + } +} diff --git a/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt b/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt index 21dea6b1cbd0..2ee289bd026d 100644 --- a/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt +++ b/packages/SystemUI/tests/utils/src/android/view/LayoutInflaterKosmos.kt @@ -18,6 +18,8 @@ package android.view import android.content.applicationContext import com.android.systemui.kosmos.Kosmos +import com.android.systemui.util.mockito.mock var Kosmos.layoutInflater: LayoutInflater by Kosmos.Fixture { LayoutInflater.from(applicationContext) } +var Kosmos.mockedLayoutInflater: LayoutInflater by Kosmos.Fixture { mock<LayoutInflater>() } diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt index f75cdd4d3bbc..9236bd2a2a8b 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bouncer/domain/interactor/AlternateBouncerInteractorKosmos.kt @@ -20,6 +20,7 @@ import com.android.keyguard.keyguardUpdateMonitor import com.android.systemui.biometrics.data.repository.fingerprintPropertyRepository import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository import com.android.systemui.deviceentry.domain.interactor.deviceEntryFingerprintAuthInteractor +import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor import com.android.systemui.keyguard.data.repository.biometricSettingsRepository import com.android.systemui.keyguard.domain.interactor.keyguardInteractor import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor @@ -28,6 +29,7 @@ import com.android.systemui.kosmos.testScope import com.android.systemui.plugins.statusbar.statusBarStateController import com.android.systemui.scene.domain.interactor.sceneInteractor import com.android.systemui.statusbar.policy.keyguardStateController +import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.systemClock val Kosmos.alternateBouncerInteractor: AlternateBouncerInteractor by @@ -47,3 +49,24 @@ val Kosmos.alternateBouncerInteractor: AlternateBouncerInteractor by sceneInteractor = { sceneInteractor }, ) } + +fun Kosmos.givenCanShowAlternateBouncer() { + this.givenAlternateBouncerSupported() + this.keyguardBouncerRepository.setPrimaryShow(false) + this.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true) + this.biometricSettingsRepository.setIsFingerprintAuthCurrentlyAllowed(true) + whenever(this.keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false) + whenever(this.keyguardStateController.isUnlocked).thenReturn(false) +} + +fun Kosmos.givenAlternateBouncerSupported() { + if (DeviceEntryUdfpsRefactor.isEnabled) { + this.fingerprintPropertyRepository.supportsUdfps() + } else { + this.keyguardBouncerRepository.setAlternateBouncerUIAvailable(true) + } +} + +fun Kosmos.givenCannotShowAlternateBouncer() { + this.biometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(false) +} diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt new file mode 100644 index 000000000000..6eb8a4925082 --- /dev/null +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2024 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.ui.binder + +import android.content.applicationContext +import android.view.layoutInflater +import android.view.mockedLayoutInflater +import android.view.windowManager +import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor +import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor +import com.android.systemui.common.ui.domain.interactor.configurationInteractor +import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor +import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel +import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerMessageAreaViewModel +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel +import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel +import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryBackgroundViewModel +import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerViewModel +import com.android.systemui.keyguard.ui.viewmodel.alternateBouncerWindowViewModel +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.power.domain.interactor.powerInteractor +import com.android.systemui.statusbar.gesture.TapGestureDetector +import com.android.systemui.util.mockito.mock +import kotlinx.coroutines.ExperimentalCoroutinesApi + +@OptIn(ExperimentalCoroutinesApi::class) +val Kosmos.alternateBouncerViewBinder by + Kosmos.Fixture { + AlternateBouncerViewBinder( + applicationScope = applicationCoroutineScope, + alternateBouncerWindowViewModel = { alternateBouncerWindowViewModel }, + alternateBouncerDependencies = { alternateBouncerDependencies }, + windowManager = { windowManager }, + layoutInflater = { mockedLayoutInflater }, + ) + } + +private val Kosmos.alternateBouncerDependencies by + Kosmos.Fixture { + AlternateBouncerDependencies( + viewModel = mock<AlternateBouncerViewModel>(), + swipeUpAnywhereGestureHandler = mock<SwipeUpAnywhereGestureHandler>(), + tapGestureDetector = mock<TapGestureDetector>(), + udfpsIconViewModel = alternateBouncerUdfpsIconViewModel, + udfpsAccessibilityOverlayViewModel = { + mock<AlternateBouncerUdfpsAccessibilityOverlayViewModel>() + }, + messageAreaViewModel = mock<AlternateBouncerMessageAreaViewModel>(), + powerInteractor = powerInteractor, + ) + } + +private val Kosmos.alternateBouncerUdfpsIconViewModel by + Kosmos.Fixture { + AlternateBouncerUdfpsIconViewModel( + context = applicationContext, + configurationInteractor = configurationInteractor, + deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor, + deviceEntryBackgroundViewModel = mock<DeviceEntryBackgroundViewModel>(), + fingerprintPropertyInteractor = fingerprintPropertyInteractor, + udfpsOverlayInteractor = udfpsOverlayInteractor, + alternateBouncerViewModel = alternateBouncerViewModel, + ) + } |