Merge "Move PIN/Pattern appear animation to RenderThread (1/2)" into mnc-dev
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 444f878..a709bb8e 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -23,10 +23,10 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Debug;
@@ -38,8 +38,10 @@
import android.util.AttributeSet;
import android.util.IntArray;
import android.util.Log;
+import android.view.DisplayListCanvas;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
+import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -200,10 +202,16 @@
}
public static class CellState {
- public float scale = 1.0f;
- public float translateY = 0.0f;
- public float alpha = 1.0f;
- public float size;
+ int row;
+ int col;
+ boolean hwAnimating;
+ CanvasProperty<Float> hwRadius;
+ CanvasProperty<Float> hwCenterX;
+ CanvasProperty<Float> hwCenterY;
+ CanvasProperty<Paint> hwPaint;
+ float radius;
+ float translationY;
+ float alpha = 1f;
public float lineEndX = Float.MIN_VALUE;
public float lineEndY = Float.MIN_VALUE;
public ValueAnimator lineAnimator;
@@ -313,7 +321,9 @@
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
mCellStates[i][j] = new CellState();
- mCellStates[i][j].size = mDotSize;
+ mCellStates[i][j].radius = mDotSize/2;
+ mCellStates[i][j].row = i;
+ mCellStates[i][j].col = j;
}
}
@@ -412,6 +422,112 @@
invalidate();
}
+ public void startCellStateAnimation(CellState cellState, float startAlpha, float endAlpha,
+ float startTranslationY, float endTranslationY, float startScale, float endScale,
+ long delay, long duration,
+ Interpolator interpolator, Runnable finishRunnable) {
+ if (isHardwareAccelerated()) {
+ startCellStateAnimationHw(cellState, startAlpha, endAlpha, startTranslationY,
+ endTranslationY, startScale, endScale, delay, duration, interpolator,
+ finishRunnable);
+ } else {
+ startCellStateAnimationSw(cellState, startAlpha, endAlpha, startTranslationY,
+ endTranslationY, startScale, endScale, delay, duration, interpolator,
+ finishRunnable);
+ }
+ }
+
+ private void startCellStateAnimationSw(final CellState cellState,
+ final float startAlpha, final float endAlpha,
+ final float startTranslationY, final float endTranslationY,
+ final float startScale, final float endScale,
+ long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) {
+ cellState.alpha = startAlpha;
+ cellState.translationY = startTranslationY;
+ cellState.radius = mDotSize/2 * startScale;
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = (float) animation.getAnimatedValue();
+ cellState.alpha = (1 - t) * startAlpha + t * endAlpha;
+ cellState.translationY = (1 - t) * startTranslationY + t * endTranslationY;
+ cellState.radius = mDotSize/2 * ((1 - t) * startScale + t * endScale);
+ invalidate();
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
+ }
+ });
+ animator.start();
+ }
+
+ private void startCellStateAnimationHw(final CellState cellState,
+ float startAlpha, float endAlpha,
+ float startTranslationY, float endTranslationY,
+ float startScale, float endScale,
+ long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) {
+ cellState.alpha = endAlpha;
+ cellState.translationY = endTranslationY;
+ cellState.radius = mDotSize/2 * endScale;
+ cellState.hwAnimating = true;
+ cellState.hwCenterY = CanvasProperty.createFloat(
+ getCenterYForRow(cellState.row) + startTranslationY);
+ cellState.hwCenterX = CanvasProperty.createFloat(getCenterXForColumn(cellState.col));
+ cellState.hwRadius = CanvasProperty.createFloat(mDotSize/2 * startScale);
+ mPaint.setColor(getCurrentColor(false));
+ mPaint.setAlpha((int) (startAlpha * 255));
+ cellState.hwPaint = CanvasProperty.createPaint(new Paint(mPaint));
+
+ startRtFloatAnimation(cellState.hwCenterY,
+ getCenterYForRow(cellState.row) + endTranslationY, delay, duration, interpolator);
+ startRtFloatAnimation(cellState.hwRadius, mDotSize/2 * endScale, delay, duration,
+ interpolator);
+ startRtAlphaAnimation(cellState, endAlpha, delay, duration, interpolator,
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ cellState.hwAnimating = false;
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
+ }
+ });
+
+ invalidate();
+ }
+
+ private void startRtAlphaAnimation(CellState cellState, float endAlpha,
+ long delay, long duration, Interpolator interpolator,
+ Animator.AnimatorListener listener) {
+ RenderNodeAnimator animator = new RenderNodeAnimator(cellState.hwPaint,
+ RenderNodeAnimator.PAINT_ALPHA, (int) (endAlpha * 255));
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.setTarget(this);
+ animator.addListener(listener);
+ animator.start();
+ }
+
+ private void startRtFloatAnimation(CanvasProperty<Float> property, float endValue,
+ long delay, long duration, Interpolator interpolator) {
+ RenderNodeAnimator animator = new RenderNodeAnimator(property, endValue);
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.setTarget(this);
+ animator.start();
+ }
+
private void notifyCellAdded() {
// sendAccessEvent(R.string.lockscreen_access_pattern_cell_added);
if (mOnPatternListener != null) {
@@ -603,14 +719,15 @@
private void startCellActivatedAnimation(Cell cell) {
final CellState cellState = mCellStates[cell.row][cell.column];
- startSizeAnimation(mDotSize, mDotSizeActivated, 96, mLinearOutSlowInInterpolator,
+ startRadiusAnimation(mDotSize/2, mDotSizeActivated/2, 96, mLinearOutSlowInInterpolator,
cellState, new Runnable() {
- @Override
- public void run() {
- startSizeAnimation(mDotSizeActivated, mDotSize, 192, mFastOutSlowInInterpolator,
- cellState, null);
- }
- });
+ @Override
+ public void run() {
+ startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192,
+ mFastOutSlowInInterpolator,
+ cellState, null);
+ }
+ });
startLineEndAnimation(cellState, mInProgressX, mInProgressY,
getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
}
@@ -639,13 +756,13 @@
state.lineAnimator = valueAnimator;
}
- private void startSizeAnimation(float start, float end, long duration, Interpolator interpolator,
- final CellState state, final Runnable endRunnable) {
+ private void startRadiusAnimation(float start, float end, long duration,
+ Interpolator interpolator, final CellState state, final Runnable endRunnable) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
- state.size = (float) animation.getAnimatedValue();
+ state.radius = (float) animation.getAnimatedValue();
invalidate();
}
});
@@ -969,10 +1086,16 @@
for (int j = 0; j < 3; j++) {
CellState cellState = mCellStates[i][j];
float centerX = getCenterXForColumn(j);
- float size = cellState.size * cellState.scale;
- float translationY = cellState.translateY;
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- size, drawLookup[i][j], cellState.alpha);
+ float translationY = cellState.translationY;
+ if (isHardwareAccelerated() && cellState.hwAnimating) {
+ DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+ displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
+ cellState.hwRadius, cellState.hwPaint);
+ } else {
+ drawCircle(canvas, (int) centerX, (int) centerY + translationY,
+ cellState.radius, drawLookup[i][j], cellState.alpha);
+
+ }
}
}
@@ -1055,11 +1178,11 @@
/**
* @param partOfPattern Whether this circle is part of the pattern.
*/
- private void drawCircle(Canvas canvas, float centerX, float centerY, float size,
+ private void drawCircle(Canvas canvas, float centerX, float centerY, float radius,
boolean partOfPattern, float alpha) {
mPaint.setColor(getCurrentColor(partOfPattern));
mPaint.setAlpha((int) (alpha * 255));
- canvas.drawCircle(centerX, centerY, size/2, mPaint);
+ canvas.drawCircle(centerX, centerY, radius, mPaint);
}
@Override
@@ -1290,7 +1413,6 @@
float centerY = getCenterYForRow(row);
float cellheight = mSquareHeight * mHitFactor * 0.5f;
float cellwidth = mSquareWidth * mHitFactor * 0.5f;
- float translationY = cell.translateY;
bounds.left = (int) (centerX - cellwidth);
bounds.right = (int) (centerX + cellwidth);
bounds.top = (int) (centerY - cellheight);
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
index d265e0d..4abb795 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPINView.java
@@ -16,8 +16,12 @@
package com.android.keyguard;
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.RenderNode;
+import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
@@ -114,10 +118,8 @@
enableClipping(false);
setAlpha(1f);
setTranslationY(mAppearAnimationUtils.getStartTranslation());
- animate()
- .setDuration(500)
- .setInterpolator(mAppearAnimationUtils.getInterpolator())
- .translationY(0);
+ AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */,
+ 0, mAppearAnimationUtils.getInterpolator());
mAppearAnimationUtils.startAnimation2d(mViews,
new Runnable() {
@Override
@@ -131,10 +133,8 @@
public boolean startDisappearAnimation(final Runnable finishRunnable) {
enableClipping(false);
setTranslationY(0);
- animate()
- .setDuration(280)
- .setInterpolator(mDisappearAnimationUtils.getInterpolator())
- .translationY(mDisappearYTranslation);
+ AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 280 /* duration */,
+ mDisappearYTranslation, mDisappearAnimationUtils.getInterpolator());
mDisappearAnimationUtils.startAnimation2d(mViews,
new Runnable() {
@Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 3568429..b000e26 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -17,6 +17,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
@@ -27,6 +28,7 @@
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
@@ -334,10 +336,8 @@
enableClipping(false);
setAlpha(1f);
setTranslationY(mAppearAnimationUtils.getStartTranslation());
- animate()
- .setDuration(500)
- .setInterpolator(mAppearAnimationUtils.getInterpolator())
- .translationY(0);
+ AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */,
+ 0, mAppearAnimationUtils.getInterpolator());
mAppearAnimationUtils.startAnimation2d(
mLockPatternView.getCellStates(),
new Runnable() {
@@ -362,10 +362,9 @@
mLockPatternView.clearPattern();
enableClipping(false);
setTranslationY(0);
- animate()
- .setDuration(300)
- .setInterpolator(mDisappearAnimationUtils.getInterpolator())
- .translationY(-mDisappearAnimationUtils.getStartTranslation());
+ AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 300 /* duration */,
+ -mDisappearAnimationUtils.getStartTranslation(),
+ mDisappearAnimationUtils.getInterpolator());
mDisappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
new Runnable() {
@Override
@@ -398,43 +397,16 @@
long duration, float translationY, final boolean appearing,
Interpolator interpolator,
final Runnable finishListener) {
- if (appearing) {
- animatedCell.scale = 0.0f;
- animatedCell.alpha = 1.0f;
- }
- animatedCell.translateY = appearing ? translationY : 0;
- ValueAnimator animator = ValueAnimator.ofFloat(animatedCell.translateY,
- appearing ? 0 : translationY);
- animator.setInterpolator(interpolator);
- animator.setDuration(duration);
- animator.setStartDelay(delay);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float animatedFraction = animation.getAnimatedFraction();
- if (appearing) {
- animatedCell.scale = animatedFraction;
- } else {
- animatedCell.alpha = 1 - animatedFraction;
- }
- animatedCell.translateY = (float) animation.getAnimatedValue();
- mLockPatternView.invalidate();
- }
- });
+ mLockPatternView.startCellStateAnimation(animatedCell,
+ 1f, appearing ? 1f : 0f, /* alpha */
+ appearing ? translationY : 0f, appearing ? 0f : translationY, /* translation */
+ appearing ? 0f : 1f, 1f /* scale */,
+ delay, duration, interpolator, finishListener);
if (finishListener != null) {
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finishListener.run();
- }
- });
-
// Also animate the Emergency call
mAppearAnimationUtils.createAnimation(mEcaView, delay, duration, translationY,
appearing, interpolator, null);
}
- animator.start();
- mLockPatternView.invalidate();
}
@Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java b/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java
index 441474d..df76125 100644
--- a/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java
@@ -16,11 +16,18 @@
package com.android.settingslib.animation;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.view.RenderNodeAnimator;
import android.view.View;
+import android.view.ViewPropertyAnimator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import com.android.internal.widget.LockPatternView;
import com.android.settingslib.R;
/**
@@ -174,26 +181,65 @@
}
@Override
- public void createAnimation(View view, long delay, long duration, float translationY,
- boolean appearing, Interpolator interpolator, Runnable endRunnable) {
+ public void createAnimation(final View view, long delay, long duration, float translationY,
+ boolean appearing, Interpolator interpolator, final Runnable endRunnable) {
if (view != null) {
view.setAlpha(appearing ? 0f : 1.0f);
view.setTranslationY(appearing ? translationY : 0);
- view.animate()
- .alpha(appearing ? 1f : 0f)
- .translationY(appearing ? 0 : translationY)
- .setInterpolator(interpolator)
- .setDuration(duration)
- .setStartDelay(delay);
+ Animator alphaAnim;
+ float targetAlpha = appearing ? 1f : 0f;
+ if (view.isHardwareAccelerated()) {
+ RenderNodeAnimator alphaAnimRt = new RenderNodeAnimator(RenderNodeAnimator.ALPHA,
+ targetAlpha);
+ alphaAnimRt.setTarget(view);
+ alphaAnim = alphaAnimRt;
+ } else {
+ alphaAnim = ObjectAnimator.ofFloat(view, View.ALPHA, view.getAlpha(), targetAlpha);
+ }
+ alphaAnim.setInterpolator(interpolator);
+ alphaAnim.setDuration(duration);
+ alphaAnim.setStartDelay(delay);
if (view.hasOverlappingRendering()) {
- view.animate().withLayer();
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ });
}
if (endRunnable != null) {
- view.animate().withEndAction(endRunnable);
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endRunnable.run();
+ }
+ });
}
+ alphaAnim.start();
+ startTranslationYAnimation(view, delay, duration, appearing ? 0 : translationY,
+ interpolator);
}
}
+ public static void startTranslationYAnimation(View view, long delay, long duration,
+ float endTranslationY, Interpolator interpolator) {
+ Animator translationAnim;
+ if (view.isHardwareAccelerated()) {
+ RenderNodeAnimator translationAnimRt = new RenderNodeAnimator(
+ RenderNodeAnimator.TRANSLATION_Y, endTranslationY);
+ translationAnimRt.setTarget(view);
+ translationAnim = translationAnimRt;
+ } else {
+ translationAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y,
+ view.getTranslationY(), endTranslationY);
+ }
+ translationAnim.setInterpolator(interpolator);
+ translationAnim.setDuration(duration);
+ translationAnim.setStartDelay(delay);
+ translationAnim.start();
+ }
+
public class AppearAnimationProperties {
public long[][] delays;
public int maxDelayRowIndex;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 03bdf97..56e3032 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -26,11 +26,13 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewRootImpl;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
@@ -42,6 +44,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.DejankUtils;
import com.android.systemui.EventLogConstants;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
@@ -79,6 +82,8 @@
private static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
+ private static final Rect mDummyDirtyRect = new Rect(0, 0, 1, 1);
+
public static final long DOZE_ANIMATION_DURATION = 700;
private KeyguardAffordanceHelper mAfforanceHelper;
@@ -1777,7 +1782,22 @@
mIsExpanding = false;
mScrollYOverride = -1;
if (isFullyCollapsed()) {
- setListening(false);
+ DejankUtils.postAfterTraversal(new Runnable() {
+ @Override
+ public void run() {
+ setListening(false);
+ }
+ });
+
+ // Workaround b/22639032: Make sure we invalidate something because else RenderThread
+ // thinks we are actually drawing a frame put in reality we don't, so RT doesn't go
+ // ahead with rendering and we jank.
+ postOnAnimation(new Runnable() {
+ @Override
+ public void run() {
+ getParent().invalidateChild(NotificationPanelView.this, mDummyDirtyRect);
+ }
+ });
} else {
setListening(true);
}