Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1b85a8b authored by Evan Laird's avatar Evan Laird
Browse files

Rework system event animations to a federated model

Before this cl, all system event chip animations were structured to run
via callbacks from a single ValueAnimator which ran from [0,1], and
clients could implement either the system chrome callbacks or the chip
callbacks.

This change reworks the whole system to instead use the animation
scheduler to collect animators from any relevant clients and play them
all together. It allows for much more granular control over individual
elements that want to participate in the animation.

The tradeoff here is that there is no single place for the animation to
be coordinated from. The entire experince needs to be composed by
orchestrating every animation individually and testing manually to
ensure that the motion is adequate.

Test: manual
Bug: 187881849
Change-Id: I8b2ec28b0489f6ec5870e4e14e5e9fd1bd15e076
parent b6d298a4
Loading
Loading
Loading
Loading
+0 −2
Original line number Diff line number Diff line
@@ -37,7 +37,5 @@
            android:layout_gravity="center"
            android:minWidth="@dimen/ongoing_appops_chip_min_width"
            android:maxWidth="@dimen/ongoing_appops_chip_max_width"
            android:clipChildren="false"
            android:clipToPadding="false"
            />
</com.android.systemui.privacy.OngoingPrivacyChip>
 No newline at end of file
+3 −0
Original line number Diff line number Diff line
@@ -941,6 +941,9 @@
    <!--  Three privacy items. This value must not be exceeded  -->
    <dimen name="ongoing_appops_chip_max_width">76dp</dimen>
    <dimen name="ongoing_appops_dot_diameter">6dp</dimen>
    <dimen name="ongoing_appops_chip_min_animation_width">10dp</dimen>
    <dimen name="ongoing_appops_chip_animation_in_status_bar_translation_x">15dp</dimen>
    <dimen name="ongoing_appops_chip_animation_out_status_bar_translation_x">7dp</dimen>
    <!--  Total minimum padding to enforce to ensure that the dot can always show  -->
    <dimen name="ongoing_appops_dot_min_padding">20dp</dimen>

+192 −84
Original line number Diff line number Diff line
@@ -16,9 +16,12 @@

package com.android.systemui.statusbar.events

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.Point
import android.graphics.Rect
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
@@ -30,6 +33,7 @@ import com.android.systemui.R
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.window.StatusBarWindowController
import javax.inject.Inject
import kotlin.math.roundToInt

/**
 * Controls the view for system event animations.
@@ -38,7 +42,7 @@ class SystemEventChipAnimationController @Inject constructor(
    private val context: Context,
    private val statusBarWindowController: StatusBarWindowController,
    private val contentInsetsProvider: StatusBarContentInsetsProvider
) : SystemStatusChipAnimationCallback {
) : SystemStatusAnimationCallback {

    private lateinit var animationWindowView: FrameLayout

@@ -49,22 +53,24 @@ class SystemEventChipAnimationController @Inject constructor(
    private var chipRight = 0
    private var chipLeft = 0
    private var chipWidth = 0
    private var dotCenter = Point(0, 0)
    private var chipMinWidth = context.resources.getDimensionPixelSize(
            R.dimen.ongoing_appops_chip_min_animation_width)
    private var dotSize = context.resources.getDimensionPixelSize(
            R.dimen.ongoing_appops_dot_diameter)
    // If the chip animates away to a persistent dot, then we modify the CHIP_OUT animation
    private var isAnimatingToDot = false
    // Use during animation so that multiple animators can update the drawing rect
    private var animRect = Rect()

    // TODO: move to dagger
    private var initialized = false

    override fun onChipAnimationStart(
        viewCreator: ViewCreator,
        @SystemAnimationState state: Int
    ) {
        if (!initialized) init()

        if (state == ANIMATING_IN) {
    /**
     * Give the chip controller a chance to inflate and configure the chip view before we start
     * animating
     */
    fun prepareChipAnimation(viewCreator: ViewCreator) {
        if (!initialized) {
            init()
        }
        animationDirection = if (animationWindowView.isLayoutRtl) RIGHT else LEFT

        // Initialize the animated view
@@ -97,43 +103,120 @@ class SystemEventChipAnimationController @Inject constructor(
                chipRight = contentRect.left + chipWidth
            }
        }
    }

            currentAnimatedView?.apply {
                updateAnimatedViewBoundsForAmount(0.1f, this)
    override fun onSystemEventAnimationBegin(): Animator {
        initializeAnimRect()

        val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply {
            startDelay = 117
            duration = 83
            interpolator = null
            addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float }
        }
        val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply {
            startDelay = 117
            duration = 383
            interpolator = STATUS_BAR_X_MOVE_IN
            addUpdateListener {
                updateAnimatedViewBoundsWidth(animatedValue as Int)
            }
        }
        val animSet = AnimatorSet()
        animSet.playTogether(alphaIn, moveIn)
        return animSet
    }

    override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator {
        initializeAnimRect()
        val finish = if (hasPersistentDot) {
            createMoveOutAnimationForDot()
        } else {
            // We are animating away
            currentAnimatedView!!.view.apply {
                alpha = 1f
            createMoveOutAnimationDefault()
        }

        finish.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                animationWindowView.removeView(currentAnimatedView!!.view)
            }
        })

        return finish
    }

    private fun createMoveOutAnimationForDot(): Animator {
        val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
            duration = 150
            interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1
            addUpdateListener {
                updateAnimatedViewBoundsWidth(it.animatedValue as Int)
            }
        }

    override fun onChipAnimationEnd(@SystemAnimationState state: Int) {
        if (state == ANIMATING_IN) {
            // Finished animating in
            currentAnimatedView?.apply {
                updateAnimatedViewBoundsForAmount(1f, this)
        val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply {
            startDelay = 150
            duration = 333
            interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2
            addUpdateListener {
                updateAnimatedViewBoundsWidth(it.animatedValue as Int)
            }
        }

        val keyFrame1Height = dotSize * 2
        val v = currentAnimatedView!!.view
        val chipVerticalCenter = v.top + v.measuredHeight / 2
        val height1 = ValueAnimator.ofInt(
                currentAnimatedView!!.view.measuredHeight, keyFrame1Height).apply {
            startDelay = 133
            duration = 100
            interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1
            addUpdateListener {
                updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
            }
        }

        val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply {
            startDelay = 233
            duration = 250
            interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2
            addUpdateListener {
                updateAnimatedViewBoundsHeight(it.animatedValue as Int, chipVerticalCenter)
            }
        }

        // Move the chip view to overlap exactly with the privacy dot. The chip displays by default
        // exactly adjacent to the dot, so we can just move over by the diameter of the dot itself
        val moveOut = ValueAnimator.ofInt(0, dotSize).apply {
            startDelay = 50
            duration = 183
            interpolator = STATUS_CHIP_MOVE_TO_DOT
            addUpdateListener {
                // If RTL, we can just invert the move
                val amt = if (animationDirection == LEFT) {
                        animatedValue as Int
                } else {
            // Finished animating away
            currentAnimatedView!!.view.apply {
                visibility = View.INVISIBLE
                    -(animatedValue as Int)
                }
                updateAnimatedBoundsX(amt)
            }
            animationWindowView.removeView(currentAnimatedView!!.view)
        }

        val animSet = AnimatorSet()
        animSet.playTogether(width1, width2, height1, height2, moveOut)
        return animSet
    }

    override fun onChipAnimationUpdate(
        animator: ValueAnimator,
        @SystemAnimationState state: Int
    ) {
    private fun createMoveOutAnimationDefault(): Animator {
        val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply {
            duration = 383
            addUpdateListener {
                currentAnimatedView?.apply {
            val amt = (animator.animatedValue as Float).amt()
            view.alpha = (animator.animatedValue as Float)
            updateAnimatedViewBoundsForAmount(amt, this)
                    updateAnimatedViewBoundsWidth(it.animatedValue as Int)
                }
            }
        }
        return moveOut
    }

    private fun init() {
        initialized = true
@@ -144,7 +227,6 @@ class SystemEventChipAnimationController @Inject constructor(
        statusBarWindowController.addViewToWindow(animationWindowView, lp)
        animationWindowView.clipToPadding = false
        animationWindowView.clipChildren = false
        animationWindowView.measureAllChildren = true
    }

    private fun layoutParamsDefault(marginEnd: Int): FrameLayout.LayoutParams =
@@ -153,29 +235,55 @@ class SystemEventChipAnimationController @Inject constructor(
                it.marginEnd = marginEnd
            }

    private fun updateAnimatedViewBoundsForAmount(amt: Float, chip: BackgroundAnimatableView) {
    private fun initializeAnimRect() = animRect.set(
            chipLeft,
            currentAnimatedView!!.view.top,
            chipRight,
            currentAnimatedView!!.view.bottom)

    /**
     * To be called during an animation, sets the width and updates the current animated chip view
     */
    private fun updateAnimatedViewBoundsWidth(width: Int) {
        when (animationDirection) {
            LEFT -> {
                chip.setBoundsForAnimation(
                        (chipRight - (chipWidth * amt)).toInt(),
                        chip.view.top,
                        chipRight,
                        chip.view.bottom)
                animRect.set((chipRight - width), animRect.top, chipRight, animRect.bottom)
            } else /* RIGHT */ -> {
                animRect.set(chipLeft, animRect.top, (chipLeft + width), animRect.bottom)
            }
            else /* RIGHT */ -> {
                chip.setBoundsForAnimation(
                        chipLeft,
                        chip.view.top,
                        (chipLeft + (chipWidth * amt)).toInt(),
                        chip.view.bottom)
        }

        updateCurrentAnimatedView()
    }

    /**
     * To be called during an animation, updates the animation rect and sends the update to the chip
     */
    private fun updateAnimatedViewBoundsHeight(height: Int, verticalCenter: Int) {
        animRect.set(
                animRect.left,
                verticalCenter - (height.toFloat() / 2).roundToInt(),
                animRect.right,
                verticalCenter + (height.toFloat() / 2).roundToInt())

        updateCurrentAnimatedView()
    }

    /**
     * To be called during an animation, updates the animation rect offset and updates the chip
     */
    private fun updateAnimatedBoundsX(translation: Int) {
        currentAnimatedView?.view?.translationX = translation.toFloat()
    }

    private fun start() = if (animationWindowView.isLayoutRtl) right() else left()
    private fun right() = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation().right
    private fun left() = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation().left
    private fun Float.amt() = 0.01f.coerceAtLeast(this)
    /**
     * To be called during an animation. Sets the chip rect to animRect
     */
    private fun updateCurrentAnimatedView() {
        currentAnimatedView?.setBoundsForAnimation(
                animRect.left, animRect.top, animRect.right, animRect.bottom
        )
    }
}

/**
+119 −137
Original line number Diff line number Diff line
@@ -19,14 +19,12 @@ package com.android.systemui.statusbar.events
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ValueAnimator
import android.annotation.IntDef
import android.os.Process
import android.provider.DeviceConfig
import android.util.Log
import android.view.animation.PathInterpolator
import com.android.systemui.Dumpable
import com.android.systemui.animation.Interpolators.STANDARD_ACCELERATE
import com.android.systemui.animation.Interpolators.STANDARD_DECELERATE

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
@@ -38,6 +36,7 @@ import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.time.SystemClock
import java.io.FileDescriptor
import java.io.PrintWriter
import java.lang.IllegalStateException

import javax.inject.Inject

@@ -165,68 +164,90 @@ class SystemStatusAnimationScheduler @Inject constructor(
            return
        }

        // Schedule the animation to start after a debounce period
        cancelExecutionRunnable = executor.executeDelayed({
            cancelExecutionRunnable = null
            animationState = ANIMATING_IN
            statusBarWindowController.setForceStatusBarVisible(true)

            val entranceAnimator = ValueAnimator.ofFloat(1f, 0f)
            entranceAnimator.duration = ENTRANCE_ANIM_LENGTH
            entranceAnimator.addListener(systemAnimatorAdapter)
            entranceAnimator.addUpdateListener(systemUpdateListener)
            entranceAnimator.interpolator = STANDARD_ACCELERATE
        chipAnimationController.prepareChipAnimation(scheduledEvent!!.viewCreator)
        animationState = ANIMATION_QUEUED
        executor.executeDelayed({
            runChipAnimation()
        }, DEBOUNCE_DELAY)
    }

            val chipAnimator = ValueAnimator.ofFloat(0f, 1f)
            chipAnimator.duration = CHIP_ANIM_LENGTH
            chipAnimator.addListener(
                    ChipAnimatorAdapter(RUNNING_CHIP_ANIM, scheduledEvent!!.viewCreator))
            chipAnimator.addUpdateListener(chipUpdateListener)
            chipAnimator.interpolator = STANDARD_DECELERATE
    /**
     * 1. Define a total budget for the chip animation (1500ms)
     * 2. Send out callbacks to listeners so that they can generate animations locally
     * 3. Update the scheduler state so that clients know where we are
     * 4. Maybe: provide scaffolding such as: dot location, margins, etc
     * 5. Maybe: define a maximum animation length and enforce it. Probably only doable if we
     * collect all of the animators and run them together.
     */
    private fun runChipAnimation() {
        statusBarWindowController.setForceStatusBarVisible(true)
        animationState = ANIMATING_IN

            val aSet2 = AnimatorSet()
            aSet2.playSequentially(entranceAnimator, chipAnimator)
            aSet2.start()
        val animSet = collectStartAnimations()
        if (animSet.totalDuration > 500) {
            throw IllegalStateException("System animation total length exceeds budget. " +
                    "Expected: 500, actual: ${animSet.totalDuration}")
        }
        animSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                animationState = RUNNING_CHIP_ANIM
            }
        })
        animSet.start()

        executor.executeDelayed({
            val animSet2 = collectFinishAnimations()
            animationState = ANIMATING_OUT

                val systemAnimator = ValueAnimator.ofFloat(0f, 1f)
                systemAnimator.duration = ENTRANCE_ANIM_LENGTH
                systemAnimator.addListener(systemAnimatorAdapter)
                systemAnimator.addUpdateListener(systemUpdateListener)
                systemAnimator.interpolator = STANDARD_DECELERATE
                systemAnimator.addListener(object : AnimatorListenerAdapter() {
            animSet2.addListener(object : AnimatorListenerAdapter() {
                override fun onAnimationEnd(animation: Animator?) {
                    animationState = if (hasPersistentDot) {
                        SHOWING_PERSISTENT_DOT
                    } else {
                        IDLE
                    }

                    statusBarWindowController.setForceStatusBarVisible(false)
                }
            })
            animSet2.start()
            scheduledEvent = null
        }, DISPLAY_LENGTH)
    }

                val chipAnimator = ValueAnimator.ofFloat(1f, 0f)
                chipAnimator.duration = CHIP_ANIM_LENGTH
                val endState = if (hasPersistentDot) {
                    SHOWING_PERSISTENT_DOT
                } else {
                    IDLE
    private fun collectStartAnimations(): AnimatorSet {
        val animators = mutableListOf<Animator>()
        listeners.forEach { listener ->
            listener.onSystemEventAnimationBegin()?.let { anim ->
                animators.add(anim)
            }
        }
        animators.add(chipAnimationController.onSystemEventAnimationBegin())
        val animSet = AnimatorSet().also {
            it.playTogether(animators)
        }
                chipAnimator.addListener(
                    ChipAnimatorAdapter(endState, scheduledEvent!!.viewCreator))
                chipAnimator.addUpdateListener(chipUpdateListener)
                chipAnimator.interpolator = STANDARD_ACCELERATE

                val aSet2 = AnimatorSet()
        return animSet
    }

                aSet2.play(chipAnimator).before(systemAnimator)
    private fun collectFinishAnimations(): AnimatorSet {
        val animators = mutableListOf<Animator>()
        listeners.forEach { listener ->
            listener.onSystemEventAnimationFinish(hasPersistentDot)?.let { anim ->
                animators.add(anim)
            }
        }
        animators.add(chipAnimationController.onSystemEventAnimationFinish(hasPersistentDot))
        if (hasPersistentDot) {
            val dotAnim = notifyTransitionToPersistentDot()
                    if (dotAnim != null) aSet2.playTogether(systemAnimator, dotAnim)
            if (dotAnim != null) {
                animators.add(dotAnim)
            }
        }
        val animSet = AnimatorSet().also {
            it.playTogether(animators)
        }

                aSet2.start()

                scheduledEvent = null
            }, DISPLAY_LENGTH)
        }, DELAY)
        return animSet
    }

    private fun notifyTransitionToPersistentDot(): Animator? {
@@ -260,18 +281,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
        return null
    }

    private fun notifySystemStart() {
        listeners.forEach { it.onSystemChromeAnimationStart() }
    }

    private fun notifySystemFinish() {
        listeners.forEach { it.onSystemChromeAnimationEnd() }
    }

    private fun notifySystemAnimationUpdate(anim: ValueAnimator) {
        listeners.forEach { it.onSystemChromeAnimationUpdate(anim) }
    }

    override fun addCallback(listener: SystemStatusAnimationCallback) {
        Assert.isMainThread()

@@ -290,24 +299,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
        }
    }

    private val systemUpdateListener = ValueAnimator.AnimatorUpdateListener {
        anim -> notifySystemAnimationUpdate(anim)
    }

    private val systemAnimatorAdapter = object : AnimatorListenerAdapter() {
        override fun onAnimationEnd(p0: Animator?) {
            notifySystemFinish()
        }

        override fun onAnimationStart(p0: Animator?) {
            notifySystemStart()
        }
    }

    private val chipUpdateListener = ValueAnimator.AnimatorUpdateListener {
        anim -> chipAnimationController.onChipAnimationUpdate(anim, animationState)
    }

    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
        pw.println("Scheduled event: $scheduledEvent")
        pw.println("Has persistent privacy dot: $hasPersistentDot")
@@ -321,24 +312,6 @@ class SystemStatusAnimationScheduler @Inject constructor(
            }
        }
    }

    inner class ChipAnimatorAdapter(
        @SystemAnimationState val endState: Int,
        val viewCreator: ViewCreator
    ) : AnimatorListenerAdapter() {
        override fun onAnimationEnd(p0: Animator?) {
            chipAnimationController.onChipAnimationEnd(animationState)
            animationState = if (endState == SHOWING_PERSISTENT_DOT && !hasPersistentDot) {
                IDLE
            } else {
                endState
            }
        }

        override fun onAnimationStart(p0: Animator?) {
            chipAnimationController.onChipAnimationStart(viewCreator, animationState)
        }
    }
}

/**
@@ -347,16 +320,14 @@ class SystemStatusAnimationScheduler @Inject constructor(
 * create space for the chip animation to display. This means hiding the system elements in the
 * status bar and keyguard.
 *
 * TODO: the chip animation really only has one client, we can probably remove it from this
 * interface
 *
 * The value animators themselves are simple animators from 0.0 to 1.0. Listeners can apply any
 * interpolation they choose but realistically these are most likely to be simple alpha transitions
 */
interface SystemStatusAnimationCallback {
    @JvmDefault fun onSystemChromeAnimationUpdate(animator: ValueAnimator) {}
    @JvmDefault fun onSystemChromeAnimationStart() {}
    @JvmDefault fun onSystemChromeAnimationEnd() {}
    /** Implement this method to return an [Animator] or [AnimatorSet] that presents the chip */
    fun onSystemEventAnimationBegin(): Animator? { return null }
    /** Implement this method to return an [Animator] or [AnimatorSet] that hides the chip */
    fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator? { return null }

    // Best method name, change my mind
    @JvmDefault
@@ -366,50 +337,61 @@ interface SystemStatusAnimationCallback {
    @JvmDefault fun onHidePersistentDot(): Animator? { return null }
}

interface SystemStatusChipAnimationCallback {
    fun onChipAnimationUpdate(animator: ValueAnimator, @SystemAnimationState state: Int) {}

    fun onChipAnimationStart(
        viewCreator: ViewCreator,
        @SystemAnimationState state: Int
    ) {}

    fun onChipAnimationEnd(@SystemAnimationState state: Int) {}
}

/**
 * Animation state IntDef
 */
@Retention(AnnotationRetention.SOURCE)
@IntDef(
        value = [
            IDLE, ANIMATING_IN, RUNNING_CHIP_ANIM, ANIMATING_OUT, SHOWING_PERSISTENT_DOT
            IDLE,
            ANIMATION_QUEUED,
            ANIMATING_IN,
            RUNNING_CHIP_ANIM,
            ANIMATING_OUT,
            SHOWING_PERSISTENT_DOT
        ]
)
annotation class SystemAnimationState

/** No animation is in progress */
const val IDLE = 0
/** An animation is queued, and awaiting the debounce period */
const val ANIMATION_QUEUED = 1
/** System is animating out, and chip is animating in */
const val ANIMATING_IN = 1
const val ANIMATING_IN = 2
/** Chip has animated in and is awaiting exit animation, and optionally playing its own animation */
const val RUNNING_CHIP_ANIM = 2
const val RUNNING_CHIP_ANIM = 3
/** Chip is animating away and system is animating back */
const val ANIMATING_OUT = 3
const val ANIMATING_OUT = 4
/** Chip has animated away, and the persistent dot is showing */
const val SHOWING_PERSISTENT_DOT = 4
const val SHOWING_PERSISTENT_DOT = 5

/** Commonly-needed interpolators can go here */
@JvmField val STATUS_BAR_X_MOVE_OUT = PathInterpolator(0.33f, 0f, 0f, 1f)
@JvmField val STATUS_BAR_X_MOVE_IN = PathInterpolator(0f, 0f, 0f, 1f)
/**
 * Status chip animation to dot have multiple stages of motion, the _1 and _2 interpolators should
 * be used in succession
 */
val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1 = PathInterpolator(0.44f, 0f, 0.25f, 1f)
val STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0.26f, 1f)
val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1 = PathInterpolator(0.4f, 0f, 0.17f, 1f)
val STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2 = PathInterpolator(0.3f, 0f, 0f, 1f)
val STATUS_CHIP_MOVE_TO_DOT = PathInterpolator(0f, 0f, 0.05f, 1f)

private const val TAG = "SystemStatusAnimationScheduler"
private const val DELAY = 0L
private const val DEBOUNCE_DELAY = 100L

/**
 * The total time spent animation should be 1500ms. The entrance animation is how much time
 * we give to the system to animate system elements out of the way. Total chip animation length
 * will be equivalent to 2*chip_anim_length + display_length
 * The total time spent on the chip animation is 1500ms, broken up into 3 sections:
 *   - 500ms to animate the chip in (including animating system icons away)
 *   - 500ms holding the chip on screen
 *   - 500ms to animate the chip away (and system icons back)
 *
 *   So DISPLAY_LENGTH should be the sum of the first 2 phases, while the final 500ms accounts for
 *   the actual animation
 */
private const val ENTRANCE_ANIM_LENGTH = 250L
private const val CHIP_ANIM_LENGTH = 250L
// 1s + entrance time + chip anim_length
private const val DISPLAY_LENGTH = 1500L
private const val DISPLAY_LENGTH = 1000L

private const val MIN_UPTIME: Long = 5 * 1000

+1 −23
Original line number Diff line number Diff line
@@ -510,28 +510,6 @@ public class KeyguardStatusBarView extends RelativeLayout {
        }
    }

    void onSystemChromeAnimationStart(boolean isAnimatingOut) {
        if (isAnimatingOut) {
            mSystemIconsContainer.setVisibility(View.VISIBLE);
            mSystemIconsContainer.setAlpha(0f);
        }
    }

    void onSystemChromeAnimationEnd(boolean isAnimatingIn) {
        // Make sure the system icons are out of the way
        if (isAnimatingIn) {
            mSystemIconsContainer.setVisibility(View.INVISIBLE);
            mSystemIconsContainer.setAlpha(0f);
        } else {
            mSystemIconsContainer.setAlpha(1f);
            mSystemIconsContainer.setVisibility(View.VISIBLE);
        }
    }

    void onSystemChromeAnimationUpdate(float animatedValue) {
        mSystemIconsContainer.setAlpha(animatedValue);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
Loading