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

Commit 3df592e5 authored by Selim Cinek's avatar Selim Cinek
Browse files

When animating between states, animate the view width

Test: add media notification observe no flickery animation
Bug: 154137987
Change-Id: I909dd4427813b34426cc7d7fc08f298761f134bc
parent 9e517f73
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@
    android:scrollbars="none"
    android:clipChildren="false"
    android:clipToPadding="false"
    android:fillViewport="true"
    >
    <LinearLayout
        android:id="@+id/media_carousel"
+9 −2
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@drawable/qs_media_background"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintEnd_toEndOf="@id/view_width"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
@@ -175,7 +175,14 @@
    <include
        layout="@layout/qs_media_panel_options"
        android:visibility="gone"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintEnd_toEndOf="@id/view_width"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/view_width"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="300dp" />
</androidx.constraintlayout.motion.widget.MotionLayout>
+20 −0
Original line number Diff line number Diff line
@@ -70,6 +70,26 @@
    <item type="id" name="panel_alpha_animator_end_tag"/>
    <item type="id" name="cross_fade_layer_type_changed_tag"/>

    <item type="id" name="absolute_x_animator_tag"/>
    <item type="id" name="absolute_x_animator_start_tag"/>
    <item type="id" name="absolute_x_animator_end_tag"/>
    <item type="id" name="absolute_x_current_value"/>

    <item type="id" name="absolute_y_animator_tag"/>
    <item type="id" name="absolute_y_animator_start_tag"/>
    <item type="id" name="absolute_y_animator_end_tag"/>
    <item type="id" name="absolute_y_current_value"/>

    <item type="id" name="view_height_animator_tag"/>
    <item type="id" name="view_height_animator_start_tag"/>
    <item type="id" name="view_height_animator_end_tag"/>
    <item type="id" name="view_height_current_value"/>

    <item type="id" name="view_width_animator_tag"/>
    <item type="id" name="view_width_animator_start_tag"/>
    <item type="id" name="view_width_animator_end_tag"/>
    <item type="id" name="view_width_current_value"/>

    <!-- Whether the icon is from a notification for which targetSdk < L -->
    <item type="id" name="icon_is_pre_L"/>

+10 −10
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@
            android:id="@+id/media_seamless"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintWidth_min="60dp"
            android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
@@ -172,7 +172,7 @@
            android:layout_marginStart="16dp"
            app:layout_constraintTop_toBottomOf="@+id/app_name"
            app:layout_constraintStart_toEndOf="@id/album_art"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
            app:layout_constraintHorizontal_bias="0"/>

        <!-- Artist name -->
@@ -184,7 +184,7 @@
            android:layout_marginTop="3dp"
            app:layout_constraintTop_toBottomOf="@id/header_title"
            app:layout_constraintStart_toStartOf="@id/header_title"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
            app:layout_constraintHorizontal_bias="0"/>

        <!-- Seek Bar -->
@@ -195,7 +195,7 @@
            android:layout_marginTop="3dp"
            app:layout_constraintTop_toBottomOf="@id/header_artist"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
            />

        <Constraint
@@ -207,7 +207,7 @@
            android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
            app:layout_constraintTop_toBottomOf="@id/header_artist"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
            />

        <Constraint
@@ -272,7 +272,7 @@
            android:layout_marginEnd="4dp"
            android:layout_marginBottom="@dimen/qs_media_panel_outer_padding"
            app:layout_constraintLeft_toRightOf="@id/action3"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintRight_toRightOf="@id/view_width"
            app:layout_constraintTop_toTopOf="@id/action0"
            app:layout_constraintBottom_toBottomOf="parent">
        </Constraint>
@@ -306,7 +306,7 @@
            android:id="@+id/media_seamless"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintWidth_min="60dp"
            android:layout_marginTop="@dimen/qs_media_panel_outer_padding"
@@ -358,7 +358,7 @@
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@id/album_art"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
            android:visibility="gone"
            />

@@ -371,7 +371,7 @@
            android:layout_marginStart="@dimen/qs_media_panel_outer_padding"
            app:layout_constraintTop_toBottomOf="@id/album_art"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintEnd_toEndOf="@id/view_width"
            android:visibility="gone"
            />

@@ -438,7 +438,7 @@
            android:layout_marginTop="18dp"
            app:layout_constraintTop_toBottomOf="@id/app_name"
            app:layout_constraintLeft_toRightOf="@id/action3"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintRight_toRightOf="@id/view_width"
            >
        </Constraint>
    </ConstraintSet>
+115 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.media

import android.graphics.Rect
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import com.android.systemui.statusbar.notification.AnimatableProperty
import com.android.systemui.statusbar.notification.PropertyAnimator
import com.android.systemui.statusbar.notification.stack.AnimationProperties

/**
 * A utility class that helps with animations of bound changes designed for motionlayout which
 * doesn't work together with regular changeBounds.
 */
class LayoutAnimationHelper {

    private val layout: ViewGroup
    private var sizeAnimationPending = false
    private val desiredBounds = mutableMapOf<View, Rect>()
    private val animationProperties = AnimationProperties()
    private val layoutListener = object : View.OnLayoutChangeListener {
        override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int,
                                    oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) {
            v?.let {
                if (v.alpha == 0.0f || v.visibility == View.GONE || oldLeft - oldRight == 0 ||
                        oldTop - oldBottom == 0) {
                    return
                }
                if (oldLeft != left || oldTop != top || oldBottom != bottom || oldRight != right) {
                    val rect = desiredBounds.getOrPut(v, { Rect() })
                    rect.set(left, top, right, bottom)
                    onDesiredLocationChanged(v, rect)
                }
            }
        }
    }

    constructor(layout: ViewGroup) {
        this.layout = layout
        val childCount = this.layout.childCount
        for (i in 0 until childCount) {
            val child = this.layout.getChildAt(i)
            child.addOnLayoutChangeListener(layoutListener)
        }
    }

    private fun onDesiredLocationChanged(v: View, rect: Rect) {
        if (!sizeAnimationPending) {
            applyBounds(v, rect, animate = false)
        }
        // We need to reapply the current bounds in every frame since the layout may override
        // the layout bounds making this view jump and not all calls to apply bounds actually
        // reapply them, for example if there's already an animator to the same target
        reapplyProperty(v, AnimatableProperty.ABSOLUTE_X);
        reapplyProperty(v, AnimatableProperty.ABSOLUTE_Y);
        reapplyProperty(v, AnimatableProperty.WIDTH);
        reapplyProperty(v, AnimatableProperty.HEIGHT);
    }

    private fun reapplyProperty(v: View, property: AnimatableProperty) {
        property.property.set(v, property.property.get(v))
    }

    private fun applyBounds(v: View, newBounds: Rect, animate: Boolean) {
        PropertyAnimator.setProperty(v, AnimatableProperty.ABSOLUTE_X, newBounds.left.toFloat(),
                animationProperties, animate)
        PropertyAnimator.setProperty(v, AnimatableProperty.ABSOLUTE_Y, newBounds.top.toFloat(),
                animationProperties, animate)
        PropertyAnimator.setProperty(v, AnimatableProperty.WIDTH, newBounds.width().toFloat(),
                animationProperties, animate)
        PropertyAnimator.setProperty(v, AnimatableProperty.HEIGHT, newBounds.height().toFloat(),
                animationProperties, animate)
    }

    private fun startBoundAnimation(v: View) {
        val target = desiredBounds[v] ?: return
        applyBounds(v, target, animate = true)
    }

    fun animatePendingSizeChange(duration: Long, delay: Long) {
        animationProperties.duration = duration
        animationProperties.delay = delay
        if (!sizeAnimationPending) {
            sizeAnimationPending = true
            layout.viewTreeObserver.addOnPreDrawListener (
                    object : ViewTreeObserver.OnPreDrawListener {
                        override fun onPreDraw(): Boolean {
                            layout.viewTreeObserver.removeOnPreDrawListener(this)
                            sizeAnimationPending = false
                            val childCount = layout.childCount
                            for (i in 0 until childCount) {
                                val child = layout.getChildAt(i)
                                startBoundAnimation(child)
                            }
                            return true
                        }
                    })
        }
    }
}
 No newline at end of file
Loading