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

Commit 9477229f authored by Alan Viverette's avatar Alan Viverette Committed by Android (Google) Code Review
Browse files

Merge "Smooth progress bar animations"

parents 7d92c474 a64ed3bf
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -40972,6 +40972,7 @@ package android.widget {
    method public void setInterpolator(android.view.animation.Interpolator);
    method public synchronized void setMax(int);
    method public synchronized void setProgress(int);
    method public void setProgress(int, boolean);
    method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
    method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
    method public void setProgressDrawable(android.graphics.drawable.Drawable);
+1 −0
Original line number Diff line number Diff line
@@ -43580,6 +43580,7 @@ package android.widget {
    method public void setInterpolator(android.view.animation.Interpolator);
    method public synchronized void setMax(int);
    method public synchronized void setProgress(int);
    method public void setProgress(int, boolean);
    method public void setProgressBackgroundTintList(android.content.res.ColorStateList);
    method public void setProgressBackgroundTintMode(android.graphics.PorterDuff.Mode);
    method public void setProgressDrawable(android.graphics.drawable.Drawable);
+14 −13
Original line number Diff line number Diff line
@@ -385,9 +385,10 @@ public abstract class AbsSeekBar extends ProgressBar {
    }

    @Override
    void onProgressRefresh(float scale, boolean fromUser, int progress) {
        super.onProgressRefresh(scale, fromUser, progress);
    void onVisualProgressChanged(int id, float scale) {
        super.onVisualProgressChanged(id, scale);

        if (id == R.id.progress) {
            final Drawable thumb = mThumb;
            if (thumb != null) {
                setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
@@ -398,6 +399,7 @@ public abstract class AbsSeekBar extends ProgressBar {
                invalidate();
            }
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
@@ -709,8 +711,7 @@ public abstract class AbsSeekBar extends ProgressBar {
                case KeyEvent.KEYCODE_DPAD_RIGHT:
                    increment = isLayoutRtl() ? -increment : increment;

                    // Let progress bar handle clamping values.
                    if (setProgress(getProgress() + increment, true)) {
                    if (setProgressInternal(getProgress() + increment, true, true)) {
                        onKeyChange();
                        return true;
                    }
@@ -764,7 +765,7 @@ public abstract class AbsSeekBar extends ProgressBar {
                }
                float value = arguments.getFloat(
                        AccessibilityNodeInfo.ACTION_ARGUMENT_PROGRESS_VALUE);
                return setProgress((int) value, true);
                return setProgressInternal((int) value, true, true);
            }
            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD:
            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
@@ -777,7 +778,7 @@ public abstract class AbsSeekBar extends ProgressBar {
                }

                // Let progress bar handle clamping values.
                if (setProgress(getProgress() + increment, true)) {
                if (setProgressInternal(getProgress() + increment, true, true)) {
                    onKeyChange();
                    return true;
                }
+114 −34
Original line number Diff line number Diff line
@@ -16,10 +16,13 @@

package android.widget;

import android.animation.ObjectAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.PorterDuff;

import android.util.FloatProperty;
import android.util.IntProperty;
import android.view.accessibility.AccessibilityNodeInfo;
import com.android.internal.R;

@@ -28,7 +31,6 @@ import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Shader;
@@ -38,7 +40,6 @@ import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ClipDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.graphics.drawable.shapes.Shape;
@@ -57,6 +58,7 @@ import android.view.accessibility.AccessibilityManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
@@ -198,9 +200,17 @@ import java.util.ArrayList;
 */
@RemoteView
public class ProgressBar extends View {

    private static final int MAX_LEVEL = 10000;
    private static final int TIMEOUT_SEND_ACCESSIBILITY_EVENT = 200;

    /** Interpolator used for smooth progress animations. */
    private static final DecelerateInterpolator PROGRESS_ANIM_INTERPOLATOR =
            new DecelerateInterpolator();

    /** Duration of smooth progress animations. */
    private static final int PROGRESS_ANIM_DURATION = 80;

    int mMinWidth;
    int mMaxWidth;
    int mMinHeight;
@@ -234,6 +244,9 @@ public class ProgressBar extends View {
    private boolean mAttached;
    private boolean mRefreshIsPosted;

    /** Value used to track progress animation, in the range [0...1]. */
    private float mVisualProgress;

    boolean mMirrorForRtl = false;

    private final ArrayList<RefreshData> mRefreshData = new ArrayList<RefreshData>();
@@ -814,8 +827,8 @@ public class ProgressBar extends View {
            updateDrawableBounds(getWidth(), getHeight());
            updateDrawableState();

            doRefreshProgress(R.id.progress, mProgress, false, false);
            doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
            doRefreshProgress(R.id.progress, mProgress, false, false, false);
            doRefreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false, false);
        }
    }

@@ -1246,7 +1259,7 @@ public class ProgressBar extends View {
                final int count = mRefreshData.size();
                for (int i = 0; i < count; i++) {
                    final RefreshData rd = mRefreshData.get(i);
                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate);
                    rd.recycle();
                }
                mRefreshData.clear();
@@ -1263,8 +1276,9 @@ public class ProgressBar extends View {
        public int id;
        public int progress;
        public boolean fromUser;
        public boolean animate;

        public static RefreshData obtain(int id, int progress, boolean fromUser) {
        public static RefreshData obtain(int id, int progress, boolean fromUser, boolean animate) {
            RefreshData rd = sPool.acquire();
            if (rd == null) {
                rd = new RefreshData();
@@ -1272,6 +1286,7 @@ public class ProgressBar extends View {
            rd.id = id;
            rd.progress = progress;
            rd.fromUser = fromUser;
            rd.animate = animate;
            return rd;
        }

@@ -1281,26 +1296,21 @@ public class ProgressBar extends View {
    }

    private synchronized void doRefreshProgress(int id, int progress, boolean fromUser,
            boolean callBackToApp) {
        float scale = mMax > 0 ? (float) progress / (float) mMax : 0;
        final Drawable d = mCurrentDrawable;
        if (d != null) {
            Drawable progressDrawable = null;

            if (d instanceof LayerDrawable) {
                progressDrawable = ((LayerDrawable) d).findDrawableByLayerId(id);
                if (progressDrawable != null && canResolveLayoutDirection()) {
                    progressDrawable.setLayoutDirection(getLayoutDirection());
                }
            }

            final int level = (int) (scale * MAX_LEVEL);
            (progressDrawable != null ? progressDrawable : d).setLevel(level);
            boolean callBackToApp, boolean animate) {
        final float scale = mMax > 0 ? progress / (float) mMax : 0;
        final boolean isPrimary = id == R.id.progress;

        if (isPrimary && animate) {
            final ObjectAnimator animator = ObjectAnimator.ofFloat(this, VISUAL_PROGRESS, scale);
            animator.setAutoCancel(true);
            animator.setDuration(PROGRESS_ANIM_DURATION);
            animator.setInterpolator(PROGRESS_ANIM_INTERPOLATOR);
            animator.start();
        } else {
            invalidate();
            setVisualProgress(id, scale);
        }

        if (callBackToApp && id == R.id.progress) {
        if (isPrimary && callBackToApp) {
            onProgressRefresh(scale, fromUser, progress);
        }
    }
@@ -1311,15 +1321,51 @@ public class ProgressBar extends View {
        }
    }

    private synchronized void refreshProgress(int id, int progress, boolean fromUser) {
    /**
     * Sets the visual state of a progress indicator.
     *
     * @param id the identifier of the progress indicator
     * @param progress the visual progress in the range [0...1]
     */
    private void setVisualProgress(int id, float progress) {
        mVisualProgress = progress;

        Drawable d = mCurrentDrawable;

        if (d instanceof LayerDrawable) {
            d = ((LayerDrawable) d).findDrawableByLayerId(id);
        }

        if (d != null) {
            final int level = (int) (progress * MAX_LEVEL);
            d.setLevel(level);
        } else {
            invalidate();
        }

        onVisualProgressChanged(id, progress);
    }

    /**
     * Called when the visual state of a progress indicator changes.
     *
     * @param id the identifier of the progress indicator
     * @param progress the visual progress in the range [0...1]
     */
    void onVisualProgressChanged(int id, float progress) {
        // Stub method.
    }

    private synchronized void refreshProgress(int id, int progress, boolean fromUser,
            boolean animate) {
        if (mUiThreadId == Thread.currentThread().getId()) {
            doRefreshProgress(id, progress, fromUser, true);
            doRefreshProgress(id, progress, fromUser, true, animate);
        } else {
            if (mRefreshProgressRunnable == null) {
                mRefreshProgressRunnable = new RefreshProgressRunnable();
            }

            final RefreshData rd = RefreshData.obtain(id, progress, fromUser);
            final RefreshData rd = RefreshData.obtain(id, progress, fromUser, animate);
            mRefreshData.add(rd);
            if (mAttached && !mRefreshIsPosted) {
                post(mRefreshProgressRunnable);
@@ -1329,8 +1375,8 @@ public class ProgressBar extends View {
    }

    /**
     * <p>Set the current progress to the specified value. Does not do anything
     * if the progress bar is in indeterminate mode.</p>
     * Sets the current progress to the specified value. Does not do anything
     * if the progress bar is in indeterminate mode.
     *
     * @param progress the new progress, between 0 and {@link #getMax()}
     *
@@ -1341,11 +1387,26 @@ public class ProgressBar extends View {
     */
    @android.view.RemotableViewMethod
    public synchronized void setProgress(int progress) {
        setProgress(progress, false);
        setProgressInternal(progress, false, false);
    }

    /**
     * Sets the current progress to the specified value, optionally animating
     * between the current and target values.
     * <p>
     * Animation does not affect the result of {@link #getProgress()}, which
     * will return the target value immediately after this method is called.
     *
     * @param progress the new progress value, between 0 and {@link #getMax()}
     * @param animate {@code true} to animate between the current and target
     *                values or {@code false} to not animate
     */
    public void setProgress(int progress, boolean animate) {
        setProgressInternal(progress, false, animate);
    }

    @android.view.RemotableViewMethod
    synchronized boolean setProgress(int progress, boolean fromUser) {
    synchronized boolean setProgressInternal(int progress, boolean fromUser, boolean animate) {
        if (mIndeterminate) {
            // Not applicable.
            return false;
@@ -1359,7 +1420,7 @@ public class ProgressBar extends View {
        }

        mProgress = progress;
        refreshProgress(R.id.progress, mProgress, fromUser);
        refreshProgress(R.id.progress, mProgress, fromUser, animate);
        return true;
    }

@@ -1391,7 +1452,7 @@ public class ProgressBar extends View {

        if (secondaryProgress != mSecondaryProgress) {
            mSecondaryProgress = secondaryProgress;
            refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false);
            refreshProgress(R.id.secondaryProgress, mSecondaryProgress, false, false);
        }
    }

@@ -1464,7 +1525,7 @@ public class ProgressBar extends View {
            if (mProgress > max) {
                mProgress = max;
            }
            refreshProgress(R.id.progress, mProgress, false);
            refreshProgress(R.id.progress, mProgress, false, false);
        }
    }

@@ -1847,7 +1908,7 @@ public class ProgressBar extends View {
                final int count = mRefreshData.size();
                for (int i = 0; i < count; i++) {
                    final RefreshData rd = mRefreshData.get(i);
                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true);
                    doRefreshProgress(rd.id, rd.progress, rd.fromUser, true, rd.animate);
                    rd.recycle();
                }
                mRefreshData.clear();
@@ -1956,4 +2017,23 @@ public class ProgressBar extends View {
        boolean mHasSecondaryProgressTint;
        boolean mHasSecondaryProgressTintMode;
    }

    /**
     * Property wrapper around the visual state of the {@code progress} functionality
     * handled by the {@link ProgressBar#setProgress(int, boolean)} method. This does
     * not correspond directly to the actual progress -- only the visual state.
     */
    private final FloatProperty<ProgressBar> VISUAL_PROGRESS =
            new FloatProperty<ProgressBar>("visual_progress") {
                @Override
                public void setValue(ProgressBar object, float value) {
                    object.setVisualProgress(R.id.progress, value);
                    object.mVisualProgress = value;
                }

                @Override
                public Float get(ProgressBar object) {
                    return object.mVisualProgress;
                }
            };
}
+10 −49
Original line number Diff line number Diff line
@@ -89,7 +89,6 @@ public class VolumeDialog {

    private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
    private static final int WAIT_FOR_RIPPLE = 200;
    private static final int UPDATE_ANIMATION_DURATION = 80;

    private final Context mContext;
    private final H mHandler = new H();
@@ -353,14 +352,6 @@ public class VolumeDialog {
        writer.println(mAccessibility.mFeedbackEnabled);
    }

    private static int getImpliedLevel(SeekBar seekBar, int progress) {
        final int m = seekBar.getMax();
        final int n = m / 100 - 1;
        final int level = progress == 0 ? 0
                : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
        return level;
    }

    @SuppressLint("InflateParams")
    private VolumeRow initRow(final int stream, int iconRes, int iconMuteRes, boolean important) {
        final VolumeRow row = new VolumeRow();
@@ -690,7 +681,7 @@ public class VolumeDialog {
                : false;

        // update slider max
        final int max = ss.levelMax * 100;
        final int max = ss.levelMax;
        if (max != row.slider.getMax()) {
            row.slider.setMax(max);
        }
@@ -777,8 +768,7 @@ public class VolumeDialog {
        if (row.tracking) {
            return;  // don't update if user is sliding
        }
        final int progress = row.slider.getProgress();
        final int level = getImpliedLevel(row.slider, progress);
        final int level = row.slider.getProgress();
        final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
        final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
                < USER_ATTEMPT_GRACE_PERIOD;
@@ -794,33 +784,7 @@ public class VolumeDialog {
                return;  // don't clamp if visible
            }
        }
        final int newProgress = vlevel * 100;
        if (progress != newProgress) {
            if (mShowing && rowVisible) {
                // animate!
                if (row.anim != null && row.anim.isRunning()
                        && row.animTargetProgress == newProgress) {
                    return;  // already animating to the target progress
                }
                // start/update animation
                if (row.anim == null) {
                    row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress);
                    row.anim.setInterpolator(new DecelerateInterpolator());
                } else {
                    row.anim.cancel();
                    row.anim.setIntValues(progress, newProgress);
                }
                row.animTargetProgress = newProgress;
                row.anim.setDuration(UPDATE_ANIMATION_DURATION);
                row.anim.start();
            } else {
                // update slider directly to clamped value
                if (row.anim != null) {
                    row.anim.cancel();
                }
                row.slider.setProgress(newProgress);
            }
        }
        row.slider.setProgress(vlevel, true);
    }

    private void recheckH(VolumeRow row) {
@@ -1025,20 +989,19 @@ public class VolumeDialog {
                    + " onProgressChanged " + progress + " fromUser=" + fromUser);
            if (!fromUser) return;
            if (mRow.ss.levelMin > 0) {
                final int minProgress = mRow.ss.levelMin * 100;
                final int minProgress = mRow.ss.levelMin;
                if (progress < minProgress) {
                    seekBar.setProgress(minProgress);
                    progress = minProgress;
                }
            }
            final int userLevel = getImpliedLevel(seekBar, progress);
            if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
            if (mRow.ss.level != progress || mRow.ss.muted && progress > 0) {
                mRow.userAttempt = SystemClock.uptimeMillis();
                if (mRow.requestedLevel != userLevel) {
                    mController.setStreamVolume(mRow.stream, userLevel);
                    mRow.requestedLevel = userLevel;
                if (mRow.requestedLevel != progress) {
                    mController.setStreamVolume(mRow.stream, progress);
                    mRow.requestedLevel = progress;
                    Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
                            userLevel);
                            progress);
                }
            }
        }
@@ -1055,7 +1018,7 @@ public class VolumeDialog {
            if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
            mRow.tracking = false;
            mRow.userAttempt = SystemClock.uptimeMillis();
            int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
            final int userLevel = seekBar.getProgress();
            Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
            if (mRow.ss.level != userLevel) {
                mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
@@ -1137,8 +1100,6 @@ public class VolumeDialog {
        private int iconState;  // from Events
        private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
        private int cachedExpandButtonRes;
        private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
        private int animTargetProgress;
        private int lastAudibleLevel = 1;
    }