diff options
5 files changed, 242 insertions, 82 deletions
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index 444f878..a709bb8 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.Context; 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.provider.Settings; 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 class LockPatternView extends View { } 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { 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 @@ public class LockPatternView extends View { /** * @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 @@ public class LockPatternView extends View { 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 @@ public class KeyguardPINView extends KeyguardPinBasedInputView { 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 class KeyguardPINView extends KeyguardPinBasedInputView { 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 @@ package com.android.keyguard; 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.text.TextUtils; 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 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit 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 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit 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 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit 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,24 +181,63 @@ public class AppearAnimationUtils implements AppearAnimationCreator<View> { } @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 { 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.content.res.Configuration; 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 android.widget.TextView; 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 @@ public class NotificationPanelView extends PanelView implements 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 @@ public class NotificationPanelView extends PanelView implements 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); } |