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

Commit 4e2a53cd authored by George Mount's avatar George Mount Committed by Android (Google) Code Review
Browse files

Merge "Update the EdgeEffect API" into sc-dev

parents d0c396e6 0901fc33
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -53591,16 +53591,19 @@ package android.widget {
  public class EdgeEffect {
    ctor public EdgeEffect(android.content.Context);
    ctor public EdgeEffect(@NonNull android.content.Context, @Nullable android.util.AttributeSet);
    method public boolean draw(android.graphics.Canvas);
    method public void finish();
    method @Nullable public android.graphics.BlendMode getBlendMode();
    method @ColorInt public int getColor();
    method public float getDistance();
    method public int getMaxHeight();
    method public int getType();
    method public boolean isFinished();
    method public void onAbsorb(int);
    method public void onPull(float);
    method public void onPull(float, float);
    method public float onPullDistance(float, float);
    method public void onRelease();
    method public void setBlendMode(@Nullable android.graphics.BlendMode);
    method public void setColor(@ColorInt int);
+93 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.widget;

import android.annotation.ColorInt;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -27,6 +28,7 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -111,11 +113,14 @@ public class EdgeEffect {
    private float mGlowAlpha;
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private float mGlowScaleY;
    private float mDistance;

    private float mGlowAlphaStart;
    private float mGlowAlphaFinish;
    private float mGlowScaleYStart;
    private float mGlowScaleYFinish;
    private float mDistanceStart;
    private float mDistanceFinish;

    private long mStartTime;
    private float mDuration;
@@ -150,9 +155,18 @@ public class EdgeEffect {
     * @param context Context used to provide theming and resource information for the EdgeEffect
     */
    public EdgeEffect(Context context) {
        this(context, null);
    }

    /**
     * Construct a new EdgeEffect with a theme appropriate for the provided context.
     * @param context Context used to provide theming and resource information for the EdgeEffect
     * @param attrs The attributes of the XML tag that is inflating the view
     */
    public EdgeEffect(@NonNull Context context, @Nullable AttributeSet attrs) {
        mPaint.setAntiAlias(true);
        final TypedArray a = context.obtainStyledAttributes(
                com.android.internal.R.styleable.EdgeEffect);
                attrs, com.android.internal.R.styleable.EdgeEffect);
        final int themeColor = a.getColor(
                com.android.internal.R.styleable.EdgeEffect_colorEdgeEffect, 0xff666666);
        mEdgeEffectType = a.getInt(
@@ -248,6 +262,7 @@ public class EdgeEffect {
        mDuration = PULL_TIME;

        mPullDistance += deltaDistance;
        mDistanceStart = mDistanceFinish = mDistance = Math.max(0f, mPullDistance);

        final float absdd = Math.abs(deltaDistance);
        mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA,
@@ -266,6 +281,56 @@ public class EdgeEffect {
        mGlowScaleYFinish = mGlowScaleY;
    }

    /**
     * A view should call this when content is pulled away from an edge by the user.
     * This will update the state of the current visual effect and its associated animation.
     * The host view should always {@link android.view.View#invalidate()} after this
     * and draw the results accordingly. This works similarly to {@link #onPull(float, float)},
     * but returns the amount of <code>deltaDistance</code> that has been consumed. If the
     * {@link #getDistance()} is currently 0 and <code>deltaDistance</code> is negative, this
     * function will return 0 and the drawn value will remain unchanged.
     *
     * This method can be used to reverse the effect from a pull or absorb and partially consume
     * some of a motion:
     *
     * <pre class="prettyprint">
     *     if (deltaY < 0) {
     *         float consumed = edgeEffect.onPullDistance(deltaY / getHeight(), x / getWidth());
     *         deltaY -= consumed * getHeight();
     *         if (edgeEffect.getDistance() == 0f) edgeEffect.onRelease();
     *     }
     * </pre>
     *
     * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to
     *                      1.f (full length of the view) or negative values to express change
     *                      back toward the edge reached to initiate the effect.
     * @param displacement The displacement from the starting side of the effect of the point
     *                     initiating the pull. In the case of touch this is the finger position.
     *                     Values may be from 0-1.
     * @return The amount of <code>deltaDistance</code> that was consumed, a number between
     * 0 and <code>deltaDistance</code>.
     */
    public float onPullDistance(float deltaDistance, float displacement) {
        float finalDistance = Math.max(0f, deltaDistance + mDistance);
        float delta = finalDistance - mDistance;
        onPull(delta, displacement);
        return delta;
    }

    /**
     * Returns the pull distance needed to be released to remove the showing effect.
     * It is determined by the {@link #onPull(float, float)} <code>deltaDistance</code> and
     * any animating values, including from {@link #onAbsorb(int)} and {@link #onRelease()}.
     *
     * This can be used in conjunction with {@link #onPullDistance(float, float)} to
     * release the currently showing effect.
     *
     * @return The pull distance that must be released to remove the showing effect.
     */
    public float getDistance() {
        return mDistance;
    }

    /**
     * Call when the object is released after being pulled.
     * This will begin the "decay" phase of the effect. After calling this method
@@ -282,9 +347,11 @@ public class EdgeEffect {
        mState = STATE_RECEDE;
        mGlowAlphaStart = mGlowAlpha;
        mGlowScaleYStart = mGlowScaleY;
        mDistanceStart = mDistance;

        mGlowAlphaFinish = 0.f;
        mGlowScaleYFinish = 0.f;
        mDistanceFinish = 0.f;

        mStartTime = AnimationUtils.currentAnimationTimeMillis();
        mDuration = RECEDE_TIME;
@@ -311,7 +378,7 @@ public class EdgeEffect {
        // nearly invisible.
        mGlowAlphaStart = GLOW_ALPHA_START;
        mGlowScaleYStart = Math.max(mGlowScaleY, 0.f);

        mDistanceStart = mDistance;

        // Growth for the size of the glow should be quadratic to properly
        // respond
@@ -322,6 +389,9 @@ public class EdgeEffect {
        mGlowAlphaFinish = Math.max(
                mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA));
        mTargetDisplacement = 0.5f;

        // Use glow values to estimate the absorption for stretch distance.
        mDistanceFinish = calculateDistanceFromGlowValues(mGlowScaleYFinish, mGlowAlphaFinish);
    }

    /**
@@ -447,6 +517,7 @@ public class EdgeEffect {

        mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp;
        mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp;
        mDistance = mDistanceStart + (mDistanceFinish - mDistanceStart) * interp;
        mDisplacement = (mDisplacement + mTargetDisplacement) / 2;

        if (t >= 1.f - EPSILON) {
@@ -458,10 +529,12 @@ public class EdgeEffect {

                    mGlowAlphaStart = mGlowAlpha;
                    mGlowScaleYStart = mGlowScaleY;
                    mDistanceStart = mDistance;

                    // After absorb, the glow should fade to nothing.
                    mGlowAlphaFinish = 0.f;
                    mGlowScaleYFinish = 0.f;
                    mDistanceFinish = 0.f;
                    break;
                case STATE_PULL:
                    mState = STATE_PULL_DECAY;
@@ -470,10 +543,12 @@ public class EdgeEffect {

                    mGlowAlphaStart = mGlowAlpha;
                    mGlowScaleYStart = mGlowScaleY;
                    mDistanceStart = mDistance;

                    // After pull, the glow should fade to nothing.
                    mGlowAlphaFinish = 0.f;
                    mGlowScaleYFinish = 0.f;
                    mDistanceFinish = 0.f;
                    break;
                case STATE_PULL_DECAY:
                    mState = STATE_RECEDE;
@@ -484,4 +559,20 @@ public class EdgeEffect {
            }
        }
    }

    /**
     * @return The estimated pull distance as calculated from mGlowScaleY.
     */
    private float calculateDistanceFromGlowValues(float scale, float alpha) {
        if (scale >= 1f) {
            // It should asymptotically approach 1, but not reach there.
            // Here, we're just choosing a value that is large.
            return 1f;
        }
        if (scale > 0f) {
            float v = 1f / 0.7f / (mGlowScaleY - 1f);
            return v * v / mBounds.height();
        }
        return alpha / PULL_DISTANCE_ALPHA_GLOW_FACTOR;
    }
}