diff options
author | jdduke <jdduke@chromium.org> | 2015-05-06 10:59:56 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-05-06 18:00:32 +0000 |
commit | afabd785dac54a2325206427ed5140ec7f7caf5a (patch) | |
tree | 49c5c37a885e4b1a732a8e7e13a43f2b7bcd2789 /third_party | |
parent | 9044bfa1dfb376789618573cd6ab2bd9996c318d (diff) | |
download | chromium_src-afabd785dac54a2325206427ed5140ec7f7caf5a.zip chromium_src-afabd785dac54a2325206427ed5140ec7f7caf5a.tar.gz chromium_src-afabd785dac54a2325206427ed5140ec7f7caf5a.tar.bz2 |
[Android] Cherry-pick upstream appcompat fixes for SwipeRefreshLayout
Cherry-pick several recent changes to SwipeRefreshLayout and its
dependencies. This includes both several stylistic tweaks as well as a
fix for animation transitions on several devices.
BUG=485145
Review URL: https://codereview.chromium.org/1127193002
Cr-Commit-Position: refs/heads/master@{#328559}
Diffstat (limited to 'third_party')
6 files changed, 202 insertions, 103 deletions
diff --git a/third_party/android_swipe_refresh/BUILD.gn b/third_party/android_swipe_refresh/BUILD.gn index ad14d81..c7939b0 100644 --- a/third_party/android_swipe_refresh/BUILD.gn +++ b/third_party/android_swipe_refresh/BUILD.gn @@ -8,4 +8,7 @@ assert(is_android) android_library("android_swipe_refresh_java") { DEPRECATED_java_in_dir = "java/src" + deps = [ + "//third_party/android_tools:android_support_v13_java", + ] } diff --git a/third_party/android_swipe_refresh/README.chromium b/third_party/android_swipe_refresh/README.chromium index 9cdec7c..3fde9b2 100644 --- a/third_party/android_swipe_refresh/README.chromium +++ b/third_party/android_swipe_refresh/README.chromium @@ -12,7 +12,7 @@ pull-to-refresh styled layout for touch-activated refresh of view contents. Local Modifications: CircleImageView, MaterialProgressDrawable - * The package has been changed, and all ViewCompat dependencies removed. + * The package has been changed, and most ViewCompat dependencies removed. SwipeRefreshLayout * MotionEvent-behavior has been changed to allow more abstract inputs. diff --git a/third_party/android_swipe_refresh/android_swipe_refresh.gyp b/third_party/android_swipe_refresh/android_swipe_refresh.gyp index 52e409b..c7f7e0f 100644 --- a/third_party/android_swipe_refresh/android_swipe_refresh.gyp +++ b/third_party/android_swipe_refresh/android_swipe_refresh.gyp @@ -7,6 +7,9 @@ { 'target_name': 'android_swipe_refresh_java', 'type': 'none', + 'dependencies': [ + '../android_tools/android_tools.gyp:android_support_v13_javalib', + ], 'variables': { 'java_in_dir': 'java', }, diff --git a/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/CircleImageView.java b/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/CircleImageView.java index fcb2185..c5611fe 100644 --- a/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/CircleImageView.java +++ b/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/CircleImageView.java @@ -85,7 +85,7 @@ class CircleImageView extends ImageView { setLayerType(View.LAYER_TYPE_SOFTWARE, circle.getPaint()); circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset, KEY_SHADOW_COLOR); - final int padding = (int) mShadowRadius; + final int padding = mShadowRadius; // set padding so the inner image sits correctly within the shadow. setPadding(padding, padding, padding, padding); return circle; @@ -126,11 +126,17 @@ class CircleImageView extends ImageView { /** * Update the background color of the circle image view. + * + * @param colorRes Id of a color resource. */ - public void setBackgroundColor(int colorRes) { + public void setBackgroundColorRes(int colorRes) { + setBackgroundColor(getContext().getResources().getColor(colorRes)); + } + + @Override + public void setBackgroundColor(int color) { if (getBackground() instanceof ShapeDrawable) { - final Resources res = getResources(); - ((ShapeDrawable) getBackground()).getPaint().setColor(res.getColor(colorRes)); + ((ShapeDrawable) getBackground()).getPaint().setColor(color); } } diff --git a/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/MaterialProgressDrawable.java b/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/MaterialProgressDrawable.java index 23a6a37..87df79a 100644 --- a/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/MaterialProgressDrawable.java +++ b/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/MaterialProgressDrawable.java @@ -26,7 +26,6 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; -import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Path; @@ -35,6 +34,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.graphics.drawable.Animatable; +import android.support.v4.view.animation.FastOutSlowInInterpolator; import android.util.DisplayMetrics; import android.view.View; @@ -45,14 +45,13 @@ import java.util.ArrayList; /** * Fancy progress indicator for Material theme. * - * @hide + * @hide */ class MaterialProgressDrawable extends Drawable implements Animatable { private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); - private static final Interpolator END_CURVE_INTERPOLATOR = new EndCurveInterpolator(); - private static final Interpolator START_CURVE_INTERPOLATOR = new StartCurveInterpolator(); - private static final Interpolator EASE_INTERPOLATOR = new AccelerateDecelerateInterpolator(); + private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator(); + private static final float FULL_ROTATION = 1080.0f; @Retention(RetentionPolicy.CLASS) public @interface ProgressDrawableSize {} // Maps to ProgressBar.Large style @@ -74,8 +73,16 @@ class MaterialProgressDrawable extends Drawable implements Animatable { Color.BLACK }; + /** + * The value in the linear interpolator for animating the drawable at which + * the color transition should start + */ + private static final float COLOR_START_DELAY_OFFSET = 0.75f; + private static final float END_TRIM_START_DELAY_OFFSET = 0.5f; + private static final float START_TRIM_DURATION_OFFSET = 0.5f; + /** The duration of a single progress spin in milliseconds. */ - private static final int ANIMATION_DURATION = 1000 * 80 / 60; + private static final int ANIMATION_DURATION = 1332; /** The number of points in the progress "star". */ private static final float NUM_POINTS = 5f; @@ -104,7 +111,7 @@ class MaterialProgressDrawable extends Drawable implements Animatable { private float mRotationCount; private double mWidth; private double mHeight; - private Animation mFinishAnimation; + private boolean mFinishing; public MaterialProgressDrawable(Context context, View parent) { mParent = parent; @@ -282,10 +289,13 @@ class MaterialProgressDrawable extends Drawable implements Animatable { mRing.storeOriginals(); // Already showing some part of the ring if (mRing.getEndTrim() != mRing.getStartTrim()) { - mParent.startAnimation(mFinishAnimation); + mFinishing = true; + mAnimation.setDuration(ANIMATION_DURATION/2); + mParent.startAnimation(mAnimation); } else { mRing.setColorIndex(0); mRing.resetOriginals(); + mAnimation.setDuration(ANIMATION_DURATION); mParent.startAnimation(mAnimation); } } @@ -299,78 +309,122 @@ class MaterialProgressDrawable extends Drawable implements Animatable { mRing.resetOriginals(); } - private void setupAnimators() { - final Ring ring = mRing; - final Animation finishRingAnimation = new Animation() { - public void applyTransformation(float interpolatedTime, Transformation t) { - // shrink back down and complete a full rotation before starting other circles - // Rotation goes between [0..1]. - float targetRotation = (float) (Math.floor(ring.getStartingRotation() - / MAX_PROGRESS_ARC) + 1f); - final float startTrim = ring.getStartingStartTrim() - + (ring.getStartingEndTrim() - ring.getStartingStartTrim()) - * interpolatedTime; - ring.setStartTrim(startTrim); - final float rotation = ring.getStartingRotation() - + ((targetRotation - ring.getStartingRotation()) * interpolatedTime); - ring.setRotation(rotation); - ring.setArrowScale(1 - interpolatedTime); - } - }; - finishRingAnimation.setInterpolator(EASE_INTERPOLATOR); - finishRingAnimation.setDuration(ANIMATION_DURATION/2); - finishRingAnimation.setAnimationListener(new Animation.AnimationListener() { + private float getMinProgressArc(Ring ring) { + return (float) Math.toRadians( + ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius())); + } - @Override - public void onAnimationStart(Animation animation) { - } + // Adapted from ArgbEvaluator.java + private int evaluateColorChange(float fraction, int startValue, int endValue) { + int startInt = (Integer) startValue; + int startA = (startInt >> 24) & 0xff; + int startR = (startInt >> 16) & 0xff; + int startG = (startInt >> 8) & 0xff; + int startB = startInt & 0xff; + + int endInt = (Integer) endValue; + int endA = (endInt >> 24) & 0xff; + int endR = (endInt >> 16) & 0xff; + int endG = (endInt >> 8) & 0xff; + int endB = endInt & 0xff; + + return (int)((startA + (int)(fraction * (endA - startA))) << 24) | + (int)((startR + (int)(fraction * (endR - startR))) << 16) | + (int)((startG + (int)(fraction * (endG - startG))) << 8) | + (int)((startB + (int)(fraction * (endB - startB)))); + } - @Override - public void onAnimationEnd(Animation animation) { - ring.goToNextColor(); - ring.storeOriginals(); - ring.setShowArrow(false); - mParent.startAnimation(mAnimation); - } + /** + * Update the ring color if this is within the last 25% of the animation. + * The new ring color will be a translation from the starting ring color to + * the next color. + */ + private void updateRingColor(float interpolatedTime, Ring ring) { + if (interpolatedTime > COLOR_START_DELAY_OFFSET) { + // scale the interpolatedTime so that the full + // transformation from 0 - 1 takes place in the + // remaining time + ring.setColor(evaluateColorChange((interpolatedTime - COLOR_START_DELAY_OFFSET) + / (1.0f - COLOR_START_DELAY_OFFSET), ring.getStartingColor(), + ring.getNextColor())); + } + } - @Override - public void onAnimationRepeat(Animation animation) { - } - }); + private void applyFinishTranslation(float interpolatedTime, Ring ring) { + // shrink back down and complete a full rotation before + // starting other circles + // Rotation goes between [0..1]. + updateRingColor(interpolatedTime, ring); + float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC) + + 1f); + final float minProgressArc = getMinProgressArc(ring); + final float startTrim = ring.getStartingStartTrim() + + (ring.getStartingEndTrim() - minProgressArc - ring.getStartingStartTrim()) + * interpolatedTime; + ring.setStartTrim(startTrim); + ring.setEndTrim(ring.getStartingEndTrim()); + final float rotation = ring.getStartingRotation() + + ((targetRotation - ring.getStartingRotation()) * interpolatedTime); + ring.setRotation(rotation); + } + + private void setupAnimators() { + final Ring ring = mRing; final Animation animation = new Animation() { @Override public void applyTransformation(float interpolatedTime, Transformation t) { - // The minProgressArc is calculated from 0 to create an angle that - // matches the stroke width. - final float minProgressArc = (float) Math.toRadians(ring.getStrokeWidth() - / (2 * Math.PI * ring.getCenterRadius())); - final float startingEndTrim = ring.getStartingEndTrim(); - final float startingTrim = ring.getStartingStartTrim(); - final float startingRotation = ring.getStartingRotation(); - - // Offset the minProgressArc to where the endTrim is located. - final float minArc = MAX_PROGRESS_ARC - minProgressArc; - final float endTrim = startingEndTrim - + (minArc * START_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime)); - ring.setEndTrim(endTrim); - - final float startTrim = startingTrim - + (MAX_PROGRESS_ARC * END_CURVE_INTERPOLATOR - .getInterpolation(interpolatedTime)); - ring.setStartTrim(startTrim); - - final float rotation = startingRotation + (0.25f * interpolatedTime); - ring.setRotation(rotation); - - float groupRotation = ((720.0f / NUM_POINTS) * interpolatedTime) - + (720.0f * (mRotationCount / NUM_POINTS)); - setRotation(groupRotation); + if (mFinishing) { + applyFinishTranslation(interpolatedTime, ring); + } else { + // The minProgressArc is calculated from 0 to create an + // angle that matches the stroke width. + final float minProgressArc = getMinProgressArc(ring); + final float startingEndTrim = ring.getStartingEndTrim(); + final float startingTrim = ring.getStartingStartTrim(); + final float startingRotation = ring.getStartingRotation(); + + updateRingColor(interpolatedTime, ring); + + // Moving the start trim only occurs in the first 50% of a + // single ring animation + if (interpolatedTime <= START_TRIM_DURATION_OFFSET) { + // scale the interpolatedTime so that the full + // transformation from 0 - 1 takes place in the + // remaining time + final float scaledTime = (interpolatedTime) + / (1.0f - START_TRIM_DURATION_OFFSET); + final float startTrim = startingTrim + + ((MAX_PROGRESS_ARC - minProgressArc) * MATERIAL_INTERPOLATOR + .getInterpolation(scaledTime)); + ring.setStartTrim(startTrim); + } + + // Moving the end trim starts after 50% of a single ring + // animation completes + if (interpolatedTime > END_TRIM_START_DELAY_OFFSET) { + // scale the interpolatedTime so that the full + // transformation from 0 - 1 takes place in the + // remaining time + final float minArc = MAX_PROGRESS_ARC - minProgressArc; + float scaledTime = (interpolatedTime - START_TRIM_DURATION_OFFSET) + / (1.0f - START_TRIM_DURATION_OFFSET); + final float endTrim = startingEndTrim + + (minArc * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime)); + ring.setEndTrim(endTrim); + } + + final float rotation = startingRotation + (0.25f * interpolatedTime); + ring.setRotation(rotation); + + float groupRotation = ((FULL_ROTATION / NUM_POINTS) * interpolatedTime) + + (FULL_ROTATION * (mRotationCount / NUM_POINTS)); + setRotation(groupRotation); + } } }; animation.setRepeatCount(10); animation.setRepeatMode(Animation.RESTART); animation.setInterpolator(LINEAR_INTERPOLATOR); - animation.setDuration(ANIMATION_DURATION); animation.setAnimationListener(new Animation.AnimationListener() { @Override @@ -388,10 +442,17 @@ class MaterialProgressDrawable extends Drawable implements Animatable { ring.storeOriginals(); ring.goToNextColor(); ring.setStartTrim(ring.getEndTrim()); - mRotationCount = (mRotationCount + 1) % (NUM_POINTS); + if (mFinishing) { + // finished closing the last ring from the swipe gesture; go + // into progress mode + mFinishing = false; + animation.setDuration(ANIMATION_DURATION); + ring.setShowArrow(false); + } else { + mRotationCount = (mRotationCount + 1) % (NUM_POINTS); + } } }); - mFinishAnimation = finishRingAnimation; mAnimation = animation; } @@ -442,6 +503,7 @@ class MaterialProgressDrawable extends Drawable implements Animatable { private int mAlpha; private final Paint mCirclePaint = new Paint(); private int mBackgroundColor; + private int mCurrentColor; public Ring(Callback callback) { mCallback = callback; @@ -481,7 +543,7 @@ class MaterialProgressDrawable extends Drawable implements Animatable { final float endAngle = (mEndTrim + mRotation) * 360; float sweepAngle = endAngle - startAngle; - mPaint.setColor(mColors[mColorIndex]); + mPaint.setColor(mCurrentColor); c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint); drawTriangle(c, startAngle, sweepAngle, bounds); @@ -519,7 +581,7 @@ class MaterialProgressDrawable extends Drawable implements Animatable { mArrow.offset(x - inset, y); mArrow.close(); // draw a triangle - mArrowPaint.setColor(mColors[mColorIndex]); + mArrowPaint.setColor(mCurrentColor); c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(), bounds.exactCenterY()); c.drawPath(mArrow, mArrowPaint); @@ -538,11 +600,34 @@ class MaterialProgressDrawable extends Drawable implements Animatable { } /** + * Set the absolute color of the progress spinner. This is should only + * be used when animating between current and next color when the + * spinner is rotating. + * + * @param color int describing the color. + */ + public void setColor(int color) { + mCurrentColor = color; + } + + /** * @param index Index into the color array of the color to display in * the progress spinner. */ public void setColorIndex(int index) { mColorIndex = index; + mCurrentColor = mColors[mColorIndex]; + } + + /** + * @return int describing the next color the progress spinner should use when drawing. + */ + public int getNextColor() { + return mColors[getNextColorIndex()]; + } + + private int getNextColorIndex() { + return (mColorIndex + 1) % (mColors.length); } /** @@ -550,7 +635,7 @@ class MaterialProgressDrawable extends Drawable implements Animatable { * wrap back to the beginning of colors. */ public void goToNextColor() { - mColorIndex = (mColorIndex + 1) % (mColors.length); + setColorIndex(getNextColorIndex()); } public void setColorFilter(ColorFilter filter) { @@ -608,6 +693,10 @@ class MaterialProgressDrawable extends Drawable implements Animatable { return mStartingEndTrim; } + public int getStartingColor() { + return mColors[mColorIndex]; + } + @SuppressWarnings("unused") public void setEndTrim(float endTrim) { mEndTrim = endTrim; @@ -711,24 +800,4 @@ class MaterialProgressDrawable extends Drawable implements Animatable { mCallback.invalidateDrawable(null); } } - - /** - * Squishes the interpolation curve into the second half of the animation. - */ - private static class EndCurveInterpolator extends AccelerateDecelerateInterpolator { - @Override - public float getInterpolation(float input) { - return super.getInterpolation(Math.max(0, (input - 0.5f) * 2.0f)); - } - } - - /** - * Squishes the interpolation curve into the first half of the animation. - */ - private static class StartCurveInterpolator extends AccelerateDecelerateInterpolator { - @Override - public float getInterpolation(float input) { - return super.getInterpolation(Math.min(1, input * 2.0f)); - } - } } diff --git a/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/SwipeRefreshLayout.java b/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/SwipeRefreshLayout.java index eed8d77..b5b6891 100644 --- a/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/SwipeRefreshLayout.java +++ b/third_party/android_swipe_refresh/java/src/org/chromium/third_party/android/swiperefresh/SwipeRefreshLayout.java @@ -441,13 +441,30 @@ public class SwipeRefreshLayout extends ViewGroup { } /** + * @deprecated Use {@link #setProgressBackgroundColorSchemeResource(int)} + */ + @Deprecated + public void setProgressBackgroundColor(int colorRes) { + setProgressBackgroundColorSchemeResource(colorRes); + } + + /** * Set the background color of the progress spinner disc. * * @param colorRes Resource id of the color. */ - public void setProgressBackgroundColor(int colorRes) { - mCircleView.setBackgroundColor(colorRes); - mProgress.setBackgroundColor(getResources().getColor(colorRes)); + public void setProgressBackgroundColorSchemeResource(int colorRes) { + setProgressBackgroundColorSchemeColor(getResources().getColor(colorRes)); + } + + /** + * Set the background color of the progress spinner disc. + * + * @param color + */ + public void setProgressBackgroundColorSchemeColor(int color) { + mCircleView.setBackgroundColor(color); + mProgress.setBackgroundColor(color); } /** @@ -596,7 +613,7 @@ public class SwipeRefreshLayout extends ViewGroup { setAnimationProgress(overscrollTop / mTotalDragDistance); } } - float strokeStart = (float) (adjustedPercent * .8f); + float strokeStart = adjustedPercent * .8f; mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart)); mProgress.setArrowScale(Math.min(1f, adjustedPercent)); @@ -719,6 +736,7 @@ public class SwipeRefreshLayout extends ViewGroup { targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime)); int offset = targetTop - mCircleView.getTop(); setTargetOffsetTopAndBottom(offset, false /* requires update */); + mProgress.setArrowScale(1 - interpolatedTime); } }; |