diff options
6 files changed, 169 insertions, 4 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt index 209d93f786a2..1482cfccdfc6 100644 --- a/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt +++ b/packages/SystemUI/src/com/android/systemui/unfold/SysUIUnfoldModule.kt @@ -20,6 +20,7 @@ import com.android.keyguard.KeyguardUnfoldTransition import com.android.systemui.dagger.SysUISingleton import com.android.systemui.shade.NotificationPanelUnfoldAnimationController import com.android.systemui.statusbar.phone.StatusBarMoveFromCenterAnimationController +import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider import com.android.systemui.util.kotlin.getOrNull @@ -95,4 +96,6 @@ interface SysUIUnfoldComponent { fun getUnfoldHapticsPlayer(): UnfoldHapticsPlayer fun getUnfoldLightRevealOverlayAnimation(): UnfoldLightRevealOverlayAnimation + + fun getUnfoldKeyguardVisibilityManager(): UnfoldKeyguardVisibilityManager } diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldKeyguardVisibilityListener.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldKeyguardVisibilityListener.kt new file mode 100644 index 000000000000..59558ac0f4bd --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldKeyguardVisibilityListener.kt @@ -0,0 +1,39 @@ +package com.android.systemui.unfold + +import android.util.Log +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.statusbar.policy.KeyguardStateController +import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager +import com.android.systemui.util.kotlin.getOrNull +import java.util.Optional +import javax.inject.Inject + +/** + * Used to set the keyguard visibility state to [UnfoldKeyguardVisibilityManager]. + * + * It is not possible to directly inject a sysui class (e.g. [KeyguardStateController]) into + * [DeviceStateProvider], as it can't depend on google sysui directly. So, + * [UnfoldKeyguardVisibilityManager] is provided to clients, that can set the keyguard visibility + * accordingly. + */ +@SysUISingleton +class UnfoldKeyguardVisibilityListener +@Inject +constructor( + keyguardStateController: KeyguardStateController, + unfoldComponent: Optional<SysUIUnfoldComponent>, +) { + + private val unfoldKeyguardVisibilityManager = + unfoldComponent.getOrNull()?.getUnfoldKeyguardVisibilityManager() + + private val delegate = { keyguardStateController.isVisible } + + fun init() { + unfoldKeyguardVisibilityManager?.setKeyguardVisibleDelegate(delegate).also { + Log.d(TAG, "setKeyguardVisibleDelegate set") + } + } +} + +private const val TAG = "UnfoldKeyguardVisibilityListener" diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt index 7d5f06c890c2..6086e16fb49a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/updates/DeviceFoldStateProviderTest.kt @@ -29,6 +29,7 @@ import com.android.systemui.unfold.updates.RotationChangeProvider.RotationListen import com.android.systemui.unfold.updates.hinge.HingeAngleProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener +import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityProvider import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.capture import com.google.common.truth.Truth.assertThat @@ -56,6 +57,9 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { @Mock private lateinit var rotationChangeProvider: RotationChangeProvider + @Mock + private lateinit var unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider + @Captor private lateinit var rotationListener: ArgumentCaptor<RotationListener> @@ -87,6 +91,7 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { screenOnStatusProvider, foldProvider, activityTypeProvider, + unfoldKeyguardVisibilityProvider, rotationChangeProvider, context.mainExecutor, handler @@ -380,6 +385,47 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { } @Test + fun startClosingEvent_whileNotOnKeyguardAndNotOnLauncher_doesNotTriggerBeforeThreshold() { + setKeyguardVisibility(visible = false) + setupForegroundActivityType(isHomeActivity = false) + sendHingeAngleEvent(180) + + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1) + + assertThat(foldUpdates).isEmpty() + } + + @Test + fun startClosingEvent_whileKeyguardStateNotAvailable_triggerBeforeThreshold() { + setKeyguardVisibility(visible = null) + sendHingeAngleEvent(180) + + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING) + } + + @Test + fun startClosingEvent_whileonKeyguard_doesTriggerBeforeThreshold() { + setKeyguardVisibility(visible = true) + sendHingeAngleEvent(180) + + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES + 1) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING) + } + + @Test + fun startClosingEvent_whileNotOnKeyguard_triggersAfterThreshold() { + setKeyguardVisibility(visible = false) + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES) + + sendHingeAngleEvent(START_CLOSING_ON_APPS_THRESHOLD_DEGREES - 1) + + assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING) + } + + @Test fun screenOff_whileFolded_hingeAngleProviderRemainsOff() { setFoldState(folded = true) assertThat(testHingeAngleProvider.isStarted).isFalse() @@ -445,6 +491,10 @@ class DeviceFoldStateProviderTest : SysuiTestCase() { whenever(activityTypeProvider.isHomeActivity).thenReturn(isHomeActivity) } + private fun setKeyguardVisibility(visible: Boolean?) { + whenever(unfoldKeyguardVisibilityProvider.isKeyguardVisible).thenReturn(visible) + } + private fun simulateTimeout(waitTime: Long = HALF_OPENED_TIMEOUT_MILLIS) { val runnableDelay = scheduledRunnableDelay ?: throw Exception("No runnable scheduled.") if (waitTime >= runnableDelay) { diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt index 8f4ee4dc9838..3fa546914d3a 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/UnfoldSharedModule.kt @@ -28,6 +28,9 @@ import com.android.systemui.unfold.updates.hinge.HingeAngleProvider import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider import com.android.systemui.unfold.util.ATraceLoggerTransitionProgressListener import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider +import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManager +import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityManagerImpl +import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityProvider import dagger.Module import dagger.Provides import java.util.Optional @@ -57,7 +60,8 @@ class UnfoldSharedModule { scaleAwareProviderFactory.wrap(baseProgressProvider).apply { // Always present callback that logs animation beginning and end. addCallback(tracingListener) - }) + } + ) } @Provides @@ -77,4 +81,16 @@ class UnfoldSharedModule { } else { EmptyHingeAngleProvider } + + @Provides + @Singleton + fun unfoldKeyguardVisibilityProvider( + impl: UnfoldKeyguardVisibilityManagerImpl + ): UnfoldKeyguardVisibilityProvider = impl + + @Provides + @Singleton + fun unfoldKeyguardVisibilityManager( + impl: UnfoldKeyguardVisibilityManagerImpl + ): UnfoldKeyguardVisibilityManager = impl } diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt index 808128d16b7e..5b458975fa34 100644 --- a/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt @@ -31,6 +31,7 @@ import com.android.systemui.unfold.updates.hinge.FULLY_OPEN_DEGREES import com.android.systemui.unfold.updates.hinge.HingeAngleProvider import com.android.systemui.unfold.updates.screen.ScreenStatusProvider import com.android.systemui.unfold.util.CurrentActivityTypeProvider +import com.android.systemui.unfold.util.UnfoldKeyguardVisibilityProvider import java.util.concurrent.Executor import javax.inject.Inject @@ -42,6 +43,7 @@ constructor( private val screenStatusProvider: ScreenStatusProvider, private val foldProvider: FoldProvider, private val activityTypeProvider: CurrentActivityTypeProvider, + private val unfoldKeyguardVisibilityProvider: UnfoldKeyguardVisibilityProvider, private val rotationChangeProvider: RotationChangeProvider, @UnfoldMain private val mainExecutor: Executor, @UnfoldMain private val handler: Handler @@ -152,12 +154,13 @@ constructor( */ private fun getClosingThreshold(): Int? { val isHomeActivity = activityTypeProvider.isHomeActivity ?: return null + val isKeyguardVisible = unfoldKeyguardVisibilityProvider.isKeyguardVisible == true if (DEBUG) { - Log.d(TAG, "isHomeActivity=$isHomeActivity") + Log.d(TAG, "isHomeActivity=$isHomeActivity, isOnKeyguard=$isKeyguardVisible") } - return if (isHomeActivity) { + return if (isHomeActivity || isKeyguardVisible) { null } else { START_CLOSING_ON_APPS_THRESHOLD_DEGREES @@ -257,7 +260,7 @@ fun @receiver:FoldUpdate Int.name() = } private const val TAG = "DeviceFoldProvider" -private const val DEBUG = false +private val DEBUG = Log.isLoggable(TAG, Log.DEBUG) /** Threshold after which we consider the device fully unfolded. */ @VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f diff --git a/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/UnfoldKeyguardVisibilityProvider.kt b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/UnfoldKeyguardVisibilityProvider.kt new file mode 100644 index 000000000000..9f0efa02906d --- /dev/null +++ b/packages/SystemUI/unfold/src/com/android/systemui/unfold/util/UnfoldKeyguardVisibilityProvider.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2022 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.unfold.util + +import java.lang.ref.WeakReference +import javax.inject.Inject +import javax.inject.Singleton + +interface UnfoldKeyguardVisibilityProvider { + /** + * True when the keyguard is visible. + * + * Might be [null] when it is not known. + */ + val isKeyguardVisible: Boolean? +} + +/** Used to notify keyguard visibility. */ +interface UnfoldKeyguardVisibilityManager { + /** Sets the delegate. [delegate] should return true when the keyguard is visible. */ + fun setKeyguardVisibleDelegate(delegate: () -> Boolean) +} + +/** + * Keeps a [WeakReference] for the keyguard visibility provider. + * + * It is a weak reference because this is in the global scope, while the delegate might be set from + * another subcomponent (that might have shorter lifespan). + */ +@Singleton +class UnfoldKeyguardVisibilityManagerImpl @Inject constructor() : + UnfoldKeyguardVisibilityProvider, UnfoldKeyguardVisibilityManager { + + private var delegatedProvider: WeakReference<() -> Boolean?>? = null + + override fun setKeyguardVisibleDelegate(delegate: () -> Boolean) { + delegatedProvider = WeakReference(delegate) + } + + override val isKeyguardVisible: Boolean? + get() = delegatedProvider?.get()?.invoke() +} |