Merge "Reformat unfold lib with ktfmt"
This commit is contained in:
committed by
Android (Google) Code Review
commit
e0e9d4ef49
@@ -16,12 +16,14 @@
|
||||
package com.android.systemui.unfold
|
||||
|
||||
import android.annotation.FloatRange
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||
import com.android.systemui.statusbar.policy.CallbackController
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||
|
||||
/**
|
||||
* Interface that allows to receive unfold transition progress updates.
|
||||
*
|
||||
* It can be used to update view properties based on the current animation progress.
|
||||
*
|
||||
* onTransitionProgress callback could be called on each frame.
|
||||
*
|
||||
* Use [createUnfoldTransitionProgressProvider] to create instances of this interface
|
||||
|
||||
@@ -18,9 +18,8 @@ package com.android.systemui.unfold.config
|
||||
import android.content.Context
|
||||
import android.os.SystemProperties
|
||||
|
||||
internal class ResourceUnfoldTransitionConfig(
|
||||
private val context: Context
|
||||
) : UnfoldTransitionConfig {
|
||||
internal class ResourceUnfoldTransitionConfig(private val context: Context) :
|
||||
UnfoldTransitionConfig {
|
||||
|
||||
override val isEnabled: Boolean
|
||||
get() = readIsEnabledResource() && isPropertyEnabled
|
||||
@@ -29,19 +28,22 @@ internal class ResourceUnfoldTransitionConfig(
|
||||
get() = readIsHingeAngleEnabled()
|
||||
|
||||
private val isPropertyEnabled: Boolean
|
||||
get() = SystemProperties.getInt(UNFOLD_TRANSITION_MODE_PROPERTY_NAME,
|
||||
UNFOLD_TRANSITION_PROPERTY_ENABLED) == UNFOLD_TRANSITION_PROPERTY_ENABLED
|
||||
get() =
|
||||
SystemProperties.getInt(
|
||||
UNFOLD_TRANSITION_MODE_PROPERTY_NAME, UNFOLD_TRANSITION_PROPERTY_ENABLED) ==
|
||||
UNFOLD_TRANSITION_PROPERTY_ENABLED
|
||||
|
||||
private fun readIsEnabledResource(): Boolean = context.resources
|
||||
.getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled)
|
||||
private fun readIsEnabledResource(): Boolean =
|
||||
context.resources.getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled)
|
||||
|
||||
private fun readIsHingeAngleEnabled(): Boolean = context.resources
|
||||
.getBoolean(com.android.internal.R.bool.config_unfoldTransitionHingeAngle)
|
||||
private fun readIsHingeAngleEnabled(): Boolean =
|
||||
context.resources.getBoolean(com.android.internal.R.bool.config_unfoldTransitionHingeAngle)
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary persistent property to control unfold transition mode
|
||||
* See [com.android.unfold.config.AnimationMode]
|
||||
* Temporary persistent property to control unfold transition mode.
|
||||
*
|
||||
* See [com.android.unfold.config.AnimationMode].
|
||||
*/
|
||||
private const val UNFOLD_TRANSITION_MODE_PROPERTY_NAME = "persist.unfold.transition_enabled"
|
||||
private const val UNFOLD_TRANSITION_PROPERTY_ENABLED = 1
|
||||
|
||||
@@ -25,21 +25,17 @@ import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
|
||||
|
||||
/**
|
||||
* Emits animation progress with fixed timing after unfolding
|
||||
*/
|
||||
/** Emits animation progress with fixed timing after unfolding */
|
||||
internal class FixedTimingTransitionProgressProvider(
|
||||
private val foldStateProvider: FoldStateProvider
|
||||
) : UnfoldTransitionProgressProvider, FoldStateProvider.FoldUpdatesListener {
|
||||
|
||||
private val animatorListener = AnimatorListener()
|
||||
private val animator =
|
||||
ObjectAnimator.ofFloat(this, AnimationProgressProperty, 0f, 1f)
|
||||
.apply {
|
||||
duration = TRANSITION_TIME_MILLIS
|
||||
addListener(animatorListener)
|
||||
}
|
||||
|
||||
ObjectAnimator.ofFloat(this, AnimationProgressProperty, 0f, 1f).apply {
|
||||
duration = TRANSITION_TIME_MILLIS
|
||||
addListener(animatorListener)
|
||||
}
|
||||
|
||||
private var transitionProgress: Float = 0.0f
|
||||
set(value) {
|
||||
@@ -62,10 +58,8 @@ internal class FixedTimingTransitionProgressProvider(
|
||||
|
||||
override fun onFoldUpdate(@FoldUpdate update: Int) {
|
||||
when (update) {
|
||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE ->
|
||||
animator.start()
|
||||
FOLD_UPDATE_FINISH_CLOSED ->
|
||||
animator.cancel()
|
||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> animator.start()
|
||||
FOLD_UPDATE_FINISH_CLOSED -> animator.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,16 +71,12 @@ internal class FixedTimingTransitionProgressProvider(
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
override fun onHingeAngleUpdate(angle: Float) {
|
||||
}
|
||||
override fun onHingeAngleUpdate(angle: Float) {}
|
||||
|
||||
private object AnimationProgressProperty :
|
||||
FloatProperty<FixedTimingTransitionProgressProvider>("animation_progress") {
|
||||
|
||||
override fun setValue(
|
||||
provider: FixedTimingTransitionProgressProvider,
|
||||
value: Float
|
||||
) {
|
||||
override fun setValue(provider: FixedTimingTransitionProgressProvider, value: Float) {
|
||||
provider.transitionProgress = value
|
||||
}
|
||||
|
||||
@@ -104,11 +94,9 @@ internal class FixedTimingTransitionProgressProvider(
|
||||
listeners.forEach { it.onTransitionFinished() }
|
||||
}
|
||||
|
||||
override fun onAnimationRepeat(animator: Animator) {
|
||||
}
|
||||
override fun onAnimationRepeat(animator: Animator) {}
|
||||
|
||||
override fun onAnimationCancel(animator: Animator) {
|
||||
}
|
||||
override fun onAnimationCancel(animator: Animator) {}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
@@ -23,10 +23,10 @@ import androidx.dynamicanimation.animation.SpringAnimation
|
||||
import androidx.dynamicanimation.animation.SpringForce
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
|
||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
|
||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
|
||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
|
||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
|
||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_HALF_OPEN
|
||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
|
||||
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
|
||||
@@ -35,13 +35,10 @@ import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
|
||||
/** Maps fold updates to unfold transition progress using DynamicAnimation. */
|
||||
internal class PhysicsBasedUnfoldTransitionProgressProvider(
|
||||
private val foldStateProvider: FoldStateProvider
|
||||
) :
|
||||
UnfoldTransitionProgressProvider,
|
||||
FoldUpdatesListener,
|
||||
DynamicAnimation.OnAnimationEndListener {
|
||||
) : UnfoldTransitionProgressProvider, FoldUpdatesListener, DynamicAnimation.OnAnimationEndListener {
|
||||
|
||||
private val springAnimation = SpringAnimation(this, AnimationProgressProperty)
|
||||
.apply {
|
||||
private val springAnimation =
|
||||
SpringAnimation(this, AnimationProgressProperty).apply {
|
||||
addEndListener(this@PhysicsBasedUnfoldTransitionProgressProvider)
|
||||
}
|
||||
|
||||
@@ -121,9 +118,7 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider(
|
||||
isTransitionRunning = false
|
||||
springAnimation.cancel()
|
||||
|
||||
listeners.forEach {
|
||||
it.onTransitionFinished()
|
||||
}
|
||||
listeners.forEach { it.onTransitionFinished() }
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onTransitionFinished")
|
||||
@@ -143,9 +138,7 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider(
|
||||
}
|
||||
|
||||
private fun onStartTransition() {
|
||||
listeners.forEach {
|
||||
it.onTransitionStarted()
|
||||
}
|
||||
listeners.forEach { it.onTransitionStarted() }
|
||||
isTransitionRunning = true
|
||||
|
||||
if (DEBUG) {
|
||||
@@ -157,11 +150,12 @@ internal class PhysicsBasedUnfoldTransitionProgressProvider(
|
||||
if (!isTransitionRunning) onStartTransition()
|
||||
|
||||
springAnimation.apply {
|
||||
spring = SpringForce().apply {
|
||||
finalPosition = startValue
|
||||
dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
|
||||
stiffness = SPRING_STIFFNESS
|
||||
}
|
||||
spring =
|
||||
SpringForce().apply {
|
||||
finalPosition = startValue
|
||||
dampingRatio = SpringForce.DAMPING_RATIO_NO_BOUNCY
|
||||
stiffness = SPRING_STIFFNESS
|
||||
}
|
||||
minimumVisibleChange = MINIMAL_VISIBLE_CHANGE
|
||||
setStartValue(startValue)
|
||||
setMinValue(0f)
|
||||
|
||||
@@ -45,11 +45,9 @@ constructor(
|
||||
|
||||
private val outputListeners: MutableList<FoldUpdatesListener> = mutableListOf()
|
||||
|
||||
@FoldUpdate
|
||||
private var lastFoldUpdate: Int? = null
|
||||
@FoldUpdate private var lastFoldUpdate: Int? = null
|
||||
|
||||
@FloatRange(from = 0.0, to = 180.0)
|
||||
private var lastHingeAngle: Float = 0f
|
||||
@FloatRange(from = 0.0, to = 180.0) private var lastHingeAngle: Float = 0f
|
||||
|
||||
private val hingeAngleListener = HingeAngleListener()
|
||||
private val screenListener = ScreenStatusListener()
|
||||
@@ -60,10 +58,7 @@ constructor(
|
||||
private var isUnfoldHandled = true
|
||||
|
||||
override fun start() {
|
||||
deviceStateManager.registerCallback(
|
||||
mainExecutor,
|
||||
foldStateListener
|
||||
)
|
||||
deviceStateManager.registerCallback(mainExecutor, foldStateListener)
|
||||
screenStatusProvider.addCallback(screenListener)
|
||||
hingeAngleProvider.addCallback(hingeAngleListener)
|
||||
}
|
||||
@@ -87,11 +82,14 @@ constructor(
|
||||
get() = !isFolded && lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN
|
||||
|
||||
private val isTransitionInProgess: Boolean
|
||||
get() = lastFoldUpdate == FOLD_UPDATE_START_OPENING ||
|
||||
get() =
|
||||
lastFoldUpdate == FOLD_UPDATE_START_OPENING ||
|
||||
lastFoldUpdate == FOLD_UPDATE_START_CLOSING
|
||||
|
||||
private fun onHingeAngle(angle: Float) {
|
||||
if (DEBUG) { Log.d(TAG, "Hinge angle: $angle, lastHingeAngle: $lastHingeAngle") }
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Hinge angle: $angle, lastHingeAngle: $lastHingeAngle")
|
||||
}
|
||||
|
||||
val isClosing = angle < lastHingeAngle
|
||||
val isFullyOpened = FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES
|
||||
@@ -116,24 +114,28 @@ constructor(
|
||||
}
|
||||
|
||||
private inner class FoldStateListener(context: Context) :
|
||||
DeviceStateManager.FoldStateListener(context, { folded: Boolean ->
|
||||
isFolded = folded
|
||||
lastHingeAngle = FULLY_CLOSED_DEGREES
|
||||
DeviceStateManager.FoldStateListener(
|
||||
context,
|
||||
{ folded: Boolean ->
|
||||
isFolded = folded
|
||||
lastHingeAngle = FULLY_CLOSED_DEGREES
|
||||
|
||||
if (folded) {
|
||||
hingeAngleProvider.stop()
|
||||
notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
|
||||
cancelTimeout()
|
||||
isUnfoldHandled = false
|
||||
} else {
|
||||
notifyFoldUpdate(FOLD_UPDATE_START_OPENING)
|
||||
rescheduleAbortAnimationTimeout()
|
||||
hingeAngleProvider.start()
|
||||
}
|
||||
})
|
||||
if (folded) {
|
||||
hingeAngleProvider.stop()
|
||||
notifyFoldUpdate(FOLD_UPDATE_FINISH_CLOSED)
|
||||
cancelTimeout()
|
||||
isUnfoldHandled = false
|
||||
} else {
|
||||
notifyFoldUpdate(FOLD_UPDATE_START_OPENING)
|
||||
rescheduleAbortAnimationTimeout()
|
||||
hingeAngleProvider.start()
|
||||
}
|
||||
})
|
||||
|
||||
private fun notifyFoldUpdate(@FoldUpdate update: Int) {
|
||||
if (DEBUG) { Log.d(TAG, stateToString(update)) }
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, stateToString(update))
|
||||
}
|
||||
outputListeners.forEach { it.onFoldUpdate(update) }
|
||||
lastFoldUpdate = update
|
||||
}
|
||||
@@ -149,8 +151,7 @@ constructor(
|
||||
handler.removeCallbacks(timeoutRunnable)
|
||||
}
|
||||
|
||||
private inner class ScreenStatusListener :
|
||||
ScreenStatusProvider.ScreenListener {
|
||||
private inner class ScreenStatusListener : ScreenStatusProvider.ScreenListener {
|
||||
|
||||
override fun onScreenTurnedOn() {
|
||||
// Trigger this event only if we are unfolded and this is the first screen
|
||||
@@ -198,9 +199,7 @@ private const val DEBUG = false
|
||||
* Time after which [FOLD_UPDATE_FINISH_HALF_OPEN] is emitted following a
|
||||
* [FOLD_UPDATE_START_CLOSING] or [FOLD_UPDATE_START_OPENING] event, if an end state is not reached.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
const val HALF_OPENED_TIMEOUT_MILLIS = 1000L
|
||||
@VisibleForTesting const val HALF_OPENED_TIMEOUT_MILLIS = 1000L
|
||||
|
||||
/** Threshold after which we consider the device fully unfolded. */
|
||||
@VisibleForTesting
|
||||
const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
|
||||
@VisibleForTesting const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
|
||||
|
||||
@@ -17,8 +17,8 @@ package com.android.systemui.unfold.updates
|
||||
|
||||
import android.annotation.FloatRange
|
||||
import android.annotation.IntDef
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
|
||||
import com.android.systemui.statusbar.policy.CallbackController
|
||||
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdatesListener
|
||||
|
||||
/**
|
||||
* Allows to subscribe to main events related to fold/unfold process such as hinge angle update,
|
||||
@@ -35,14 +35,16 @@ interface FoldStateProvider : CallbackController<FoldUpdatesListener> {
|
||||
fun onFoldUpdate(@FoldUpdate update: Int)
|
||||
}
|
||||
|
||||
@IntDef(prefix = ["FOLD_UPDATE_"], value = [
|
||||
FOLD_UPDATE_START_OPENING,
|
||||
FOLD_UPDATE_START_CLOSING,
|
||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE,
|
||||
FOLD_UPDATE_FINISH_HALF_OPEN,
|
||||
FOLD_UPDATE_FINISH_FULL_OPEN,
|
||||
FOLD_UPDATE_FINISH_CLOSED
|
||||
])
|
||||
@IntDef(
|
||||
prefix = ["FOLD_UPDATE_"],
|
||||
value =
|
||||
[
|
||||
FOLD_UPDATE_START_OPENING,
|
||||
FOLD_UPDATE_START_CLOSING,
|
||||
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE,
|
||||
FOLD_UPDATE_FINISH_HALF_OPEN,
|
||||
FOLD_UPDATE_FINISH_FULL_OPEN,
|
||||
FOLD_UPDATE_FINISH_CLOSED])
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
annotation class FoldUpdate
|
||||
}
|
||||
|
||||
@@ -3,15 +3,11 @@ package com.android.systemui.unfold.updates.hinge
|
||||
import androidx.core.util.Consumer
|
||||
|
||||
internal object EmptyHingeAngleProvider : HingeAngleProvider {
|
||||
override fun start() {
|
||||
}
|
||||
override fun start() {}
|
||||
|
||||
override fun stop() {
|
||||
}
|
||||
override fun stop() {}
|
||||
|
||||
override fun removeCallback(listener: Consumer<Float>) {
|
||||
}
|
||||
override fun removeCallback(listener: Consumer<Float>) {}
|
||||
|
||||
override fun addCallback(listener: Consumer<Float>) {
|
||||
}
|
||||
override fun addCallback(listener: Consumer<Float>) {}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,10 @@ import com.android.systemui.statusbar.policy.CallbackController
|
||||
|
||||
/**
|
||||
* Emits device hinge angle values (angle between two integral parts of the device).
|
||||
* The hinge angle could be from 0 to 360 degrees inclusive.
|
||||
* For foldable devices usually 0 corresponds to fully closed (folded) state and
|
||||
* 180 degrees corresponds to fully open (flat) state
|
||||
*
|
||||
* The hinge angle could be from 0 to 360 degrees inclusive. For foldable devices usually 0
|
||||
* corresponds to fully closed (folded) state and 180 degrees corresponds to fully open (flat)
|
||||
* state.
|
||||
*/
|
||||
interface HingeAngleProvider : CallbackController<Consumer<Float>> {
|
||||
fun start()
|
||||
|
||||
@@ -6,9 +6,8 @@ import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import androidx.core.util.Consumer
|
||||
|
||||
internal class HingeSensorAngleProvider(
|
||||
private val sensorManager: SensorManager
|
||||
) : HingeAngleProvider {
|
||||
internal class HingeSensorAngleProvider(private val sensorManager: SensorManager) :
|
||||
HingeAngleProvider {
|
||||
|
||||
private val sensorListener = HingeAngleSensorListener()
|
||||
private val listeners: MutableList<Consumer<Float>> = arrayListOf()
|
||||
@@ -32,8 +31,7 @@ internal class HingeSensorAngleProvider(
|
||||
|
||||
private inner class HingeAngleSensorListener : SensorEventListener {
|
||||
|
||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
|
||||
}
|
||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
|
||||
|
||||
override fun onSensorChanged(event: SensorEvent) {
|
||||
listeners.forEach { it.accept(event.values[0]) }
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
package com.android.systemui.unfold.updates.screen
|
||||
|
||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
|
||||
import com.android.systemui.statusbar.policy.CallbackController
|
||||
import com.android.systemui.unfold.updates.screen.ScreenStatusProvider.ScreenListener
|
||||
|
||||
interface ScreenStatusProvider : CallbackController<ScreenListener> {
|
||||
|
||||
|
||||
@@ -10,9 +10,8 @@ import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionPr
|
||||
|
||||
/**
|
||||
* [UnfoldTransitionProgressProvider] that emits transition progress only when the display has
|
||||
* default rotation or 180 degrees opposite rotation (ROTATION_0 or ROTATION_180).
|
||||
* It could be helpful to run the animation only when the display's rotation is perpendicular
|
||||
* to the fold.
|
||||
* default rotation or 180 degrees opposite rotation (ROTATION_0 or ROTATION_180). It could be
|
||||
* helpful to run the animation only when the display's rotation is perpendicular to the fold.
|
||||
*/
|
||||
class NaturalRotationUnfoldProgressProvider(
|
||||
private val context: Context,
|
||||
@@ -21,7 +20,7 @@ class NaturalRotationUnfoldProgressProvider(
|
||||
) : UnfoldTransitionProgressProvider {
|
||||
|
||||
private val scopedUnfoldTransitionProgressProvider =
|
||||
ScopedUnfoldTransitionProgressProvider(unfoldTransitionProgressProvider)
|
||||
ScopedUnfoldTransitionProgressProvider(unfoldTransitionProgressProvider)
|
||||
private val rotationWatcher = RotationWatcher()
|
||||
|
||||
private var isNaturalRotation: Boolean = false
|
||||
@@ -37,8 +36,8 @@ class NaturalRotationUnfoldProgressProvider(
|
||||
}
|
||||
|
||||
private fun onRotationChanged(rotation: Int) {
|
||||
val isNewRotationNatural = rotation == Surface.ROTATION_0 ||
|
||||
rotation == Surface.ROTATION_180
|
||||
val isNewRotationNatural =
|
||||
rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
|
||||
|
||||
if (isNaturalRotation != isNewRotationNatural) {
|
||||
isNaturalRotation = isNewRotationNatural
|
||||
|
||||
@@ -21,17 +21,18 @@ constructor(
|
||||
private val scopedUnfoldTransitionProgressProvider =
|
||||
ScopedUnfoldTransitionProgressProvider(progressProviderToWrap)
|
||||
|
||||
private val animatorDurationScaleObserver = object : ContentObserver(null) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
onAnimatorScaleChanged()
|
||||
private val animatorDurationScaleObserver =
|
||||
object : ContentObserver(null) {
|
||||
override fun onChange(selfChange: Boolean) {
|
||||
onAnimatorScaleChanged()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
contentResolver.registerContentObserver(
|
||||
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
|
||||
/* notifyForDescendants= */ false,
|
||||
animatorDurationScaleObserver)
|
||||
Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
|
||||
/* notifyForDescendants= */ false,
|
||||
animatorDurationScaleObserver)
|
||||
onAnimatorScaleChanged()
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,18 @@ import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionPr
|
||||
|
||||
/**
|
||||
* Manages progress listeners that can have smaller lifespan than the unfold animation.
|
||||
* Allows to limit getting transition updates to only when
|
||||
* [ScopedUnfoldTransitionProgressProvider.setReadyToHandleTransition] is called
|
||||
* with readyToHandleTransition = true
|
||||
*
|
||||
* If the transition has already started by the moment when the clients are ready to play
|
||||
* the transition then it will report transition started callback and current animation progress.
|
||||
* Allows to limit getting transition updates to only when
|
||||
* [ScopedUnfoldTransitionProgressProvider.setReadyToHandleTransition] is called with
|
||||
* readyToHandleTransition = true
|
||||
*
|
||||
* If the transition has already started by the moment when the clients are ready to play the
|
||||
* transition then it will report transition started callback and current animation progress.
|
||||
*/
|
||||
class ScopedUnfoldTransitionProgressProvider @JvmOverloads constructor(
|
||||
source: UnfoldTransitionProgressProvider? = null
|
||||
) : UnfoldTransitionProgressProvider, TransitionProgressListener {
|
||||
class ScopedUnfoldTransitionProgressProvider
|
||||
@JvmOverloads
|
||||
constructor(source: UnfoldTransitionProgressProvider? = null) :
|
||||
UnfoldTransitionProgressProvider, TransitionProgressListener {
|
||||
|
||||
private var source: UnfoldTransitionProgressProvider? = null
|
||||
|
||||
@@ -43,8 +45,8 @@ class ScopedUnfoldTransitionProgressProvider @JvmOverloads constructor(
|
||||
setSourceProvider(source)
|
||||
}
|
||||
/**
|
||||
* Sets the source for the unfold transition progress updates,
|
||||
* it replaces current provider if it is already set
|
||||
* Sets the source for the unfold transition progress updates. Replaces current provider if it
|
||||
* is already set
|
||||
* @param provider transition provider that emits transition progress updates
|
||||
*/
|
||||
fun setSourceProvider(provider: UnfoldTransitionProgressProvider?) {
|
||||
@@ -60,8 +62,10 @@ class ScopedUnfoldTransitionProgressProvider @JvmOverloads constructor(
|
||||
|
||||
/**
|
||||
* Allows to notify this provide whether the listeners can play the transition or not.
|
||||
* Call this method with readyToHandleTransition = true when all listeners
|
||||
* are ready to consume the transition progress events.
|
||||
*
|
||||
* Call this method with readyToHandleTransition = true when all listeners are ready to consume
|
||||
* the transition progress events.
|
||||
*
|
||||
* Call it with readyToHandleTransition = false when listeners can't process the events.
|
||||
*/
|
||||
fun setReadyToHandleTransition(isReadyToHandleTransition: Boolean) {
|
||||
|
||||
@@ -30,17 +30,17 @@ import dagger.Lazy
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Controls folding to AOD animation: when AOD is enabled and foldable device is folded
|
||||
* we play a special AOD animation on the outer screen
|
||||
* Controls folding to AOD animation: when AOD is enabled and foldable device is folded we play a
|
||||
* special AOD animation on the outer screen
|
||||
*/
|
||||
@SysUIUnfoldScope
|
||||
class FoldAodAnimationController @Inject constructor(
|
||||
class FoldAodAnimationController
|
||||
@Inject
|
||||
constructor(
|
||||
private val keyguardViewMediatorLazy: Lazy<KeyguardViewMediator>,
|
||||
private val wakefulnessLifecycle: WakefulnessLifecycle,
|
||||
private val globalSettings: GlobalSettings
|
||||
) : CallbackController<FoldAodAnimationStatus>,
|
||||
ScreenOffAnimation,
|
||||
WakefulnessLifecycle.Observer {
|
||||
) : CallbackController<FoldAodAnimationStatus>, ScreenOffAnimation, WakefulnessLifecycle.Observer {
|
||||
|
||||
private var alwaysOnEnabled: Boolean = false
|
||||
private var isScrimOpaque: Boolean = false
|
||||
@@ -58,17 +58,13 @@ class FoldAodAnimationController @Inject constructor(
|
||||
wakefulnessLifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if we should run fold to AOD animation
|
||||
*/
|
||||
override fun shouldPlayAnimation(): Boolean =
|
||||
shouldPlayAnimation
|
||||
/** Returns true if we should run fold to AOD animation */
|
||||
override fun shouldPlayAnimation(): Boolean = shouldPlayAnimation
|
||||
|
||||
override fun startAnimation(): Boolean =
|
||||
if (alwaysOnEnabled &&
|
||||
wakefulnessLifecycle.lastSleepReason == PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD &&
|
||||
globalSettings.getString(Settings.Global.ANIMATOR_DURATION_SCALE) != "0"
|
||||
) {
|
||||
globalSettings.getString(Settings.Global.ANIMATOR_DURATION_SCALE) != "0") {
|
||||
shouldPlayAnimation = true
|
||||
|
||||
isAnimationPlaying = true
|
||||
@@ -107,9 +103,7 @@ class FoldAodAnimationController @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when keyguard scrim opaque changed
|
||||
*/
|
||||
/** Called when keyguard scrim opaque changed */
|
||||
override fun onScrimOpaqueChanged(isOpaque: Boolean) {
|
||||
isScrimOpaque = isOpaque
|
||||
|
||||
@@ -130,27 +124,19 @@ class FoldAodAnimationController @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun isAnimationPlaying(): Boolean =
|
||||
isAnimationPlaying
|
||||
override fun isAnimationPlaying(): Boolean = isAnimationPlaying
|
||||
|
||||
override fun isKeyguardHideDelayed(): Boolean =
|
||||
isAnimationPlaying()
|
||||
override fun isKeyguardHideDelayed(): Boolean = isAnimationPlaying()
|
||||
|
||||
override fun shouldShowAodIconsWhenShade(): Boolean =
|
||||
shouldPlayAnimation()
|
||||
override fun shouldShowAodIconsWhenShade(): Boolean = shouldPlayAnimation()
|
||||
|
||||
override fun shouldAnimateAodIcons(): Boolean =
|
||||
!shouldPlayAnimation()
|
||||
override fun shouldAnimateAodIcons(): Boolean = !shouldPlayAnimation()
|
||||
|
||||
override fun shouldAnimateDozingChange(): Boolean =
|
||||
!shouldPlayAnimation()
|
||||
override fun shouldAnimateDozingChange(): Boolean = !shouldPlayAnimation()
|
||||
|
||||
override fun shouldAnimateClockChange(): Boolean =
|
||||
!isAnimationPlaying()
|
||||
override fun shouldAnimateClockChange(): Boolean = !isAnimationPlaying()
|
||||
|
||||
/**
|
||||
* Called when AOD status is changed
|
||||
*/
|
||||
/** Called when AOD status is changed */
|
||||
override fun onAlwaysOnChanged(alwaysOn: Boolean) {
|
||||
alwaysOnEnabled = alwaysOn
|
||||
}
|
||||
|
||||
@@ -29,12 +29,16 @@ import javax.inject.Inject
|
||||
* Logs performance metrics regarding time to turn the inner screen on.
|
||||
*
|
||||
* This class assumes that [onFoldEvent] is always called before [onScreenTurnedOn].
|
||||
*
|
||||
* This should be used from only one process.
|
||||
*
|
||||
* For now, the focus is on the time the inner display is visible, but in the future, it is easily
|
||||
* possible to monitor the time to go from the inner screen to the outer.
|
||||
*/
|
||||
@SysUISingleton
|
||||
class UnfoldLatencyTracker @Inject constructor(
|
||||
class UnfoldLatencyTracker
|
||||
@Inject
|
||||
constructor(
|
||||
private val latencyTracker: LatencyTracker,
|
||||
private val deviceStateManager: DeviceStateManager,
|
||||
@UiBackground private val uiBgExecutor: Executor,
|
||||
@@ -45,8 +49,11 @@ class UnfoldLatencyTracker @Inject constructor(
|
||||
private var folded: Boolean? = null
|
||||
private val foldStateListener = FoldStateListener(context)
|
||||
private val isFoldable: Boolean
|
||||
get() = context.resources.getIntArray(
|
||||
com.android.internal.R.array.config_foldedDeviceStates).isNotEmpty()
|
||||
get() =
|
||||
context
|
||||
.resources
|
||||
.getIntArray(com.android.internal.R.array.config_foldedDeviceStates)
|
||||
.isNotEmpty()
|
||||
|
||||
/** Registers for relevant events only if the device is foldable. */
|
||||
fun init() {
|
||||
|
||||
@@ -20,8 +20,8 @@ import android.content.Context
|
||||
import android.graphics.PixelFormat
|
||||
import android.hardware.devicestate.DeviceStateManager
|
||||
import android.hardware.devicestate.DeviceStateManager.FoldStateListener
|
||||
import android.hardware.input.InputManager
|
||||
import android.hardware.display.DisplayManager
|
||||
import android.hardware.input.InputManager
|
||||
import android.os.Handler
|
||||
import android.os.Trace
|
||||
import android.view.Choreographer
|
||||
@@ -46,7 +46,9 @@ import java.util.function.Consumer
|
||||
import javax.inject.Inject
|
||||
|
||||
@SysUIUnfoldScope
|
||||
class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
class UnfoldLightRevealOverlayAnimation
|
||||
@Inject
|
||||
constructor(
|
||||
private val context: Context,
|
||||
private val deviceStateManager: DeviceStateManager,
|
||||
private val displayManager: DisplayManager,
|
||||
@@ -75,12 +77,13 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
deviceStateManager.registerCallback(executor, FoldListener())
|
||||
unfoldTransitionProgressProvider.addCallback(transitionListener)
|
||||
|
||||
val containerBuilder = SurfaceControl.Builder(SurfaceSession())
|
||||
.setContainerLayer()
|
||||
.setName("unfold-overlay-container")
|
||||
val containerBuilder =
|
||||
SurfaceControl.Builder(SurfaceSession())
|
||||
.setContainerLayer()
|
||||
.setName("unfold-overlay-container")
|
||||
|
||||
displayAreaHelper.get().attachToRootDisplayArea(Display.DEFAULT_DISPLAY,
|
||||
containerBuilder) { builder ->
|
||||
displayAreaHelper.get().attachToRootDisplayArea(
|
||||
Display.DEFAULT_DISPLAY, containerBuilder) { builder ->
|
||||
executor.execute {
|
||||
overlayContainer = builder.build()
|
||||
|
||||
@@ -89,13 +92,13 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
.show(overlayContainer)
|
||||
.apply()
|
||||
|
||||
wwm = WindowlessWindowManager(context.resources.configuration,
|
||||
overlayContainer, null)
|
||||
wwm =
|
||||
WindowlessWindowManager(context.resources.configuration, overlayContainer, null)
|
||||
}
|
||||
}
|
||||
|
||||
displayManager.registerDisplayListener(displayListener, handler,
|
||||
DisplayManager.EVENT_FLAG_DISPLAY_CHANGED)
|
||||
displayManager.registerDisplayListener(
|
||||
displayListener, handler, DisplayManager.EVENT_FLAG_DISPLAY_CHANGED)
|
||||
|
||||
// Get unfolded display size immediately as 'current display info' might be
|
||||
// not up-to-date during unfolding
|
||||
@@ -136,8 +139,8 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
ensureOverlayRemoved()
|
||||
|
||||
val newRoot = SurfaceControlViewHost(context, context.display!!, wwm, false)
|
||||
val newView = LightRevealScrim(context, null)
|
||||
.apply {
|
||||
val newView =
|
||||
LightRevealScrim(context, null).apply {
|
||||
revealEffect = createLightRevealEffect()
|
||||
isScrimOpaqueChangedListener = Consumer {}
|
||||
revealAmount = 0f
|
||||
@@ -147,8 +150,7 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
newRoot.setView(newView, params)
|
||||
|
||||
onOverlayReady?.let { callback ->
|
||||
Trace.beginAsyncSection(
|
||||
"UnfoldLightRevealOverlayAnimation#relayout", 0)
|
||||
Trace.beginAsyncSection("UnfoldLightRevealOverlayAnimation#relayout", 0)
|
||||
|
||||
newRoot.relayout(params) { transaction ->
|
||||
val vsyncId = Choreographer.getSfInstance().vsyncId
|
||||
@@ -161,15 +163,11 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
// (turn on the brightness) only when the content is actually visible as it
|
||||
// might be presented only in the next frame.
|
||||
// See b/197538198
|
||||
transaction.setFrameTimelineVsync(vsyncId)
|
||||
.apply(/* sync */true)
|
||||
transaction.setFrameTimelineVsync(vsyncId).apply(/* sync */ true)
|
||||
|
||||
transaction
|
||||
.setFrameTimelineVsync(vsyncId + 1)
|
||||
.apply(/* sync */ true)
|
||||
transaction.setFrameTimelineVsync(vsyncId + 1).apply(/* sync */ true)
|
||||
|
||||
Trace.endAsyncSection(
|
||||
"UnfoldLightRevealOverlayAnimation#relayout", 0)
|
||||
Trace.endAsyncSection("UnfoldLightRevealOverlayAnimation#relayout", 0)
|
||||
callback.run()
|
||||
}
|
||||
}
|
||||
@@ -185,10 +183,10 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
val rotation = context.display!!.rotation
|
||||
val isNatural = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
|
||||
|
||||
params.height = if (isNatural)
|
||||
unfoldedDisplayInfo.naturalHeight else unfoldedDisplayInfo.naturalWidth
|
||||
params.width = if (isNatural)
|
||||
unfoldedDisplayInfo.naturalWidth else unfoldedDisplayInfo.naturalHeight
|
||||
params.height =
|
||||
if (isNatural) unfoldedDisplayInfo.naturalHeight else unfoldedDisplayInfo.naturalWidth
|
||||
params.width =
|
||||
if (isNatural) unfoldedDisplayInfo.naturalWidth else unfoldedDisplayInfo.naturalHeight
|
||||
|
||||
params.format = PixelFormat.TRANSLUCENT
|
||||
params.type = WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY
|
||||
@@ -206,8 +204,8 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
}
|
||||
|
||||
private fun createLightRevealEffect(): LightRevealEffect {
|
||||
val isVerticalFold = currentRotation == Surface.ROTATION_0 ||
|
||||
currentRotation == Surface.ROTATION_180
|
||||
val isVerticalFold =
|
||||
currentRotation == Surface.ROTATION_0 || currentRotation == Surface.ROTATION_180
|
||||
return LinearLightRevealEffect(isVertical = isVerticalFold)
|
||||
}
|
||||
|
||||
@@ -218,7 +216,8 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
}
|
||||
|
||||
private fun getUnfoldedDisplayInfo(): DisplayInfo =
|
||||
displayManager.displays
|
||||
displayManager
|
||||
.displays
|
||||
.asSequence()
|
||||
.map { DisplayInfo().apply { it.getDisplayInfo(this) } }
|
||||
.filter { it.type == Display.TYPE_INTERNAL }
|
||||
@@ -255,18 +254,19 @@ class UnfoldLightRevealOverlayAnimation @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDisplayAdded(displayId: Int) {
|
||||
}
|
||||
override fun onDisplayAdded(displayId: Int) {}
|
||||
|
||||
override fun onDisplayRemoved(displayId: Int) {
|
||||
}
|
||||
override fun onDisplayRemoved(displayId: Int) {}
|
||||
}
|
||||
|
||||
private inner class FoldListener : FoldStateListener(context, Consumer { isFolded ->
|
||||
if (isFolded) {
|
||||
ensureOverlayRemoved()
|
||||
isUnfoldHandled = false
|
||||
}
|
||||
this.isFolded = isFolded
|
||||
})
|
||||
private inner class FoldListener :
|
||||
FoldStateListener(
|
||||
context,
|
||||
Consumer { isFolded ->
|
||||
if (isFolded) {
|
||||
ensureOverlayRemoved()
|
||||
isUnfoldHandled = false
|
||||
}
|
||||
this.isFolded = isFolded
|
||||
})
|
||||
}
|
||||
|
||||
@@ -21,29 +21,23 @@ import com.android.wm.shell.unfold.ShellUnfoldProgressProvider
|
||||
import com.android.wm.shell.unfold.ShellUnfoldProgressProvider.UnfoldListener
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
class UnfoldProgressProvider(
|
||||
private val unfoldProgressProvider: UnfoldTransitionProgressProvider
|
||||
) : ShellUnfoldProgressProvider {
|
||||
class UnfoldProgressProvider(private val unfoldProgressProvider: UnfoldTransitionProgressProvider) :
|
||||
ShellUnfoldProgressProvider {
|
||||
|
||||
override fun addListener(executor: Executor, listener: UnfoldListener) {
|
||||
unfoldProgressProvider.addCallback(object : TransitionProgressListener {
|
||||
override fun onTransitionStarted() {
|
||||
executor.execute {
|
||||
listener.onStateChangeStarted()
|
||||
unfoldProgressProvider.addCallback(
|
||||
object : TransitionProgressListener {
|
||||
override fun onTransitionStarted() {
|
||||
executor.execute { listener.onStateChangeStarted() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTransitionProgress(progress: Float) {
|
||||
executor.execute {
|
||||
listener.onStateChangeProgress(progress)
|
||||
override fun onTransitionProgress(progress: Float) {
|
||||
executor.execute { listener.onStateChangeProgress(progress) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTransitionFinished() {
|
||||
executor.execute {
|
||||
listener.onStateChangeFinished()
|
||||
override fun onTransitionFinished() {
|
||||
executor.execute { listener.onStateChangeFinished() }
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ class UnfoldTransitionModule {
|
||||
config: UnfoldTransitionConfig,
|
||||
provider: Optional<UnfoldTransitionProgressProvider>
|
||||
): ShellUnfoldProgressProvider =
|
||||
if (config.isEnabled && provider.isPresent()) {
|
||||
if (config.isEnabled && provider.isPresent) {
|
||||
UnfoldProgressProvider(provider.get())
|
||||
} else {
|
||||
ShellUnfoldProgressProvider.NO_PROVIDER
|
||||
|
||||
@@ -21,7 +21,9 @@ import com.android.systemui.util.WallpaperController
|
||||
import javax.inject.Inject
|
||||
|
||||
@SysUIUnfoldScope
|
||||
class UnfoldTransitionWallpaperController @Inject constructor(
|
||||
class UnfoldTransitionWallpaperController
|
||||
@Inject
|
||||
constructor(
|
||||
private val unfoldTransitionProgressProvider: UnfoldTransitionProgressProvider,
|
||||
private val wallpaperController: WallpaperController
|
||||
) {
|
||||
|
||||
Reference in New Issue
Block a user