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

Commit a4d39c22 authored by Jordan Demeulenaere's avatar Jordan Demeulenaere Committed by Android (Google) Code Review
Browse files

Merge changes from topic "qs-animation" into sc-dev

* changes:
  Animate QuickSettings long press (1/2).
  Add generic support for corner radius in launch animations.
  Animate the media activity launch.
parents 6d4e4b84 49bcc0d1
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -63,6 +63,8 @@ public interface ActivityStarter {
    void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade);
    void startActivity(Intent intent, boolean dismissShade, Callback callback);
    void postStartActivityDismissingKeyguard(Intent intent, int delay);
    void postStartActivityDismissingKeyguard(Intent intent, int delay,
            @Nullable ActivityLaunchAnimator.Controller animationController);
    void postStartActivityDismissingKeyguard(PendingIntent intent);

    /**
+2 −2
Original line number Diff line number Diff line
@@ -35,12 +35,12 @@ class ActivityLaunchAnimator {
        private const val ANIMATION_DURATION_NAV_FADE_OUT = 133L
        private const val ANIMATION_DELAY_NAV_FADE_IN =
                ANIMATION_DURATION - ANIMATION_DURATION_NAV_FADE_IN
        private const val LAUNCH_TIMEOUT = 500L
        private const val LAUNCH_TIMEOUT = 1000L

        // TODO(b/184121838): Use android.R.interpolator.fast_out_extra_slow_in instead.
        // TODO(b/184121838): Move com.android.systemui.Interpolators in an animation library we can
        // reuse here.
        private val ANIMATION_INTERPOLATOR = PathInterpolator(0f, 0f, 0.2f, 1f)
        private val ANIMATION_INTERPOLATOR = PathInterpolator(0.4f, 0f, 0.2f, 1f)
        private val LINEAR_INTERPOLATOR = LinearInterpolator()
        private val ALPHA_IN_INTERPOLATOR = PathInterpolator(0.4f, 0f, 1f, 1f)
        private val ALPHA_OUT_INTERPOLATOR = PathInterpolator(0f, 0f, 0.8f, 1f)
+140 −7
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@ import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.LayerDrawable
import android.view.GhostView
import android.view.View
import android.view.ViewGroup
@@ -66,15 +68,28 @@ open class GhostedViewLaunchAnimatorController(
        topCornerRadius: Float,
        bottomCornerRadius: Float
    ) {
        // TODO(b/184121838): Add default support for GradientDrawable and LayerDrawable to make
        // this work out of the box for common rounded backgrounds.
        // By default, we rely on WrappedDrawable to set/restore the background radii before/after
        // each draw.
        backgroundDrawable?.setBackgroundRadius(topCornerRadius, bottomCornerRadius)
    }

    /** Return the current top corner radius of the background. */
    protected open fun getCurrentTopCornerRadius(): Float = 0f
    protected open fun getCurrentTopCornerRadius(): Float {
        val drawable = getBackground() ?: return 0f
        val gradient = findGradientDrawable(drawable) ?: return 0f

        // TODO(b/184121838): Support more than symmetric top & bottom radius.
        return gradient.cornerRadii?.get(CORNER_RADIUS_TOP_INDEX) ?: gradient.cornerRadius
    }

    /** Return the current bottom corner radius of the background. */
    protected open fun getCurrentBottomCornerRadius(): Float = 0f
    protected open fun getCurrentBottomCornerRadius(): Float {
        val drawable = getBackground() ?: return 0f
        val gradient = findGradientDrawable(drawable) ?: return 0f

        // TODO(b/184121838): Support more than symmetric top & bottom radius.
        return gradient.cornerRadii?.get(CORNER_RADIUS_BOTTOM_INDEX) ?: gradient.cornerRadius
    }

    override fun getRootView(): View {
        return rootView
@@ -94,7 +109,7 @@ open class GhostedViewLaunchAnimatorController(

    override fun onLaunchAnimationStart(isExpandingFullyAbove: Boolean) {
        backgroundView = FrameLayout(rootView.context).apply {
            forceHasOverlappingRendering(true)
            forceHasOverlappingRendering(false)
        }
        rootViewOverlay.add(backgroundView)

@@ -143,6 +158,33 @@ open class GhostedViewLaunchAnimatorController(
        ghostedView.invalidate()
    }

    companion object {
        private const val CORNER_RADIUS_TOP_INDEX = 0
        private const val CORNER_RADIUS_BOTTOM_INDEX = 4

        /**
         * Return the first [GradientDrawable] found in [drawable], or null if none is found. If
         * [drawable] is a [LayerDrawable], this will return the first layer that is a
         * [GradientDrawable].
         */
        private fun findGradientDrawable(drawable: Drawable): GradientDrawable? {
            if (drawable is GradientDrawable) {
                return drawable
            }

            if (drawable is LayerDrawable) {
                for (i in 0 until drawable.numberOfLayers) {
                    val maybeGradient = drawable.getDrawable(i)
                    if (maybeGradient is GradientDrawable) {
                        return maybeGradient
                    }
                }
            }

            return null
        }
    }

    private class WrappedDrawable(val wrapped: Drawable?) : Drawable() {
        companion object {
            private val SRC_MODE = PorterDuffXfermode(PorterDuff.Mode.SRC)
@@ -151,6 +193,9 @@ open class GhostedViewLaunchAnimatorController(
        private var currentAlpha = 0xFF
        private var previousBounds = Rect()

        private var cornerRadii = FloatArray(8) { -1f }
        private var previousCornerRadii = FloatArray(8)

        override fun draw(canvas: Canvas) {
            val wrapped = this.wrapped ?: return

@@ -158,7 +203,8 @@ open class GhostedViewLaunchAnimatorController(

            wrapped.alpha = currentAlpha
            wrapped.bounds = bounds
            wrapped.setXfermode(SRC_MODE)
            setXfermode(wrapped, SRC_MODE)
            applyBackgroundRadii()

            wrapped.draw(canvas)

@@ -167,7 +213,8 @@ open class GhostedViewLaunchAnimatorController(
            // background.
            wrapped.alpha = 0
            wrapped.bounds = previousBounds
            wrapped.setXfermode(null)
            setXfermode(wrapped, null)
            restoreBackgroundRadii()
        }

        override fun setAlpha(alpha: Int) {
@@ -192,5 +239,91 @@ open class GhostedViewLaunchAnimatorController(
        override fun setColorFilter(filter: ColorFilter?) {
            wrapped?.colorFilter = filter
        }

        private fun setXfermode(background: Drawable, mode: PorterDuffXfermode?) {
            if (background !is LayerDrawable) {
                background.setXfermode(mode)
                return
            }

            // We set the xfermode on the first layer that is not a mask. Most of the time it will
            // be the "background layer".
            for (i in 0 until background.numberOfLayers) {
                if (background.getId(i) != android.R.id.mask) {
                    background.getDrawable(i).setXfermode(mode)
                    break
                }
            }
        }

        fun setBackgroundRadius(topCornerRadius: Float, bottomCornerRadius: Float) {
            updateRadii(cornerRadii, topCornerRadius, bottomCornerRadius)
            invalidateSelf()
        }

        private fun updateRadii(
            radii: FloatArray,
            topCornerRadius: Float,
            bottomCornerRadius: Float
        ) {
            radii[0] = topCornerRadius
            radii[1] = topCornerRadius
            radii[2] = topCornerRadius
            radii[3] = topCornerRadius

            radii[4] = bottomCornerRadius
            radii[5] = bottomCornerRadius
            radii[6] = bottomCornerRadius
            radii[7] = bottomCornerRadius
        }

        private fun applyBackgroundRadii() {
            if (cornerRadii[0] < 0 || wrapped == null) {
                return
            }

            savePreviousBackgroundRadii(wrapped)
            applyBackgroundRadii(wrapped, cornerRadii)
        }

        private fun savePreviousBackgroundRadii(background: Drawable) {
            // TODO(b/184121838): This method assumes that all GradientDrawable in background will
            // have the same radius. Should we save/restore the radii for each layer instead?
            val gradient = findGradientDrawable(background) ?: return

            // TODO(b/184121838): GradientDrawable#getCornerRadii clones its radii array. Should we
            // try to avoid that?
            val radii = gradient.cornerRadii
            if (radii != null) {
                radii.copyInto(previousCornerRadii)
            } else {
                // Copy the cornerRadius into previousCornerRadii.
                val radius = gradient.cornerRadius
                updateRadii(previousCornerRadii, radius, radius)
            }
        }

        private fun applyBackgroundRadii(drawable: Drawable, radii: FloatArray) {
            if (drawable is GradientDrawable) {
                drawable.cornerRadii = radii
                return
            }

            if (drawable !is LayerDrawable) {
                return
            }

            for (i in 0 until drawable.numberOfLayers) {
                (drawable.getDrawable(i) as? GradientDrawable)?.cornerRadii = radii
            }
        }

        private fun restoreBackgroundRadii() {
            if (cornerRadii[0] < 0 || wrapped == null) {
                return
            }

            applyBackgroundRadii(wrapped, previousCornerRadii)
        }
    }
}
+10 −2
Original line number Diff line number Diff line
@@ -15,10 +15,12 @@
package com.android.systemui.plugins.qs;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.metrics.LogMaker;
import android.service.quicksettings.Tile;
import android.view.View;

import com.android.internal.logging.InstanceId;
import com.android.systemui.plugins.annotations.DependsOn;
@@ -56,7 +58,13 @@ public interface QSTile {

    void click();
    void secondaryClick();
    void longClick();

    /**
     * The tile was long clicked.
     *
     * @param view The view that was clicked.
     */
    void longClick(@Nullable View view);

    void userSwitch(int currentUser);
    int getMetricsCategory();
+10 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ import android.app.PendingIntent;
import android.content.Intent;
import android.view.View;

import androidx.annotation.Nullable;

import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.animation.ActivityLaunchAnimator;
@@ -106,6 +108,14 @@ public class ActivityStarterDelegate implements ActivityStarter {
                starter -> starter.get().postStartActivityDismissingKeyguard(intent, delay));
    }

    @Override
    public void postStartActivityDismissingKeyguard(Intent intent, int delay,
            @Nullable ActivityLaunchAnimator.Controller animationController) {
        mActualStarter.ifPresent(
                starter -> starter.get().postStartActivityDismissingKeyguard(intent, delay,
                        animationController));
    }

    @Override
    public void postStartActivityDismissingKeyguard(PendingIntent intent) {
        mActualStarter.ifPresent(
Loading