summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorSelim Cinek <cinek@google.com>2014-05-30 03:33:06 +0200
committerSelim Cinek <cinek@google.com>2014-05-30 17:29:22 +0200
commit3018197cf0dff5a9061f6065a8ecc108a0866dab (patch)
tree8face68f8cbf9341b62b6cc6b58a86dcd2d37cf9 /packages
parent6326ef4dd5fd6e03b13bf0d0f3b49aeca7580f14 (diff)
downloadframeworks_base-3018197cf0dff5a9061f6065a8ecc108a0866dab.zip
frameworks_base-3018197cf0dff5a9061f6065a8ecc108a0866dab.tar.gz
frameworks_base-3018197cf0dff5a9061f6065a8ecc108a0866dab.tar.bz2
Implemented the appear animation for the pattern security.
Also refactored AppearAnimationUtils slightly to support this. Bug: 15163546 Change-Id: I411fad20c410875dcf7bc465ea545ed90aac187e
Diffstat (limited to 'packages')
-rw-r--r--packages/Keyguard/res/values/dimens.xml2
-rw-r--r--packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java29
-rw-r--r--packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java126
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java84
4 files changed, 193 insertions, 48 deletions
diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml
index 01d9ab3..e9cdfcd 100644
--- a/packages/Keyguard/res/values/dimens.xml
+++ b/packages/Keyguard/res/values/dimens.xml
@@ -162,5 +162,5 @@
<dimen name="big_font_size">120dp</dimen>
<!-- The y translation to apply at the start in appear animations. -->
- <dimen name="appear_y_translation_start">24dp</dimen>
+ <dimen name="appear_y_translation_start">32dp</dimen>
</resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
new file mode 100644
index 0000000..0d30ea6
--- /dev/null
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationCreator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 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.keyguard;
+
+import android.animation.Animator;
+import android.view.animation.Interpolator;
+
+/**
+ * An interface which can create animations when starting an appear animation with
+ * {@link com.android.keyguard.AppearAnimationUtils}
+ */
+public interface AppearAnimationCreator<T> {
+ void createAnimation(T animatedObject, long delay, long duration,
+ float startTranslationY, Interpolator interpolator, Runnable finishListener);
+}
diff --git a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
index ea896d5..6bb1f2c 100644
--- a/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
+++ b/packages/Keyguard/src/com/android/keyguard/AppearAnimationUtils.java
@@ -16,84 +16,124 @@
package com.android.keyguard;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
import android.content.Context;
import android.view.View;
-import android.view.ViewPropertyAnimator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
/**
* A class to make nice appear transitions for views in a tabular layout.
*/
-public class AppearAnimationUtils {
+public class AppearAnimationUtils implements AppearAnimationCreator<View> {
public static final long APPEAR_DURATION = 220;
private final Interpolator mLinearOutSlowIn;
private final float mStartTranslation;
+ private final AppearAnimationProperties mProperties = new AppearAnimationProperties();
+ private final float mDelayScale;
public AppearAnimationUtils(Context ctx) {
+ this(ctx, 1.0f, 1.0f);
+ }
+
+ public AppearAnimationUtils(Context ctx, float delayScaleFactor,
+ float translationScaleFactor) {
mLinearOutSlowIn = AnimationUtils.loadInterpolator(
ctx, android.R.interpolator.linear_out_slow_in);
- mStartTranslation =
- ctx.getResources().getDimensionPixelOffset(R.dimen.appear_y_translation_start);
+ mStartTranslation = ctx.getResources().getDimensionPixelOffset(
+ R.dimen.appear_y_translation_start) * translationScaleFactor;
+ mDelayScale = delayScaleFactor;
}
- public void startAppearAnimation(View[][] views, final Runnable finishListener) {
- long maxDelay = 0;
- ViewPropertyAnimator maxDelayAnimator = null;
- for (int row = 0; row < views.length; row++) {
- View[] columns = views[row];
+ public void startAppearAnimation(View[][] objects, final Runnable finishListener) {
+ startAppearAnimation(objects, finishListener, this);
+ }
+
+ public <T> void startAppearAnimation(T[][] objects, final Runnable finishListener,
+ AppearAnimationCreator<T> creator) {
+ AppearAnimationProperties properties = getDelays(objects);
+ startAnimations(properties, objects, finishListener, creator);
+ }
+
+ private <T> void startAnimations(AppearAnimationProperties properties, T[][] objects,
+ final Runnable finishListener, AppearAnimationCreator creator) {;
+ if (properties.maxDelayRowIndex == -1 || properties.maxDelayColIndex == -1) {
+ finishListener.run();
+ return;
+ }
+ for (int row = 0; row < properties.delays.length; row++) {
+ long[] columns = properties.delays[row];
for (int col = 0; col < columns.length; col++) {
- long delay = calculateDelay(row, col);
- ViewPropertyAnimator animator = startAppearAnimation(columns[col], delay);
- if (animator != null && delay > maxDelay) {
- maxDelay = delay;
- maxDelayAnimator = animator;
+ long delay = columns[col];
+ Runnable endRunnable = null;
+ if (properties.maxDelayRowIndex == row && properties.maxDelayColIndex == col) {
+ endRunnable = finishListener;
}
+ creator.createAnimation(objects[row][col], delay, APPEAR_DURATION,
+ mStartTranslation, mLinearOutSlowIn, endRunnable);
}
}
- if (maxDelayAnimator != null) {
- maxDelayAnimator.setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finishListener.run();
- }
- });
- } else {
- finishListener.run();
- }
+
}
- private ViewPropertyAnimator startAppearAnimation(View view, long delay) {
- if (view == null) return null;
- view.setAlpha(0f);
- view.setTranslationY(mStartTranslation);
- view.animate()
- .alpha(1f)
- .translationY(0)
- .setInterpolator(mLinearOutSlowIn)
- .setDuration(APPEAR_DURATION)
- .setStartDelay(delay)
- .setListener(null);
- if (view.hasOverlappingRendering()) {
- view.animate().withLayer();
+ private <T> AppearAnimationProperties getDelays(T[][] items) {
+ long maxDelay = 0;
+ mProperties.maxDelayColIndex = -1;
+ mProperties.maxDelayRowIndex = -1;
+ mProperties.delays = new long[items.length][];
+ for (int row = 0; row < items.length; row++) {
+ T[] columns = items[row];
+ mProperties.delays[row] = new long[columns.length];
+ for (int col = 0; col < columns.length; col++) {
+ long delay = calculateDelay(row, col);
+ mProperties.delays[row][col] = delay;
+ if (items[row][col] != null && delay > maxDelay) {
+ maxDelay = delay;
+ mProperties.maxDelayColIndex = col;
+ mProperties.maxDelayRowIndex = row;
+ }
+ }
}
- return view.animate();
+ return mProperties;
}
private long calculateDelay(int row, int col) {
- return (long) (row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20);
+ return (long) ((row * 40 + col * (Math.pow(row, 0.4) + 0.4) * 20) * mDelayScale);
}
- public TimeInterpolator getInterpolator() {
+ public Interpolator getInterpolator() {
return mLinearOutSlowIn;
}
public float getStartTranslation() {
return mStartTranslation;
}
+
+ @Override
+ public void createAnimation(View view, long delay, long duration, float startTranslationY,
+ Interpolator interpolator, Runnable endRunnable) {
+ if (view != null) {
+ view.setAlpha(0f);
+ view.setTranslationY(startTranslationY);
+ view.animate()
+ .alpha(1f)
+ .translationY(0)
+ .setInterpolator(interpolator)
+ .setDuration(duration)
+ .setStartDelay(delay);
+ if (view.hasOverlappingRendering()) {
+ view.animate().withLayer();
+ }
+ if (endRunnable != null) {
+ view.animate().withEndAction(endRunnable);
+ }
+ }
+ }
+
+ public class AppearAnimationProperties {
+ public long[][] delays;
+ public int maxDelayRowIndex;
+ public int maxDelayColIndex;
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index 5853ff9..e6de72f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -21,6 +21,9 @@ import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -28,10 +31,13 @@ import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
import android.widget.Button;
import android.widget.LinearLayout;
@@ -41,7 +47,8 @@ import com.android.internal.widget.LockPatternView;
import java.io.IOException;
import java.util.List;
-public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView {
+public class KeyguardPatternView extends LinearLayout implements KeyguardSecurityView,
+ AppearAnimationCreator<LockPatternView.CellState> {
private static final String TAG = "SecurityPatternView";
private static final boolean DEBUG = KeyguardConstants.DEBUG;
@@ -59,6 +66,7 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
private static final int MIN_PATTERN_BEFORE_POKE_WAKELOCK = 2;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final AppearAnimationUtils mAppearAnimationUtils;
private CountDownTimer mCountdownTimer = null;
private LockPatternUtils mLockPatternUtils;
@@ -87,6 +95,8 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
private SecurityMessageDisplay mSecurityMessageDisplay;
private View mEcaView;
private Drawable mBouncerFrame;
+ private ViewGroup mKeyguardBouncerFrame;
+ private KeyguardMessageArea mHelpMessage;
enum FooterMode {
Normal,
@@ -101,6 +111,8 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
public KeyguardPatternView(Context context, AttributeSet attrs) {
super(context, attrs);
mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
+ mAppearAnimationUtils = new AppearAnimationUtils(context, 1.5f /* delayScale */,
+ 2.0f /* transitionScale */);
}
public void setKeyguardCallback(KeyguardSecurityCallback callback) {
@@ -148,6 +160,9 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
if (bouncerFrameView != null) {
mBouncerFrame = bouncerFrameView.getBackground();
}
+
+ mKeyguardBouncerFrame = (ViewGroup) findViewById(R.id.keyguard_bouncer_frame);
+ mHelpMessage = (KeyguardMessageArea) findViewById(R.id.keyguard_message_area);
}
private void updateFooter(FooterMode mode) {
@@ -403,8 +418,69 @@ public class KeyguardPatternView extends LinearLayout implements KeyguardSecurit
@Override
public void startAppearAnimation() {
- // TODO: Fancy animation.
- setAlpha(0);
- animate().alpha(1).withLayer().setDuration(200);
+ enableClipping(false);
+ mAppearAnimationUtils.startAppearAnimation(
+ mLockPatternView.getCellStates(),
+ new Runnable() {
+ @Override
+ public void run() {
+ enableClipping(true);
+ }
+ },
+ this);
+ if (!TextUtils.isEmpty(mHelpMessage.getText())) {
+ mAppearAnimationUtils.createAnimation(mHelpMessage, 0,
+ AppearAnimationUtils.APPEAR_DURATION,
+ mAppearAnimationUtils.getStartTranslation(),
+ mAppearAnimationUtils.getInterpolator(),
+ null /* finishRunnable */);
+ }
+ }
+
+ private void enableClipping(boolean enable) {
+ setClipChildren(enable);
+ mKeyguardBouncerFrame.setClipToPadding(enable);
+ mKeyguardBouncerFrame.setClipChildren(enable);
+ }
+
+ @Override
+ public void createAnimation(final LockPatternView.CellState animatedCell, long delay,
+ long duration, float startTranslationY, Interpolator interpolator,
+ final Runnable finishListener) {
+ animatedCell.scale = 0.0f;
+ animatedCell.translateY = startTranslationY;
+ ValueAnimator animator = ValueAnimator.ofFloat(startTranslationY, 0.0f);
+ animator.setInterpolator(interpolator);
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float animatedFraction = animation.getAnimatedFraction();
+ animatedCell.scale = animatedFraction;
+ animatedCell.translateY = (float) animation.getAnimatedValue();
+ mLockPatternView.invalidate();
+ }
+ });
+ 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, startTranslationY,
+ interpolator, null);
+
+ // And the forgot pattern button
+ if (mForgotPatternButton.getVisibility() == View.VISIBLE) {
+ mAppearAnimationUtils.createAnimation(mForgotPatternButton, delay, duration,
+ startTranslationY, interpolator, null);
+ }
+ }
+ animator.start();
+ mLockPatternView.invalidate();
}
}