Trigger unfold animation without treshold while on keyguard
When folding, the fold animation triggers at different angles based on what's on the screen. Before this cl, it was triggering regardless of the angle only while on launcher, and after a certain threshold in all other cases. While on keyguard, the angle depended by the app that was in foreground. (e.g. if calculator was open, and device locked, the threshold was 60 degrees). After this change, while the keyguard is visible, there is no threshold. It has been needed to create the intermediate UnfoldKeyguardVisibilityListener as DeviceFoldStateProvider is in the global dagger scope, while KeyguardStateController in the sysui subcomponent (so, injecting KeyguardStateController directly in DeviceFoldStateProvider is not possible). From launcher, it is expected we don't have the information whether keyguard is visible (as we don't need it). Bug: 261313897 Test: DeviceFoldStateProviderTest & manual Change-Id: I07f133e96b16572448754ce2009f55e9e316b136
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -379,6 +384,47 @@ class DeviceFoldStateProviderTest : SysuiTestCase() {
|
||||
assertThat(foldUpdates).containsExactly(FOLD_UPDATE_START_CLOSING)
|
||||
}
|
||||
|
||||
@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)
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user