Merge "Combine UDFPS enroll segments into a single circle" into sc-v2-dev am: e1d531787c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/16200850

Change-Id: I0e1f370dad1d7a6806c986267a664b7b57c77e39
This commit is contained in:
Curtis Belmonte
2021-11-06 01:17:23 +00:00
committed by Automerger Merge Worker
4 changed files with 243 additions and 356 deletions

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2021 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="54dp"
android:height="54dp"
android:viewportWidth="54"
android:viewportHeight="54">
<path
android:pathData="M26.9999,3.9619C39.7029,3.9619 50.0369,14.2969 50.0369,26.9999C50.0369,39.7029 39.7029,50.0379 26.9999,50.0379C14.2969,50.0379 3.9629,39.7029 3.9629,26.9999C3.9629,14.2969 14.2969,3.9619 26.9999,3.9619Z"
android:fillColor="?android:colorBackground"
android:fillType="evenOdd"/>
<path
android:pathData="M27,0C12.088,0 0,12.088 0,27C0,41.912 12.088,54 27,54C41.912,54 54,41.912 54,27C54,12.088 41.912,0 27,0ZM27,3.962C39.703,3.962 50.037,14.297 50.037,27C50.037,39.703 39.703,50.038 27,50.038C14.297,50.038 3.963,39.703 3.963,27C3.963,14.297 14.297,3.962 27,3.962Z"
android:fillColor="@color/udfps_enroll_progress"
android:fillType="evenOdd"/>
<path
android:pathData="M23.0899,38.8534L10.4199,26.1824L13.2479,23.3544L23.0899,33.1974L41.2389,15.0474L44.0679,17.8754L23.0899,38.8534Z"
android:fillColor="@color/udfps_enroll_progress"
android:fillType="evenOdd"/>
</vector>

View File

@@ -16,17 +16,22 @@
package com.android.systemui.biometrics;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.util.TypedValue;
import android.view.animation.Interpolator;
import android.view.animation.OvershootInterpolator;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import com.android.systemui.R;
/**
* UDFPS enrollment progress bar.
@@ -34,108 +39,193 @@ import java.util.List;
public class UdfpsEnrollProgressBarDrawable extends Drawable {
private static final String TAG = "UdfpsProgressBar";
private static final float SEGMENT_GAP_ANGLE = 12f;
private static final long CHECKMARK_ANIMATION_DELAY_MS = 200L;
private static final long CHECKMARK_ANIMATION_DURATION_MS = 300L;
private static final long FILL_COLOR_ANIMATION_DURATION_MS = 200L;
private static final long PROGRESS_ANIMATION_DURATION_MS = 400L;
private static final float STROKE_WIDTH_DP = 12f;
@NonNull private final Context mContext;
private final float mStrokeWidthPx;
@ColorInt private final int mProgressColor;
@ColorInt private final int mHelpColor;
@NonNull private final Drawable mCheckmarkDrawable;
@NonNull private final Interpolator mCheckmarkInterpolator;
@NonNull private final Paint mBackgroundPaint;
@NonNull private final Paint mFillPaint;
@Nullable private UdfpsEnrollHelper mEnrollHelper;
@NonNull private List<UdfpsEnrollProgressBarSegment> mSegments = new ArrayList<>();
private boolean mAfterFirstTouch;
private int mRemainingSteps = 0;
private int mTotalSteps = 0;
private int mProgressSteps = 0;
private boolean mIsShowingHelp = false;
private float mProgress = 0f;
@Nullable private ValueAnimator mProgressAnimator;
@NonNull private final ValueAnimator.AnimatorUpdateListener mProgressUpdateListener;
private boolean mShowingHelp = false;
@Nullable private ValueAnimator mFillColorAnimator;
@NonNull private final ValueAnimator.AnimatorUpdateListener mFillColorUpdateListener;
private boolean mComplete = false;
private float mCheckmarkScale = 0f;
@Nullable private ValueAnimator mCheckmarkAnimator;
@NonNull private final ValueAnimator.AnimatorUpdateListener mCheckmarkUpdateListener;
public UdfpsEnrollProgressBarDrawable(@NonNull Context context) {
mContext = context;
}
mStrokeWidthPx = Utils.dpToPixels(context, STROKE_WIDTH_DP);
mProgressColor = context.getColor(R.color.udfps_enroll_progress);
mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark);
mCheckmarkDrawable.mutate();
mCheckmarkInterpolator = new OvershootInterpolator();
void setEnrollHelper(@Nullable UdfpsEnrollHelper enrollHelper) {
mEnrollHelper = enrollHelper;
if (enrollHelper != null) {
final int stageCount = enrollHelper.getStageCount();
mSegments = new ArrayList<>(stageCount);
float startAngle = SEGMENT_GAP_ANGLE / 2f;
final float sweepAngle = (360f / stageCount) - SEGMENT_GAP_ANGLE;
final Runnable invalidateRunnable = this::invalidateSelf;
for (int index = 0; index < stageCount; index++) {
mSegments.add(new UdfpsEnrollProgressBarSegment(mContext, getBounds(), startAngle,
sweepAngle, SEGMENT_GAP_ANGLE, invalidateRunnable));
startAngle += sweepAngle + SEGMENT_GAP_ANGLE;
}
invalidateSelf();
mBackgroundPaint = new Paint();
mBackgroundPaint.setStrokeWidth(mStrokeWidthPx);
mBackgroundPaint.setColor(context.getColor(R.color.white_disabled));
mBackgroundPaint.setAntiAlias(true);
mBackgroundPaint.setStyle(Paint.Style.STROKE);
mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
// Set background paint color and alpha.
final int[] attrs = new int[] {android.R.attr.colorControlNormal};
final TypedArray typedArray = context.obtainStyledAttributes(attrs);
try {
@ColorInt final int tintColor = typedArray.getColor(0, mBackgroundPaint.getColor());
mBackgroundPaint.setColor(tintColor);
} finally {
typedArray.recycle();
}
TypedValue alpha = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true);
mBackgroundPaint.setAlpha((int) (alpha.getFloat() * 255f));
// Progress fill should *not* use the extracted system color.
mFillPaint = new Paint();
mFillPaint.setStrokeWidth(mStrokeWidthPx);
mFillPaint.setColor(mProgressColor);
mFillPaint.setAntiAlias(true);
mFillPaint.setStyle(Paint.Style.STROKE);
mFillPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressUpdateListener = animation -> {
mProgress = (float) animation.getAnimatedValue();
invalidateSelf();
};
mFillColorUpdateListener = animation -> {
mFillPaint.setColor((int) animation.getAnimatedValue());
invalidateSelf();
};
mCheckmarkUpdateListener = animation -> {
mCheckmarkScale = (float) animation.getAnimatedValue();
invalidateSelf();
};
}
void onEnrollmentProgress(int remaining, int totalSteps) {
mTotalSteps = totalSteps;
// Show some progress for the initial touch.
updateState(Math.max(1, totalSteps - remaining), false /* isShowingHelp */);
mAfterFirstTouch = true;
updateState(remaining, totalSteps, false /* showingHelp */);
}
void onEnrollmentHelp(int remaining, int totalSteps) {
updateState(Math.max(0, totalSteps - remaining), true /* isShowingHelp */);
updateState(remaining, totalSteps, true /* showingHelp */);
}
void onLastStepAcquired() {
updateState(mTotalSteps, false /* isShowingHelp */);
updateState(0, mTotalSteps, false /* showingHelp */);
}
private void updateState(int progressSteps, boolean isShowingHelp) {
updateProgress(progressSteps);
updateFillColor(isShowingHelp);
private void updateState(int remainingSteps, int totalSteps, boolean showingHelp) {
updateProgress(remainingSteps, totalSteps);
updateFillColor(showingHelp);
}
private void updateProgress(int progressSteps) {
if (mProgressSteps == progressSteps) {
private void updateProgress(int remainingSteps, int totalSteps) {
if (mRemainingSteps == remainingSteps && mTotalSteps == totalSteps) {
return;
}
mProgressSteps = progressSteps;
mRemainingSteps = remainingSteps;
mTotalSteps = totalSteps;
if (mEnrollHelper == null) {
Log.e(TAG, "updateState: UDFPS enroll helper was null");
return;
final int progressSteps = Math.max(0, totalSteps - remainingSteps);
// If needed, add 1 to progress and total steps to account for initial touch.
final int adjustedSteps = mAfterFirstTouch ? progressSteps + 1 : progressSteps;
final int adjustedTotal = mAfterFirstTouch ? mTotalSteps + 1 : mTotalSteps;
final float targetProgress = Math.min(1f, (float) adjustedSteps / (float) adjustedTotal);
if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
mProgressAnimator.cancel();
}
int index = 0;
int prevThreshold = 0;
while (index < mSegments.size()) {
final UdfpsEnrollProgressBarSegment segment = mSegments.get(index);
final int thresholdSteps = mEnrollHelper.getStageThresholdSteps(mTotalSteps, index);
if (progressSteps >= thresholdSteps && segment.getProgress() < 1f) {
segment.updateProgress(1f);
break;
} else if (progressSteps >= prevThreshold && progressSteps < thresholdSteps) {
final int relativeSteps = progressSteps - prevThreshold;
final int relativeThreshold = thresholdSteps - prevThreshold;
final float segmentProgress = (float) relativeSteps / (float) relativeThreshold;
segment.updateProgress(segmentProgress);
break;
}
mProgressAnimator = ValueAnimator.ofFloat(mProgress, targetProgress);
mProgressAnimator.setDuration(PROGRESS_ANIMATION_DURATION_MS);
mProgressAnimator.addUpdateListener(mProgressUpdateListener);
mProgressAnimator.start();
index++;
prevThreshold = thresholdSteps;
}
if (progressSteps >= mTotalSteps) {
for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
segment.startCompletionAnimation();
}
} else {
for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
segment.cancelCompletionAnimation();
}
if (remainingSteps == 0) {
startCompletionAnimation();
} else if (remainingSteps > 0) {
rollBackCompletionAnimation();
}
}
private void updateFillColor(boolean isShowingHelp) {
if (mIsShowingHelp == isShowingHelp) {
private void updateFillColor(boolean showingHelp) {
if (mShowingHelp == showingHelp) {
return;
}
mIsShowingHelp = isShowingHelp;
mShowingHelp = showingHelp;
for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
segment.updateFillColor(isShowingHelp);
if (mFillColorAnimator != null && mFillColorAnimator.isRunning()) {
mFillColorAnimator.cancel();
}
@ColorInt final int targetColor = showingHelp ? mHelpColor : mProgressColor;
mFillColorAnimator = ValueAnimator.ofArgb(mFillPaint.getColor(), targetColor);
mFillColorAnimator.setDuration(FILL_COLOR_ANIMATION_DURATION_MS);
mFillColorAnimator.addUpdateListener(mFillColorUpdateListener);
mFillColorAnimator.start();
}
private void startCompletionAnimation() {
if (mComplete) {
return;
}
mComplete = true;
if (mCheckmarkAnimator != null && mCheckmarkAnimator.isRunning()) {
mCheckmarkAnimator.cancel();
}
mCheckmarkAnimator = ValueAnimator.ofFloat(mCheckmarkScale, 1f);
mCheckmarkAnimator.setStartDelay(CHECKMARK_ANIMATION_DELAY_MS);
mCheckmarkAnimator.setDuration(CHECKMARK_ANIMATION_DURATION_MS);
mCheckmarkAnimator.setInterpolator(mCheckmarkInterpolator);
mCheckmarkAnimator.addUpdateListener(mCheckmarkUpdateListener);
mCheckmarkAnimator.start();
}
private void rollBackCompletionAnimation() {
if (!mComplete) {
return;
}
mComplete = false;
// Adjust duration based on how much of the completion animation has played.
final float animatedFraction = mCheckmarkAnimator != null
? mCheckmarkAnimator.getAnimatedFraction()
: 0f;
final long durationMs = Math.round(CHECKMARK_ANIMATION_DELAY_MS * animatedFraction);
if (mCheckmarkAnimator != null && mCheckmarkAnimator.isRunning()) {
mCheckmarkAnimator.cancel();
}
mCheckmarkAnimator = ValueAnimator.ofFloat(mCheckmarkScale, 0f);
mCheckmarkAnimator.setDuration(durationMs);
mCheckmarkAnimator.addUpdateListener(mCheckmarkUpdateListener);
mCheckmarkAnimator.start();
}
@Override
@@ -145,12 +235,55 @@ public class UdfpsEnrollProgressBarDrawable extends Drawable {
// Progress starts from the top, instead of the right
canvas.rotate(-90f, getBounds().centerX(), getBounds().centerY());
// Draw each of the enroll segments.
for (final UdfpsEnrollProgressBarSegment segment : mSegments) {
segment.draw(canvas);
final float halfPaddingPx = mStrokeWidthPx / 2f;
if (mProgress < 1f) {
// Draw the background color of the progress circle.
canvas.drawArc(
halfPaddingPx,
halfPaddingPx,
getBounds().right - halfPaddingPx,
getBounds().bottom - halfPaddingPx,
0f /* startAngle */,
360f /* sweepAngle */,
false /* useCenter */,
mBackgroundPaint);
}
if (mProgress > 0f) {
// Draw the filled portion of the progress circle.
canvas.drawArc(
halfPaddingPx,
halfPaddingPx,
getBounds().right - halfPaddingPx,
getBounds().bottom - halfPaddingPx,
0f /* startAngle */,
360f * mProgress /* sweepAngle */,
false /* useCenter */,
mFillPaint);
}
canvas.restore();
if (mCheckmarkScale > 0f) {
final float offsetScale = (float) Math.sqrt(2) / 2f;
final float centerXOffset = (getBounds().width() - mStrokeWidthPx) / 2f * offsetScale;
final float centerYOffset = (getBounds().height() - mStrokeWidthPx) / 2f * offsetScale;
final float centerX = getBounds().centerX() + centerXOffset;
final float centerY = getBounds().centerY() + centerYOffset;
final float boundsXOffset =
mCheckmarkDrawable.getIntrinsicWidth() / 2f * mCheckmarkScale;
final float boundsYOffset =
mCheckmarkDrawable.getIntrinsicHeight() / 2f * mCheckmarkScale;
final int left = Math.round(centerX - boundsXOffset);
final int top = Math.round(centerY - boundsYOffset);
final int right = Math.round(centerX + boundsXOffset);
final int bottom = Math.round(centerY + boundsYOffset);
mCheckmarkDrawable.setBounds(left, top, right, bottom);
mCheckmarkDrawable.draw(canvas);
}
}
@Override

View File

@@ -1,280 +0,0 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.biometrics;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.util.TypedValue;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.systemui.R;
/**
* A single segment of the UDFPS enrollment progress bar.
*/
public class UdfpsEnrollProgressBarSegment {
private static final String TAG = "UdfpsProgressBarSegment";
private static final long FILL_COLOR_ANIMATION_DURATION_MS = 200L;
private static final long PROGRESS_ANIMATION_DURATION_MS = 400L;
private static final long OVER_SWEEP_ANIMATION_DELAY_MS = 200L;
private static final long OVER_SWEEP_ANIMATION_DURATION_MS = 200L;
private static final float STROKE_WIDTH_DP = 12f;
private final Handler mHandler = new Handler(Looper.getMainLooper());
@NonNull private final Rect mBounds;
@NonNull private final Runnable mInvalidateRunnable;
private final float mStartAngle;
private final float mSweepAngle;
private final float mMaxOverSweepAngle;
private final float mStrokeWidthPx;
@ColorInt private final int mProgressColor;
@ColorInt private final int mHelpColor;
@NonNull private final Paint mBackgroundPaint;
@NonNull private final Paint mProgressPaint;
private float mProgress = 0f;
private float mAnimatedProgress = 0f;
@Nullable private ValueAnimator mProgressAnimator;
@NonNull private final ValueAnimator.AnimatorUpdateListener mProgressUpdateListener;
private boolean mIsShowingHelp = false;
@Nullable private ValueAnimator mFillColorAnimator;
@NonNull private final ValueAnimator.AnimatorUpdateListener mFillColorUpdateListener;
private float mOverSweepAngle = 0f;
@Nullable private ValueAnimator mOverSweepAnimator;
@Nullable private ValueAnimator mOverSweepReverseAnimator;
@NonNull private final ValueAnimator.AnimatorUpdateListener mOverSweepUpdateListener;
@NonNull private final Runnable mOverSweepAnimationRunnable;
public UdfpsEnrollProgressBarSegment(@NonNull Context context, @NonNull Rect bounds,
float startAngle, float sweepAngle, float maxOverSweepAngle,
@NonNull Runnable invalidateRunnable) {
mBounds = bounds;
mInvalidateRunnable = invalidateRunnable;
mStartAngle = startAngle;
mSweepAngle = sweepAngle;
mMaxOverSweepAngle = maxOverSweepAngle;
mStrokeWidthPx = Utils.dpToPixels(context, STROKE_WIDTH_DP);
mProgressColor = context.getColor(R.color.udfps_enroll_progress);
mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
mBackgroundPaint = new Paint();
mBackgroundPaint.setStrokeWidth(mStrokeWidthPx);
mBackgroundPaint.setColor(context.getColor(R.color.white_disabled));
mBackgroundPaint.setAntiAlias(true);
mBackgroundPaint.setStyle(Paint.Style.STROKE);
mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
// Background paint color + alpha
final int[] attrs = new int[] {android.R.attr.colorControlNormal};
final TypedArray ta = context.obtainStyledAttributes(attrs);
@ColorInt final int tintColor = ta.getColor(0, mBackgroundPaint.getColor());
mBackgroundPaint.setColor(tintColor);
ta.recycle();
TypedValue alpha = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, alpha, true);
mBackgroundPaint.setAlpha((int) (alpha.getFloat() * 255f));
// Progress should not be color extracted
mProgressPaint = new Paint();
mProgressPaint.setStrokeWidth(mStrokeWidthPx);
mProgressPaint.setColor(mProgressColor);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
mProgressUpdateListener = animation -> {
mAnimatedProgress = (float) animation.getAnimatedValue();
mInvalidateRunnable.run();
};
mFillColorUpdateListener = animation -> {
mProgressPaint.setColor((int) animation.getAnimatedValue());
mInvalidateRunnable.run();
};
mOverSweepUpdateListener = animation -> {
mOverSweepAngle = (float) animation.getAnimatedValue();
mInvalidateRunnable.run();
};
mOverSweepAnimationRunnable = () -> {
if (mOverSweepAnimator != null && mOverSweepAnimator.isRunning()) {
mOverSweepAnimator.cancel();
}
mOverSweepAnimator = ValueAnimator.ofFloat(mOverSweepAngle, mMaxOverSweepAngle);
mOverSweepAnimator.setDuration(OVER_SWEEP_ANIMATION_DURATION_MS);
mOverSweepAnimator.addUpdateListener(mOverSweepUpdateListener);
mOverSweepAnimator.start();
};
}
/**
* Draws this segment to the given canvas.
*/
public void draw(@NonNull Canvas canvas) {
final float halfPaddingPx = mStrokeWidthPx / 2f;
if (mAnimatedProgress < 1f) {
// Draw the unfilled background color of the segment.
canvas.drawArc(
halfPaddingPx,
halfPaddingPx,
mBounds.right - halfPaddingPx,
mBounds.bottom - halfPaddingPx,
mStartAngle,
mSweepAngle,
false /* useCenter */,
mBackgroundPaint);
}
if (mAnimatedProgress > 0f) {
// Draw the filled progress portion of the segment.
canvas.drawArc(
halfPaddingPx,
halfPaddingPx,
mBounds.right - halfPaddingPx,
mBounds.bottom - halfPaddingPx,
mStartAngle,
mSweepAngle * mAnimatedProgress + mOverSweepAngle,
false /* useCenter */,
mProgressPaint);
}
}
/**
* @return The fill progress of this segment, in the range [0, 1]. If fill progress is being
* animated, returns the value it is animating to.
*/
public float getProgress() {
return mProgress;
}
/**
* Updates the fill progress of this segment, animating if necessary.
*
* @param progress The new fill progress, in the range [0, 1].
*/
public void updateProgress(float progress) {
updateProgress(progress, PROGRESS_ANIMATION_DURATION_MS);
}
private void updateProgress(float progress, long animationDurationMs) {
if (mProgress == progress) {
return;
}
mProgress = progress;
if (mProgressAnimator != null && mProgressAnimator.isRunning()) {
mProgressAnimator.cancel();
}
mProgressAnimator = ValueAnimator.ofFloat(mAnimatedProgress, progress);
mProgressAnimator.setDuration(animationDurationMs);
mProgressAnimator.addUpdateListener(mProgressUpdateListener);
mProgressAnimator.start();
}
/**
* Updates the fill color of this segment, animating if necessary.
*
* @param isShowingHelp Whether fill color should indicate that a help message is being shown.
*/
public void updateFillColor(boolean isShowingHelp) {
if (mIsShowingHelp == isShowingHelp) {
return;
}
mIsShowingHelp = isShowingHelp;
if (mFillColorAnimator != null && mFillColorAnimator.isRunning()) {
mFillColorAnimator.cancel();
}
@ColorInt final int targetColor = isShowingHelp ? mHelpColor : mProgressColor;
mFillColorAnimator = ValueAnimator.ofArgb(mProgressPaint.getColor(), targetColor);
mFillColorAnimator.setDuration(FILL_COLOR_ANIMATION_DURATION_MS);
mFillColorAnimator.addUpdateListener(mFillColorUpdateListener);
mFillColorAnimator.start();
}
/**
* Queues and runs the completion animation for this segment.
*/
public void startCompletionAnimation() {
final boolean hasCallback = mHandler.hasCallbacks(mOverSweepAnimationRunnable);
if (hasCallback || mOverSweepAngle >= mMaxOverSweepAngle) {
Log.d(TAG, "startCompletionAnimation skipped: hasCallback = " + hasCallback
+ ", mOverSweepAngle = " + mOverSweepAngle);
return;
}
// Reset sweep angle back to zero if the animation is being rolled back.
if (mOverSweepReverseAnimator != null && mOverSweepReverseAnimator.isRunning()) {
mOverSweepReverseAnimator.cancel();
mOverSweepAngle = 0f;
}
// Clear help color and start filling the segment if it isn't already.
if (mAnimatedProgress < 1f) {
updateProgress(1f, OVER_SWEEP_ANIMATION_DELAY_MS);
updateFillColor(false /* isShowingHelp */);
}
// Queue the animation to run after fill completes.
mHandler.postDelayed(mOverSweepAnimationRunnable, OVER_SWEEP_ANIMATION_DELAY_MS);
}
/**
* Cancels (and reverses, if necessary) a queued or running completion animation.
*/
public void cancelCompletionAnimation() {
// Cancel the animation if it's queued or running.
mHandler.removeCallbacks(mOverSweepAnimationRunnable);
if (mOverSweepAnimator != null && mOverSweepAnimator.isRunning()) {
mOverSweepAnimator.cancel();
}
// Roll back the animation if it has at least partially run.
if (mOverSweepAngle > 0f) {
if (mOverSweepReverseAnimator != null && mOverSweepReverseAnimator.isRunning()) {
mOverSweepReverseAnimator.cancel();
}
final float completion = mOverSweepAngle / mMaxOverSweepAngle;
final long proratedDuration = (long) (OVER_SWEEP_ANIMATION_DURATION_MS * completion);
mOverSweepReverseAnimator = ValueAnimator.ofFloat(mOverSweepAngle, 0f);
mOverSweepReverseAnimator.setDuration(proratedDuration);
mOverSweepReverseAnimator.addUpdateListener(mOverSweepUpdateListener);
mOverSweepReverseAnimator.start();
}
}
}

View File

@@ -73,7 +73,6 @@ public class UdfpsEnrollView extends UdfpsAnimationView {
}
void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
mFingerprintProgressDrawable.setEnrollHelper(enrollHelper);
mFingerprintDrawable.setEnrollHelper(enrollHelper);
}