16412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh/* 26412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * Copyright (C) 2015 The Android Open Source Project 36412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * 46412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * Licensed under the Apache License, Version 2.0 (the "License"); 56412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * you may not use this file except in compliance with the License. 66412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * You may obtain a copy of the License at 76412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * 86412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * http://www.apache.org/licenses/LICENSE-2.0 96412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * 106412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * Unless required by applicable law or agreed to in writing, software 116412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * distributed under the License is distributed on an "AS IS" BASIS, 126412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * See the License for the specific language governing permissions and 146412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * limitations under the License 156412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh */ 166412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 176412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughpackage android.support.wearable.view; 186412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 196412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.animation.ObjectAnimator; 206412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.animation.TimeInterpolator; 216412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.animation.ValueAnimator; 226412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.annotation.TargetApi; 236412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.graphics.Canvas; 246412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.graphics.ColorFilter; 256412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.graphics.Paint; 266412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.graphics.PixelFormat; 276412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.graphics.RectF; 286412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.graphics.drawable.Drawable; 296412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.os.Build; 306412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.util.Property; 316412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughimport android.view.animation.LinearInterpolator; 326412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 336412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh/** 346412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * Drawable for showing an indeterminate progress indicator. 356412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * 366412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * TODO: When Material progress drawable is available in the support library stop using this. 376412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * 386412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * @hide 396412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh */ 406412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh@TargetApi(Build.VERSION_CODES.KITKAT_WATCH) 416412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hughclass ProgressDrawable extends Drawable { 426412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 436412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static Property<ProgressDrawable, Integer> LEVEL = 446412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh new Property<ProgressDrawable, Integer>(Integer.class, "level") { 456412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh @Override 466412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public Integer get(ProgressDrawable drawable) { 476412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh return drawable.getLevel(); 486412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 496412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 506412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh @Override 516412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public void set(ProgressDrawable drawable, Integer value) { 526412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh drawable.setLevel(value); 536412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh drawable.invalidateSelf(); 546412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 556412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh }; 566412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh /** Max level for a level drawable, as specified in developer docs for {@link Drawable}. */ 576412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final int MAX_LEVEL = 10000; 586412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 596412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh /** How many different sections are there, five gives us the material style star. **/ 606412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final int NUMBER_OF_SEGMENTS = 5; 616412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 626412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final int LEVELS_PER_SEGMENT = MAX_LEVEL / NUMBER_OF_SEGMENTS; 636412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final float STARTING_ANGLE = -90f; 646412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final long ANIMATION_DURATION = 6000; 656412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final int FULL_CIRCLE = 360; 666412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final int MAX_SWEEP = 306; 676412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final int CORRECTION_ANGLE = FULL_CIRCLE - MAX_SWEEP; 686412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh /** How far through each cycle does the bar stop growing and start shrinking, half way. **/ 696412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final float GROW_SHRINK_RATIO = 0.5f; 706412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh // TODO: replace this with BakedBezierInterpolator when its available in support library. 716412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static final TimeInterpolator mInterpolator = Gusterpolator.INSTANCE; 726412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 736412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private final RectF mInnerCircleBounds = new RectF(); 746412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private final Paint mPaint = new Paint(); 756412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private final ObjectAnimator mAnimator; 766412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private float mCircleBorderWidth; 776412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private int mCircleBorderColor; 786412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 796412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public ProgressDrawable() { 806412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mPaint.setAntiAlias(true); 816412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mPaint.setStyle(Paint.Style.STROKE); 826412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mAnimator = ObjectAnimator.ofInt(this, LEVEL, 0, MAX_LEVEL); 836412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mAnimator.setRepeatCount(ValueAnimator.INFINITE); 846412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mAnimator.setRepeatMode(ValueAnimator.RESTART); 856412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mAnimator.setDuration(ANIMATION_DURATION); 866412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mAnimator.setInterpolator(new LinearInterpolator()); 876412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 886412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 896412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public void setRingColor(int color) { 906412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mCircleBorderColor = color; 916412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 926412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 936412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public void setRingWidth(float width) { 946412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mCircleBorderWidth = width; 956412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 966412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 976412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public void startAnimation() { 986412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mAnimator.start(); 996412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1006412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1016412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public void stopAnimation() { 1026412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mAnimator.cancel(); 1036412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1046412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1056412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh @Override 1066412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public void draw(Canvas canvas) { 1076412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh canvas.save(); 1086412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mInnerCircleBounds.set(getBounds()); 1096412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mInnerCircleBounds.inset(mCircleBorderWidth / 2.0f, mCircleBorderWidth / 2.0f); 1106412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mPaint.setStrokeWidth(mCircleBorderWidth); 1116412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mPaint.setColor(mCircleBorderColor); 1126412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1136412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh float sweepAngle = FULL_CIRCLE; 1146412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh boolean growing = false; 1156412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh float correctionAngle = 0; 1166412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh int level = getLevel(); 1176412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1186412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh int currentSegment = level / LEVELS_PER_SEGMENT; 1196412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh int offset = currentSegment * LEVELS_PER_SEGMENT; 1206412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh float progress = (level - offset) / (float) LEVELS_PER_SEGMENT; 1216412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1226412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh growing = progress < GROW_SHRINK_RATIO; 1236412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh correctionAngle = CORRECTION_ANGLE * progress; 1246412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1256412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh if (growing) { 1266412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh sweepAngle = MAX_SWEEP * mInterpolator.getInterpolation( 1276412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh lerpInv(0f, GROW_SHRINK_RATIO, progress)); 1286412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } else { 1296412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh sweepAngle = MAX_SWEEP * (1.0f - mInterpolator.getInterpolation( 1306412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh lerpInv(GROW_SHRINK_RATIO, 1.0f, progress))); 1316412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1326412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1336412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh sweepAngle = Math.max(1, sweepAngle); 1346412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1356412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh canvas.rotate( 1366412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh level * (1.0f / MAX_LEVEL) * 2 * FULL_CIRCLE + STARTING_ANGLE + correctionAngle, 1376412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mInnerCircleBounds.centerX(), 1386412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mInnerCircleBounds.centerY()); 1396412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh canvas.drawArc(mInnerCircleBounds, 1406412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh growing ? 0 : MAX_SWEEP - sweepAngle, 1416412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh sweepAngle, 1426412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh false, 1436412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh mPaint); 1446412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh canvas.restore(); 1456412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1466412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1476412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh @Override 1486412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public void setAlpha(int i) { 1496412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh // Not supported. 1506412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1516412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1526412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh @Override 1536412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public void setColorFilter(ColorFilter colorFilter) { 1546412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh // Not supported. 1556412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1566412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1576412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh @Override 1586412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh public int getOpacity() { 1596412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh return PixelFormat.OPAQUE; 1606412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1616412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1626412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh @Override 1636412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh protected boolean onLevelChange(int level) { 1646412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh return true; // Changing the level of this drawable does change its appearance. 1656412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1666412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh 1676412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh /** 1686412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * Returns the interpolation scalar (s) that satisfies the equation: 1696412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * {@code value = }lerp(a, b, s) 1706412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * 1716412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh * <p>If {@code a == b}, then this function will return 0. 1726412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh */ 1736412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh private static float lerpInv(float a, float b, float value) { 1746412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh return a != b ? ((value - a) / (b - a)) : 0.0f; 1756412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh } 1766412dc4a8f47b134af6c5abb5f7f30321bb3ce68Anthony Hugh} 177