Implemented new camera affordance
Also fixed a bug in the touch logic where you could close the shade / hint
after going to the camera / phone.
Bug: 15126905
Change-Id: Iadfde56cb68f4048868eedec6bd3456f55823cd9
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
new file mode 100644
index 0000000..a8a0cb1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -0,0 +1,479 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.os.PowerManager;
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.FlingAnimationUtils;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
+
+/**
+ * A touch handler of the keyguard which is responsible for launching phone and camera affordances.
+ */
+public class KeyguardAffordanceHelper {
+
+ public static final float SWIPE_RESTING_ALPHA_AMOUNT = 0.5f;
+ public static final long HINT_PHASE1_DURATION = 200;
+ private static final long HINT_PHASE2_DURATION = 350;
+ private static final float BACKGROUND_RADIUS_SCALE_FACTOR = 0.15f;
+ private static final int HINT_CIRCLE_OPEN_DURATION = 500;
+
+ private final Context mContext;
+
+ private FlingAnimationUtils mFlingAnimationUtils;
+ private Callback mCallback;
+ private int mTrackingPointer;
+ private VelocityTracker mVelocityTracker;
+ private boolean mSwipingInProgress;
+ private float mInitialTouchX;
+ private float mInitialTouchY;
+ private float mTranslation;
+ private float mTranslationOnDown;
+ private int mTouchSlop;
+ private int mMinTranslationAmount;
+ private int mMinFlingVelocity;
+ private int mHintGrowAmount;
+ private final KeyguardAffordanceView mLeftIcon;
+ private final KeyguardAffordanceView mCenterIcon;
+ private final KeyguardAffordanceView mRightIcon;
+ private Interpolator mAppearInterpolator;
+ private Interpolator mDisappearInterpolator;
+ private Animator mSwipeAnimator;
+ private int mMinBackgroundRadius;
+ private boolean mMotionPerformedByUser;
+ private PowerManager mPM;
+ private AnimatorListenerAdapter mFlingEndListener = new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSwipeAnimator = null;
+ setSwipingInProgress(false);
+ }
+ };
+ private Runnable mAnimationEndRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onAnimationToSideEnded();
+ }
+ };
+
+ KeyguardAffordanceHelper(Callback callback, Context context) {
+ mContext = context;
+ mCallback = callback;
+ mLeftIcon = mCallback.getLeftIcon();
+ mLeftIcon.setIsLeft(true);
+ mCenterIcon = mCallback.getCenterIcon();
+ mRightIcon = mCallback.getRightIcon();
+ updateIcon(mLeftIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
+ updateIcon(mCenterIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
+ updateIcon(mRightIcon, 0.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
+ initDimens();
+ mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ }
+
+ private void initDimens() {
+ final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+ mTouchSlop = configuration.getScaledTouchSlop();
+ mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
+ mMinTranslationAmount = mContext.getResources().getDimensionPixelSize(
+ R.dimen.keyguard_min_swipe_amount);
+ mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize(
+ R.dimen.keyguard_affordance_min_background_radius);
+ mHintGrowAmount =
+ mContext.getResources().getDimensionPixelSize(R.dimen.hint_grow_amount_sideways);
+ mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
+ mAppearInterpolator = AnimationUtils.loadInterpolator(mContext,
+ android.R.interpolator.linear_out_slow_in);
+ mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
+ android.R.interpolator.fast_out_linear_in);
+ }
+
+ public boolean onTouchEvent(MotionEvent event) {
+ int pointerIndex = event.findPointerIndex(mTrackingPointer);
+ if (pointerIndex < 0) {
+ pointerIndex = 0;
+ mTrackingPointer = event.getPointerId(pointerIndex);
+ }
+ final float y = event.getY(pointerIndex);
+ final float x = event.getX(pointerIndex);
+
+ boolean isUp = false;
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ if (mSwipingInProgress) {
+ cancelAnimation();
+ }
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ mTranslationOnDown = mTranslation;
+ initVelocityTracker();
+ trackMovement(event);
+ mMotionPerformedByUser = false;
+ break;
+
+ case MotionEvent.ACTION_POINTER_UP:
+ final int upPointer = event.getPointerId(event.getActionIndex());
+ if (mTrackingPointer == upPointer) {
+ // gesture is ongoing, find a new pointer to track
+ final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
+ final float newY = event.getY(newIndex);
+ final float newX = event.getX(newIndex);
+ mTrackingPointer = event.getPointerId(newIndex);
+ mInitialTouchY = newY;
+ mInitialTouchX = newX;
+ mTranslationOnDown = mTranslation;
+ }
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ final float w = x - mInitialTouchX;
+ trackMovement(event);
+ if (((leftSwipePossible() && w > mTouchSlop)
+ || (rightSwipePossible() && w < -mTouchSlop))
+ && Math.abs(w) > Math.abs(y - mInitialTouchY)
+ && !mSwipingInProgress) {
+ cancelAnimation();
+ mInitialTouchY = y;
+ mInitialTouchX = x;
+ mTranslationOnDown = mTranslation;
+ setSwipingInProgress(true);
+ }
+ if (mSwipingInProgress) {
+ setTranslation(mTranslationOnDown + x - mInitialTouchX, false, false);
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ isUp = true;
+ case MotionEvent.ACTION_CANCEL:
+ mTrackingPointer = -1;
+ trackMovement(event);
+ if (mSwipingInProgress) {
+ flingWithCurrentVelocity(!isUp);
+ }
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ }
+ break;
+ }
+ return true;
+ }
+
+ private void setSwipingInProgress(boolean inProgress) {
+ mSwipingInProgress = inProgress;
+ if (inProgress) {
+ mCallback.onSwipingStarted();
+ }
+ }
+
+ private boolean rightSwipePossible() {
+ return mRightIcon.getVisibility() == View.VISIBLE;
+ }
+
+ private boolean leftSwipePossible() {
+ return mLeftIcon.getVisibility() == View.VISIBLE;
+ }
+
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return false;
+ }
+
+ public void startHintAnimation(boolean right, Runnable onFinishedListener) {
+
+ startHintAnimationPhase1(right, onFinishedListener);
+ }
+
+ private void startHintAnimationPhase1(final boolean right, final Runnable onFinishedListener) {
+ final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
+ targetView.showArrow(true);
+ ValueAnimator animator = getAnimatorToRadius(right, mHintGrowAmount);
+ animator.addListener(new AnimatorListenerAdapter() {
+ private boolean mCancelled;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mCancelled) {
+ mSwipeAnimator = null;
+ onFinishedListener.run();
+ targetView.showArrow(false);
+ } else {
+ startUnlockHintAnimationPhase2(right, onFinishedListener);
+ }
+ }
+ });
+ animator.setInterpolator(mAppearInterpolator);
+ animator.setDuration(HINT_PHASE1_DURATION);
+ animator.start();
+ mSwipeAnimator = animator;
+ }
+
+ /**
+ * Phase 2: Move back.
+ */
+ private void startUnlockHintAnimationPhase2(boolean right, final Runnable onFinishedListener) {
+ final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
+ ValueAnimator animator = getAnimatorToRadius(right, 0);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSwipeAnimator = null;
+ targetView.showArrow(false);
+ onFinishedListener.run();
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ targetView.showArrow(false);
+ }
+ });
+ animator.setInterpolator(mDisappearInterpolator);
+ animator.setDuration(HINT_PHASE2_DURATION);
+ animator.setStartDelay(HINT_CIRCLE_OPEN_DURATION);
+ animator.start();
+ mSwipeAnimator = animator;
+ }
+
+ private ValueAnimator getAnimatorToRadius(final boolean right, int radius) {
+ final KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
+ ValueAnimator animator = ValueAnimator.ofFloat(targetView.getCircleRadius(), radius);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float newRadius = (float) animation.getAnimatedValue();
+ targetView.setCircleRadiusWithoutAnimation(newRadius);
+ float translation = getTranslationFromRadius(newRadius);
+ mTranslation = right ? -translation : translation;
+ updateIconsFromRadius(targetView, newRadius);
+ }
+ });
+ return animator;
+ }
+
+ private void cancelAnimation() {
+ if (mSwipeAnimator != null) {
+ mSwipeAnimator.cancel();
+ }
+ }
+
+ private void flingWithCurrentVelocity(boolean forceSnapBack) {
+ float vel = getCurrentVelocity();
+
+ // We snap back if the current translation is not far enough
+ boolean snapBack = Math.abs(mTranslation) < Math.abs(mTranslationOnDown)
+ + mMinTranslationAmount;
+
+ // or if the velocity is in the opposite direction.
+ boolean velIsInWrongDirection = vel * mTranslation < 0;
+ snapBack |= Math.abs(vel) > mMinFlingVelocity && velIsInWrongDirection;
+ vel = snapBack ^ velIsInWrongDirection ? 0 : vel;
+ fling(vel, snapBack || forceSnapBack);
+ }
+
+ private void fling(float vel, final boolean snapBack) {
+ float target = mTranslation < 0 ? -mCallback.getPageWidth() : mCallback.getPageWidth();
+ target = snapBack ? 0 : target;
+
+ ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target);
+ mFlingAnimationUtils.apply(animator, mTranslation, target, vel);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mTranslation = (float) animation.getAnimatedValue();
+ }
+ });
+ animator.addListener(mFlingEndListener);
+ if (!snapBack) {
+ startFinishingCircleAnimation(vel * 0.375f, mAnimationEndRunnable);
+ mCallback.onAnimationToSideStarted(mTranslation < 0);
+ } else {
+ reset(true);
+ }
+ animator.start();
+ mSwipeAnimator = animator;
+ }
+
+ private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable) {
+ KeyguardAffordanceView targetView = mTranslation > 0 ? mLeftIcon : mRightIcon;
+ targetView.finishAnimation(velocity, mAnimationEndRunnable);
+ }
+
+ private void setTranslation(float translation, boolean isReset, boolean animateReset) {
+ translation = rightSwipePossible() ? translation : Math.max(0, translation);
+ translation = leftSwipePossible() ? translation : Math.min(0, translation);
+ float absTranslation = Math.abs(translation);
+ if (absTranslation > Math.abs(mTranslationOnDown) + mMinTranslationAmount ||
+ mMotionPerformedByUser) {
+ userActivity();
+ mMotionPerformedByUser = true;
+ }
+ if (translation != mTranslation || isReset) {
+ KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon;
+ KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon;
+ float alpha = absTranslation / mMinTranslationAmount;
+
+ // We interpolate the alpha of the other icons to 0
+ float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha);
+ fadeOutAlpha = Math.max(0.0f, fadeOutAlpha);
+
+ // We interpolate the alpha of the targetView to 1
+ alpha = fadeOutAlpha + alpha;
+
+ boolean animateIcons = isReset && animateReset;
+ float radius = getRadiusFromTranslation(absTranslation);
+ if (!isReset) {
+ updateIcon(targetView, radius, alpha, false);
+ } else {
+ updateIcon(targetView, 0.0f, fadeOutAlpha, animateIcons);
+ }
+ updateIcon(otherView, 0.0f, fadeOutAlpha, animateIcons);
+ updateIcon(mCenterIcon, 0.0f, fadeOutAlpha, animateIcons);
+
+ mTranslation = translation;
+ }
+ }
+
+ private void updateIconsFromRadius(KeyguardAffordanceView targetView, float newRadius) {
+ float alpha = newRadius / mMinBackgroundRadius;
+
+ // We interpolate the alpha of the other icons to 0
+ float fadeOutAlpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - alpha);
+ fadeOutAlpha = Math.max(0.0f, fadeOutAlpha);
+
+ // We interpolate the alpha of the targetView to 1
+ alpha = fadeOutAlpha + alpha;
+ KeyguardAffordanceView otherView = targetView == mRightIcon ? mLeftIcon : mRightIcon;
+ updateIconAlpha(targetView, alpha, false);
+ updateIconAlpha(otherView, fadeOutAlpha, false);
+ updateIconAlpha(mCenterIcon, fadeOutAlpha, false);
+ }
+
+ private float getTranslationFromRadius(float circleSize) {
+ float translation = (circleSize - mMinBackgroundRadius) / BACKGROUND_RADIUS_SCALE_FACTOR;
+ return Math.max(0, translation);
+ }
+
+ private float getRadiusFromTranslation(float translation) {
+ return translation * BACKGROUND_RADIUS_SCALE_FACTOR + mMinBackgroundRadius;
+ }
+
+
+ private void userActivity() {
+ mPM.userActivity(SystemClock.uptimeMillis(), false);
+ }
+
+ public void animateHideLeftRightIcon() {
+ updateIcon(mRightIcon, 0f, 0f, true);
+ updateIcon(mLeftIcon, 0f, 0f, true);
+ }
+
+ private void updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha,
+ boolean animate) {
+ if (view.getVisibility() != View.VISIBLE) {
+ return;
+ }
+ view.setCircleRadius(circleRadius);
+ updateIconAlpha(view, alpha, animate);
+ }
+
+ private void updateIconAlpha(KeyguardAffordanceView view, float alpha, boolean animate) {
+ float scale = getScale(alpha);
+ alpha = Math.min(1.0f, alpha);
+ view.setImageAlpha(alpha, animate);
+ view.setImageScale(scale, animate);
+ }
+
+ private float getScale(float alpha) {
+ float scale = alpha / SWIPE_RESTING_ALPHA_AMOUNT * 0.2f +
+ KeyguardAffordanceView.MIN_ICON_SCALE_AMOUNT;
+ return Math.min(scale, KeyguardAffordanceView.MAX_ICON_SCALE_AMOUNT);
+ }
+
+ private void trackMovement(MotionEvent event) {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.addMovement(event);
+ }
+ }
+
+ private void initVelocityTracker() {
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ }
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+
+ private float getCurrentVelocity() {
+ if (mVelocityTracker == null) {
+ return 0;
+ }
+ mVelocityTracker.computeCurrentVelocity(1000);
+ return mVelocityTracker.getXVelocity();
+ }
+
+ public void onConfigurationChanged() {
+ initDimens();
+ }
+
+ public void reset(boolean animate) {
+ if (mSwipeAnimator != null) {
+ mSwipeAnimator.cancel();
+ }
+ setTranslation(0.0f, true, animate);
+ setSwipingInProgress(false);
+ }
+
+ public interface Callback {
+
+ /**
+ * Notifies the callback when an animation to a side page was started.
+ *
+ * @param rightPage Is the page animated to the right page?
+ */
+ void onAnimationToSideStarted(boolean rightPage);
+
+ /**
+ * Notifies the callback the animation to a side page has ended.
+ */
+ void onAnimationToSideEnded();
+
+ float getPageWidth();
+
+ void onSwipingStarted();
+
+ KeyguardAffordanceView getLeftIcon();
+
+ KeyguardAffordanceView getCenterIcon();
+
+ KeyguardAffordanceView getRightIcon();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 74bc698..b9f012c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -39,6 +39,7 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
@@ -56,9 +57,9 @@
new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
- private ImageView mCameraImageView;
- private ImageView mPhoneImageView;
- private ImageView mLockIcon;
+ private KeyguardAffordanceView mCameraImageView;
+ private KeyguardAffordanceView mPhoneImageView;
+ private KeyguardAffordanceView mLockIcon;
private View mIndicationText;
private ActivityStarter mActivityStarter;
@@ -87,9 +88,9 @@
protected void onFinishInflate() {
super.onFinishInflate();
mLockPatternUtils = new LockPatternUtils(mContext);
- mCameraImageView = (ImageView) findViewById(R.id.camera_button);
- mPhoneImageView = (ImageView) findViewById(R.id.phone_button);
- mLockIcon = (ImageView) findViewById(R.id.lock_icon);
+ mCameraImageView = (KeyguardAffordanceView) findViewById(R.id.camera_button);
+ mPhoneImageView = (KeyguardAffordanceView) findViewById(R.id.phone_button);
+ mLockIcon = (KeyguardAffordanceView) findViewById(R.id.lock_icon);
mIndicationText = findViewById(R.id.keyguard_indication_text);
watchForCameraPolicyChanges();
watchForAccessibilityChanges();
@@ -98,6 +99,8 @@
mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
mUnlockMethodCache.addListener(this);
updateTrust();
+ setClipChildren(false);
+ setClipToPadding(false);
}
public void setActivityStarter(ActivityStarter activityStarter) {
@@ -228,15 +231,15 @@
mLockIcon.setImageResource(iconRes);
}
- public ImageView getPhoneImageView() {
+ public KeyguardAffordanceView getPhoneView() {
return mPhoneImageView;
}
- public ImageView getCameraImageView() {
+ public KeyguardAffordanceView getCameraView() {
return mCameraImageView;
}
- public ImageView getLockIcon() {
+ public KeyguardAffordanceView getLockIcon() {
return mLockIcon;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
deleted file mode 100644
index d5f9619..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java
+++ /dev/null
@@ -1,496 +0,0 @@
-/*
- * 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.systemui.statusbar.phone;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.os.PowerManager;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.view.ViewPropertyAnimator;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.R;
-import com.android.systemui.statusbar.FlingAnimationUtils;
-
-import java.util.ArrayList;
-
-/**
- * A touch handler of the Keyguard which is responsible for swiping the content left or right.
- */
-public class KeyguardPageSwipeHelper {
-
- private static final float SWIPE_MAX_ICON_SCALE_AMOUNT = 2.0f;
- public static final float SWIPE_RESTING_ALPHA_AMOUNT = 0.5f;
- public static final long HINT_PHASE1_DURATION = 250;
- private static final long HINT_PHASE2_DURATION = 450;
-
- private final Context mContext;
-
- private FlingAnimationUtils mFlingAnimationUtils;
- private Callback mCallback;
- private int mTrackingPointer;
- private VelocityTracker mVelocityTracker;
- private boolean mSwipingInProgress;
- private float mInitialTouchX;
- private float mInitialTouchY;
- private float mTranslation;
- private float mTranslationOnDown;
- private int mTouchSlop;
- private int mMinTranslationAmount;
- private int mMinFlingVelocity;
- private int mHintDistance;
- private final View mLeftIcon;
- private final View mCenterIcon;
- private final View mRightIcon;
- private Interpolator mFastOutSlowIn;
- private Interpolator mBounceInterpolator;
- private Animator mSwipeAnimator;
- private boolean mCallbackCalled;
-
- KeyguardPageSwipeHelper(Callback callback, Context context) {
- mContext = context;
- mCallback = callback;
- mLeftIcon = mCallback.getLeftIcon();
- mCenterIcon = mCallback.getCenterIcon();
- mRightIcon = mCallback.getRightIcon();
- updateIcon(mLeftIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
- updateIcon(mCenterIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
- updateIcon(mRightIcon, 1.0f, SWIPE_RESTING_ALPHA_AMOUNT, false);
- initDimens();
- }
-
- private void initDimens() {
- final ViewConfiguration configuration = ViewConfiguration.get(mContext);
- mTouchSlop = configuration.getScaledTouchSlop();
- mMinFlingVelocity = configuration.getScaledMinimumFlingVelocity();
- mMinTranslationAmount = mContext.getResources().getDimensionPixelSize(
- R.dimen.keyguard_min_swipe_amount);
- mHintDistance =
- mContext.getResources().getDimensionPixelSize(R.dimen.hint_move_distance_sideways);
- mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.4f);
- mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
- android.R.interpolator.fast_out_slow_in);
- mBounceInterpolator = new BounceInterpolator();
- }
-
- public boolean onTouchEvent(MotionEvent event) {
- int pointerIndex = event.findPointerIndex(mTrackingPointer);
- if (pointerIndex < 0) {
- pointerIndex = 0;
- mTrackingPointer = event.getPointerId(pointerIndex);
- }
- final float y = event.getY(pointerIndex);
- final float x = event.getX(pointerIndex);
-
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN:
- if (mSwipingInProgress) {
- cancelAnimations();
- }
- mInitialTouchY = y;
- mInitialTouchX = x;
- mTranslationOnDown = mTranslation;
- initVelocityTracker();
- trackMovement(event);
- break;
-
- case MotionEvent.ACTION_POINTER_UP:
- final int upPointer = event.getPointerId(event.getActionIndex());
- if (mTrackingPointer == upPointer) {
- // gesture is ongoing, find a new pointer to track
- final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
- final float newY = event.getY(newIndex);
- final float newX = event.getX(newIndex);
- mTrackingPointer = event.getPointerId(newIndex);
- mInitialTouchY = newY;
- mInitialTouchX = newX;
- mTranslationOnDown = mTranslation;
- }
- break;
-
- case MotionEvent.ACTION_MOVE:
- final float w = x - mInitialTouchX;
- trackMovement(event);
- if (((leftSwipePossible() && w > mTouchSlop)
- || (rightSwipePossible() && w < -mTouchSlop))
- && Math.abs(w) > Math.abs(y - mInitialTouchY)
- && !mSwipingInProgress) {
- cancelAnimations();
- mInitialTouchY = y;
- mInitialTouchX = x;
- mTranslationOnDown = mTranslation;
- mSwipingInProgress = true;
- }
- if (mSwipingInProgress) {
- setTranslation(mTranslationOnDown + x - mInitialTouchX, false);
- }
- break;
-
- case MotionEvent.ACTION_UP:
- case MotionEvent.ACTION_CANCEL:
- mTrackingPointer = -1;
- trackMovement(event);
- if (mSwipingInProgress) {
- flingWithCurrentVelocity();
- }
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- break;
- }
- return true;
- }
-
- private boolean rightSwipePossible() {
- return mRightIcon.getVisibility() == View.VISIBLE;
- }
-
- private boolean leftSwipePossible() {
- return mLeftIcon.getVisibility() == View.VISIBLE;
- }
-
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- return false;
- }
-
- public void startHintAnimation(boolean right, Runnable onFinishedListener) {
- startHintAnimationPhase1(right, onFinishedListener);
- }
-
- /**
- * Phase 1: Move everything sidewards.
- */
- private void startHintAnimationPhase1(boolean right, final Runnable onFinishedListener) {
- float target = right ? -mHintDistance : mHintDistance;
- startHintTranslationAnimations(target, HINT_PHASE1_DURATION, mFastOutSlowIn);
- ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mTranslation = (float) animation.getAnimatedValue();
- }
- });
- animator.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (mCancelled) {
- mSwipeAnimator = null;
- onFinishedListener.run();
- } else {
- startUnlockHintAnimationPhase2(onFinishedListener);
- }
- }
- });
- animator.setInterpolator(mFastOutSlowIn);
- animator.setDuration(HINT_PHASE1_DURATION);
- animator.start();
- mSwipeAnimator = animator;
- }
-
- /**
- * Phase 2: Move back.
- */
- private void startUnlockHintAnimationPhase2(final Runnable onFinishedListener) {
- startHintTranslationAnimations(0f /* target */, HINT_PHASE2_DURATION, mBounceInterpolator);
- ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, 0f);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mTranslation = (float) animation.getAnimatedValue();
- }
- });
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mSwipeAnimator = null;
- onFinishedListener.run();
- }
- });
- animator.setInterpolator(mBounceInterpolator);
- animator.setDuration(HINT_PHASE2_DURATION);
- animator.start();
- mSwipeAnimator = animator;
- }
-
- private void startHintTranslationAnimations(float target, long duration,
- Interpolator interpolator) {
- ArrayList<View> targetViews = mCallback.getTranslationViews();
- for (View targetView : targetViews) {
- targetView.animate()
- .setDuration(duration)
- .setInterpolator(interpolator)
- .translationX(target);
- }
- }
-
- private void cancelAnimations() {
- ArrayList<View> targetViews = mCallback.getTranslationViews();
- for (View target : targetViews) {
- target.animate().cancel();
- }
- View targetView = mTranslation > 0 ? mLeftIcon : mRightIcon;
- targetView.animate().cancel();
- if (mSwipeAnimator != null) {
- mSwipeAnimator.cancel();
- hideInactiveIcons(true);
- }
- }
-
- private void flingWithCurrentVelocity() {
- float vel = getCurrentVelocity();
-
- // We snap back if the current translation is not far enough
- boolean snapBack = Math.abs(mTranslation) < mMinTranslationAmount;
-
- // or if the velocity is in the opposite direction.
- boolean velIsInWrongDirection = vel * mTranslation < 0;
- snapBack |= Math.abs(vel) > mMinFlingVelocity && velIsInWrongDirection;
- vel = snapBack ^ velIsInWrongDirection ? 0 : vel;
- fling(vel, snapBack);
- }
-
- private void fling(float vel, final boolean snapBack) {
- float target = mTranslation < 0 ? -mCallback.getPageWidth() : mCallback.getPageWidth();
- target = snapBack ? 0 : target;
-
- // translation Animation
- startTranslationAnimations(vel, target);
-
- // animate left / right icon
- startIconAnimation(vel, snapBack, target);
-
- ValueAnimator animator = ValueAnimator.ofFloat(mTranslation, target);
- mFlingAnimationUtils.apply(animator, mTranslation, target, vel);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mTranslation = (float) animation.getAnimatedValue();
- }
- });
- animator.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- mSwipeAnimator = null;
- mSwipingInProgress = false;
- if (!snapBack && !mCallbackCalled && !mCancelled) {
-
- // ensure that the callback is called eventually
- mCallback.onAnimationToSideStarted(mTranslation < 0);
- mCallbackCalled = true;
- }
- }
- });
- if (!snapBack) {
- mCallbackCalled = false;
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- int frameNumber;
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- if (frameNumber == 2 && !mCallbackCalled) {
-
- // we have to wait for the second frame for this call,
- // until the render thread has definitely kicked in, to avoid a lag.
- mCallback.onAnimationToSideStarted(mTranslation < 0);
- mCallbackCalled = true;
- }
- frameNumber++;
- }
- });
- } else {
- showAllIcons(true);
- }
- animator.start();
- mSwipeAnimator = animator;
- }
-
- private void startTranslationAnimations(float vel, float target) {
- ArrayList<View> targetViews = mCallback.getTranslationViews();
- for (View targetView : targetViews) {
- ViewPropertyAnimator animator = targetView.animate();
- mFlingAnimationUtils.apply(animator, mTranslation, target, vel);
- animator.translationX(target);
- }
- }
-
- private void startIconAnimation(float vel, boolean snapBack, float target) {
- float scale = snapBack ? 1.0f : SWIPE_MAX_ICON_SCALE_AMOUNT;
- float alpha = snapBack ? SWIPE_RESTING_ALPHA_AMOUNT : 1.0f;
- View targetView = mTranslation > 0
- ? mLeftIcon
- : mRightIcon;
- if (targetView.getVisibility() == View.VISIBLE) {
- ViewPropertyAnimator iconAnimator = targetView.animate();
- mFlingAnimationUtils.apply(iconAnimator, mTranslation, target, vel);
- iconAnimator.scaleX(scale);
- iconAnimator.scaleY(scale);
- iconAnimator.alpha(alpha);
- }
- }
-
- private void setTranslation(float translation, boolean isReset) {
- translation = rightSwipePossible() ? translation : Math.max(0, translation);
- translation = leftSwipePossible() ? translation : Math.min(0, translation);
- if (translation != mTranslation || isReset) {
- ArrayList<View> translatedViews = mCallback.getTranslationViews();
- for (View view : translatedViews) {
- view.setTranslationX(translation);
- }
- if (translation == 0.0f) {
- boolean animate = !isReset;
- showAllIcons(animate);
- } else {
- View targetView = translation > 0 ? mLeftIcon : mRightIcon;
- float progress = Math.abs(translation) / mCallback.getPageWidth();
- progress = Math.min(progress, 1.0f);
- float alpha = SWIPE_RESTING_ALPHA_AMOUNT * (1.0f - progress) + progress;
- float scale = (1.0f - progress) + progress * SWIPE_MAX_ICON_SCALE_AMOUNT;
- updateIcon(targetView, scale, alpha, false);
- View otherView = translation < 0 ? mLeftIcon : mRightIcon;
- if (mTranslation * translation <= 0) {
- // The sign of the translation has changed so we need to hide the other icons
- updateIcon(otherView, 0, 0, true);
- updateIcon(mCenterIcon, 0, 0, true);
- }
- }
- mTranslation = translation;
- }
- }
-
- public void showAllIcons(boolean animate) {
- float scale = 1.0f;
- float alpha = SWIPE_RESTING_ALPHA_AMOUNT;
- updateIcon(mRightIcon, scale, alpha, animate);
- updateIcon(mCenterIcon, scale, alpha, animate);
- updateIcon(mLeftIcon, scale, alpha, animate);
- }
-
- public void animateHideLeftRightIcon() {
- updateIcon(mRightIcon, 0f, 0f, true);
- updateIcon(mLeftIcon, 0f, 0f, true);
- }
-
- private void hideInactiveIcons(boolean animate){
- View otherView = mTranslation < 0 ? mLeftIcon : mRightIcon;
- updateIcon(otherView, 0, 0, animate);
- updateIcon(mCenterIcon, 0, 0, animate);
- }
-
- private void updateIcon(View view, float scale, float alpha, boolean animate) {
- if (view.getVisibility() != View.VISIBLE) {
- return;
- }
- if (!animate) {
- view.animate().cancel();
- view.setAlpha(alpha);
- view.setScaleX(scale);
- view.setScaleY(scale);
- // TODO: remove this invalidate once the property setters invalidate it properly
- view.invalidate();
- } else {
- if (view.getAlpha() != alpha || view.getScaleX() != scale) {
- view.animate()
- .setInterpolator(mFastOutSlowIn)
- .alpha(alpha)
- .scaleX(scale)
- .scaleY(scale);
- }
- }
- }
-
- private void trackMovement(MotionEvent event) {
- if (mVelocityTracker != null) {
- mVelocityTracker.addMovement(event);
- }
- }
-
- private void initVelocityTracker() {
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- }
- mVelocityTracker = VelocityTracker.obtain();
- }
-
- private float getCurrentVelocity() {
- if (mVelocityTracker == null) {
- return 0;
- }
- mVelocityTracker.computeCurrentVelocity(1000);
- return mVelocityTracker.getXVelocity();
- }
-
- public void onConfigurationChanged() {
- initDimens();
- }
-
- public void reset() {
- if (mSwipeAnimator != null) {
- mSwipeAnimator.cancel();
- }
- ArrayList<View> targetViews = mCallback.getTranslationViews();
- for (View view : targetViews) {
- view.animate().cancel();
- }
- setTranslation(0.0f, true);
- mSwipingInProgress = false;
- }
-
- public boolean isSwipingInProgress() {
- return mSwipingInProgress;
- }
-
- public interface Callback {
-
- /**
- * Notifies the callback when an animation to a side page was started.
- *
- * @param rightPage Is the page animated to the right page?
- */
- void onAnimationToSideStarted(boolean rightPage);
-
- float getPageWidth();
-
- ArrayList<View> getTranslationViews();
-
- View getLeftIcon();
-
- View getCenterIcon();
-
- View getRightIcon();
- }
-}
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 fc0f2d5..11a38b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -39,6 +39,7 @@
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.MirrorView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -49,7 +50,7 @@
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
- KeyguardPageSwipeHelper.Callback {
+ KeyguardAffordanceHelper.Callback {
// Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
// changed.
@@ -59,7 +60,7 @@
private static final float HEADER_RUBBERBAND_FACTOR = 2.15f;
private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
- private KeyguardPageSwipeHelper mPageSwiper;
+ private KeyguardAffordanceHelper mAfforanceHelper;
private StatusBarHeaderView mHeader;
private View mQsContainer;
private QSPanel mQsPanel;
@@ -124,7 +125,6 @@
private boolean mIsExpanding;
private boolean mBlockTouches;
- private ArrayList<View> mSwipeTranslationViews = new ArrayList<>();
private int mNotificationScrimWaitDistance;
private boolean mTwoFingerQsExpand;
private boolean mTwoFingerQsExpandPossible;
@@ -135,6 +135,10 @@
*/
private int mScrollYOverride = -1;
private boolean mQsAnimatorExpand;
+ private boolean mIsLaunchTransitionFinished;
+ private boolean mIsLaunchTransitionRunning;
+ private Runnable mLaunchAnimationEndRunnable;
+ private boolean mOnlyAffordanceInThisMotion;
public NotificationPanelView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -167,9 +171,7 @@
mFastOutLinearInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_linear_in);
mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
- mSwipeTranslationViews.add(mNotificationStackScroller);
- mSwipeTranslationViews.add(mKeyguardStatusView);
- mPageSwiper = new KeyguardPageSwipeHelper(this, getContext());
+ mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
}
@Override
@@ -297,9 +299,10 @@
@Override
public void resetViews() {
+ mIsLaunchTransitionFinished = false;
mBlockTouches = false;
mUnlockIconActive = false;
- mPageSwiper.reset();
+ mAfforanceHelper.reset(true);
closeQs();
mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
true /* cancelAnimators */);
@@ -354,6 +357,7 @@
if (mBlockTouches) {
return false;
}
+ resetDownStates(event);
int pointerIndex = event.findPointerIndex(mTrackingPointer);
if (pointerIndex < 0) {
pointerIndex = 0;
@@ -430,6 +434,12 @@
return !mQsExpanded && super.onInterceptTouchEvent(event);
}
+ private void resetDownStates(MotionEvent event) {
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+ mOnlyAffordanceInThisMotion = false;
+ }
+ }
+
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
@@ -464,15 +474,14 @@
if (mBlockTouches) {
return false;
}
- // TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
- // implementation.
+ resetDownStates(event);
if ((!mIsExpanding || mHintAnimationRunning)
&& !mQsExpanded
&& mStatusBar.getBarState() != StatusBarState.SHADE) {
- mPageSwiper.onTouchEvent(event);
- if (mPageSwiper.isSwipingInProgress()) {
- return true;
- }
+ mAfforanceHelper.onTouchEvent(event);
+ }
+ if (mOnlyAffordanceInThisMotion) {
+ return true;
}
if (event.getActionMasked() == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
&& mStatusBar.getBarState() != StatusBarState.KEYGUARD) {
@@ -951,20 +960,16 @@
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
boolean active = getMaxPanelHeight() - getExpandedHeight() > mUnlockMoveDistance;
+ KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
if (active && !mUnlockIconActive && mTracking) {
- mKeyguardBottomArea.getLockIcon().animate()
- .alpha(1f)
- .scaleY(LOCK_ICON_ACTIVE_SCALE)
- .scaleX(LOCK_ICON_ACTIVE_SCALE)
- .setInterpolator(mFastOutLinearInterpolator)
- .setDuration(150);
+ lockIcon.setImageAlpha(1.0f, true, 150, mFastOutLinearInterpolator, null);
+ lockIcon.setImageScale(LOCK_ICON_ACTIVE_SCALE, true, 150,
+ mFastOutLinearInterpolator);
} else if (!active && mUnlockIconActive && mTracking) {
- mKeyguardBottomArea.getLockIcon().animate()
- .alpha(KeyguardPageSwipeHelper.SWIPE_RESTING_ALPHA_AMOUNT)
- .scaleY(1f)
- .scaleX(1f)
- .setInterpolator(mFastOutLinearInterpolator)
- .setDuration(150);
+ lockIcon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT, true,
+ 150, mFastOutLinearInterpolator, null);
+ lockIcon.setImageScale(1.0f, true, 150,
+ mFastOutLinearInterpolator);
}
mUnlockIconActive = active;
}
@@ -1093,7 +1098,7 @@
super.onTrackingStarted();
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
- mPageSwiper.animateHideLeftRightIcon();
+ mAfforanceHelper.animateHideLeftRightIcon();
}
}
@@ -1106,16 +1111,15 @@
}
if (expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
- mPageSwiper.showAllIcons(true);
+ if (!mHintAnimationRunning) {
+ mAfforanceHelper.reset(true);
+ }
}
if (!expand && (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED)) {
- mKeyguardBottomArea.getLockIcon().animate()
- .alpha(0f)
- .scaleX(2f)
- .scaleY(2f)
- .setInterpolator(mFastOutLinearInterpolator)
- .setDuration(100);
+ KeyguardAffordanceView lockIcon = mKeyguardBottomArea.getLockIcon();
+ lockIcon.setImageAlpha(0.0f, true, 100, mFastOutLinearInterpolator, null);
+ lockIcon.setImageScale(2.0f, true, 100, mFastOutLinearInterpolator);
}
}
@@ -1141,7 +1145,7 @@
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- mPageSwiper.onConfigurationChanged();
+ mAfforanceHelper.onConfigurationChanged();
}
@Override
@@ -1159,6 +1163,8 @@
@Override
public void onAnimationToSideStarted(boolean rightPage) {
boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? rightPage : !rightPage;
+ mIsLaunchTransitionRunning = true;
+ mLaunchAnimationEndRunnable = null;
if (start) {
mKeyguardBottomArea.launchPhone();
} else {
@@ -1168,20 +1174,29 @@
}
@Override
+ public void onAnimationToSideEnded() {
+ mIsLaunchTransitionRunning = false;
+ mIsLaunchTransitionFinished = true;
+ if (mLaunchAnimationEndRunnable != null) {
+ mLaunchAnimationEndRunnable.run();
+ mLaunchAnimationEndRunnable = null;
+ }
+ }
+
+ @Override
protected void onEdgeClicked(boolean right) {
if ((right && getRightIcon().getVisibility() != View.VISIBLE)
|| (!right && getLeftIcon().getVisibility() != View.VISIBLE)) {
return;
}
mHintAnimationRunning = true;
- mPageSwiper.startHintAnimation(right, new Runnable() {
+ mAfforanceHelper.startHintAnimation(right, new Runnable() {
@Override
public void run() {
mHintAnimationRunning = false;
mStatusBar.onHintFinished();
}
});
- startHighlightIconAnimation(right ? getRightIcon() : getLeftIcon());
boolean start = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? right : !right;
if (start) {
mStatusBar.onPhoneHintStarted();
@@ -1199,17 +1214,14 @@
/**
* Starts the highlight (making it fully opaque) animation on an icon.
*/
- private void startHighlightIconAnimation(final View icon) {
- icon.animate()
- .alpha(1.0f)
- .setDuration(KeyguardPageSwipeHelper.HINT_PHASE1_DURATION)
- .setInterpolator(mFastOutSlowInInterpolator)
- .withEndAction(new Runnable() {
+ private void startHighlightIconAnimation(final KeyguardAffordanceView icon) {
+ icon.setImageAlpha(1.0f, true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
+ mFastOutSlowInInterpolator, new Runnable() {
@Override
public void run() {
- icon.animate().alpha(KeyguardPageSwipeHelper.SWIPE_RESTING_ALPHA_AMOUNT)
- .setDuration(KeyguardPageSwipeHelper.HINT_PHASE1_DURATION)
- .setInterpolator(mFastOutSlowInInterpolator);
+ icon.setImageAlpha(KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT,
+ true, KeyguardAffordanceHelper.HINT_PHASE1_DURATION,
+ mFastOutSlowInInterpolator, null);
}
});
}
@@ -1220,27 +1232,28 @@
}
@Override
- public ArrayList<View> getTranslationViews() {
- return mSwipeTranslationViews;
+ public void onSwipingStarted() {
+ requestDisallowInterceptTouchEvent(true);
+ mOnlyAffordanceInThisMotion = true;
}
@Override
- public View getLeftIcon() {
+ public KeyguardAffordanceView getLeftIcon() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL
- ? mKeyguardBottomArea.getCameraImageView()
- : mKeyguardBottomArea.getPhoneImageView();
+ ? mKeyguardBottomArea.getCameraView()
+ : mKeyguardBottomArea.getPhoneView();
}
@Override
- public View getCenterIcon() {
+ public KeyguardAffordanceView getCenterIcon() {
return mKeyguardBottomArea.getLockIcon();
}
@Override
- public View getRightIcon() {
+ public KeyguardAffordanceView getRightIcon() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL
- ? mKeyguardBottomArea.getPhoneImageView()
- : mKeyguardBottomArea.getCameraImageView();
+ ? mKeyguardBottomArea.getPhoneView()
+ : mKeyguardBottomArea.getCameraView();
}
@Override
@@ -1282,4 +1295,16 @@
public boolean shouldDelayChildPressedState() {
return true;
}
+
+ public boolean isLaunchTransitionFinished() {
+ return mIsLaunchTransitionFinished;
+ }
+
+ public boolean isLaunchTransitionRunning() {
+ return mIsLaunchTransitionRunning;
+ }
+
+ public void setLaunchTransitionEndRunnable(Runnable r) {
+ mLaunchAnimationEndRunnable = r;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index e4e67c9..46a32da 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -53,7 +53,6 @@
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.Rect;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.InputMethodService;
@@ -63,6 +62,7 @@
import android.media.session.MediaSession;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
+import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -70,6 +70,7 @@
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService.RankingMap;
@@ -201,6 +202,9 @@
.setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
.build();
+ public static final int FADE_KEYGUARD_START_DELAY = 100;
+ public static final int FADE_KEYGUARD_DURATION = 300;
+
PhoneStatusBarPolicy mIconPolicy;
// These are no longer handled by the policy, because we need custom strategies for them
@@ -441,6 +445,8 @@
private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
private int mDrawCount;
+ private Runnable mLaunchTransitionEndRunnable;
+ private boolean mLaunchTransitionFadingAway;
private static final int VISIBLE_LOCATIONS = ViewState.LOCATION_FIRST_CARD
| ViewState.LOCATION_TOP_STACK_PEEKING
@@ -1728,7 +1734,8 @@
}
private int adjustDisableFlags(int state) {
- if (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit) {
+ if (!mLaunchTransitionFadingAway
+ && (mExpandedVisible || mBouncerShowing || mWaitingForKeyguardExit)) {
state |= StatusBarManager.DISABLE_NOTIFICATION_ICONS;
state |= StatusBarManager.DISABLE_SYSTEM_INFO;
}
@@ -2725,13 +2732,18 @@
dismissKeyguardThenExecute(new OnDismissAction() {
@Override
public boolean onDismiss() {
- try {
- // Dismiss the lock screen when Settings starts.
- ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
- } catch (RemoteException e) {
- }
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+ AsyncTask.execute(new Runnable() {
+ public void run() {
+ try {
+ intent.setFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ mContext.startActivityAsUser(
+ intent, new UserHandle(UserHandle.USER_CURRENT));
+ mWindowManagerService.overridePendingAppTransition(null, 0, 0, null);
+ } catch (RemoteException e) {
+ }
+ }
+ });
animateCollapsePanels();
return DELAY_DISMISS_TO_ACTIVITY_LAUNCH;
@@ -2795,9 +2807,20 @@
};
@Override
- protected void dismissKeyguardThenExecute(OnDismissAction action) {
+ protected void dismissKeyguardThenExecute(final OnDismissAction action) {
if (mStatusBarKeyguardViewManager.isShowing()) {
- mStatusBarKeyguardViewManager.dismissWithAction(action);
+ if (UnlockMethodCache.getInstance(mContext).isMethodInsecure()
+ && mNotificationPanel.isLaunchTransitionRunning()) {
+ action.onDismiss();
+ mNotificationPanel.setLaunchTransitionEndRunnable(new Runnable() {
+ @Override
+ public void run() {
+ mStatusBarKeyguardViewManager.dismiss();
+ }
+ });
+ } else {
+ mStatusBarKeyguardViewManager.dismissWithAction(action);
+ }
} else {
action.onDismiss();
}
@@ -3170,6 +3193,52 @@
mLeaveOpenOnKeyguardHide = false;
}
+ public boolean isInLaunchTransition() {
+ return mNotificationPanel.isLaunchTransitionRunning()
+ || mNotificationPanel.isLaunchTransitionFinished();
+ }
+
+ /**
+ * Fades the content of the keyguard away after the launch transition is done.
+ *
+ * @param beforeFading the runnable to be run when the circle is fully expanded and the fading
+ * starts
+ * @param endRunnable the runnable to be run when the transition is done
+ */
+ public void fadeKeyguardAfterLaunchTransition(final Runnable beforeFading,
+ final Runnable endRunnable) {
+ Runnable hideRunnable = new Runnable() {
+ @Override
+ public void run() {
+ mLaunchTransitionFadingAway = true;
+ if (beforeFading != null) {
+ beforeFading.run();
+ }
+ mNotificationPanel.setAlpha(1);
+ mNotificationPanel.animate()
+ .alpha(0)
+ .setStartDelay(FADE_KEYGUARD_START_DELAY)
+ .setDuration(FADE_KEYGUARD_DURATION)
+ .withLayer()
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ mNotificationPanel.setAlpha(1);
+ if (endRunnable != null) {
+ endRunnable.run();
+ }
+ mLaunchTransitionFadingAway = false;
+ }
+ });
+ }
+ };
+ if (mNotificationPanel.isLaunchTransitionRunning()) {
+ mNotificationPanel.setLaunchTransitionEndRunnable(hideRunnable);
+ } else {
+ hideRunnable.run();
+ }
+ }
+
public void hideKeyguard() {
setBarState(StatusBarState.SHADE);
if (mLeaveOpenOnKeyguardHide) {
@@ -3204,8 +3273,8 @@
private void updatePublicMode() {
setLockscreenPublicMode(
- (mStatusBarKeyguardViewManager.isShowing() ||
- mStatusBarKeyguardViewManager.isOccluded())
+ (mStatusBarKeyguardViewManager.isShowing() ||
+ mStatusBarKeyguardViewManager.isOccluded())
&& mStatusBarKeyguardViewManager.isSecure());
}
@@ -3315,7 +3384,7 @@
private void showBouncer() {
if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
- mWaitingForKeyguardExit = true;
+ mWaitingForKeyguardExit = mStatusBarKeyguardViewManager.isShowing();
mStatusBarKeyguardViewManager.dismiss();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index cf930bd..eb42401 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -71,7 +71,6 @@
private boolean mAnimationStarted;
private boolean mDozing;
private int mTeasesRemaining;
-
private final Interpolator mInterpolator = new DecelerateInterpolator();
public ScrimController(View scrimBehind, View scrimInFront) {
@@ -149,7 +148,10 @@
}
private void updateScrims() {
- if ((!mKeyguardShowing && !mBouncerShowing) || mAnimateKeyguardFadingOut) {
+ if (mAnimateKeyguardFadingOut) {
+ setScrimInFrontColor(0f);
+ setScrimBehindColor(0f);
+ }else if (!mKeyguardShowing && !mBouncerShowing) {
updateScrimNormal();
setScrimInFrontColor(0);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 93dcf90..af21f25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -176,6 +176,19 @@
}
public void setOccluded(boolean occluded) {
+ if (occluded && !mOccluded && mShowing) {
+ if (mPhoneStatusBar.isInLaunchTransition()) {
+ mOccluded = true;
+ mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */,
+ new Runnable() {
+ @Override
+ public void run() {
+ mStatusBarWindowManager.setKeyguardOccluded(true);
+ }
+ });
+ return;
+ }
+ }
mOccluded = occluded;
mStatusBarWindowManager.setKeyguardOccluded(occluded);
reset();
@@ -188,29 +201,50 @@
/**
* Hides the keyguard view
*/
- public void hide(long startTime, long fadeoutDuration) {
+ public void hide(long startTime, final long fadeoutDuration) {
mShowing = false;
long uptimeMillis = SystemClock.uptimeMillis();
- long delay = startTime - uptimeMillis;
- if (delay < 0) {
- delay = 0;
+ long delay = Math.max(0, startTime - uptimeMillis);
+
+ if (mPhoneStatusBar.isInLaunchTransition() ) {
+ mPhoneStatusBar.fadeKeyguardAfterLaunchTransition(new Runnable() {
+ @Override
+ public void run() {
+ mStatusBarWindowManager.setKeyguardShowing(false);
+ mStatusBarWindowManager.setKeyguardFadingAway(true);
+ mBouncer.animateHide(PhoneStatusBar.FADE_KEYGUARD_START_DELAY,
+ PhoneStatusBar.FADE_KEYGUARD_DURATION);
+ updateStates();
+ mScrimController.animateKeyguardFadingOut(
+ PhoneStatusBar.FADE_KEYGUARD_START_DELAY,
+ PhoneStatusBar.FADE_KEYGUARD_DURATION, null);
+ }
+ }, new Runnable() {
+ @Override
+ public void run() {
+ mPhoneStatusBar.hideKeyguard();
+ mStatusBarWindowManager.setKeyguardFadingAway(false);
+ mViewMediatorCallback.keyguardGone();
+ }
+ });
+ } else {
+ mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration);
+ mPhoneStatusBar.hideKeyguard();
+ mStatusBarWindowManager.setKeyguardFadingAway(true);
+ mStatusBarWindowManager.setKeyguardShowing(false);
+ mBouncer.animateHide(delay, fadeoutDuration);
+ mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() {
+ @Override
+ public void run() {
+ mStatusBarWindowManager.setKeyguardFadingAway(false);
+ mPhoneStatusBar.finishKeyguardFadingAway();
+ }
+ });
+ mViewMediatorCallback.keyguardGone();
+ updateStates();
}
- mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration);
- mPhoneStatusBar.hideKeyguard();
- mStatusBarWindowManager.setKeyguardFadingAway(true);
- mStatusBarWindowManager.setKeyguardShowing(false);
- mBouncer.animateHide(delay, fadeoutDuration);
- mScrimController.animateKeyguardFadingOut(delay, fadeoutDuration, new Runnable() {
- @Override
- public void run() {
- mStatusBarWindowManager.setKeyguardFadingAway(false);
- mPhoneStatusBar.finishKeyguardFadingAway();
- }
- });
- mViewMediatorCallback.keyguardGone();
- updateStates();
}
/**