Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c162dd04 authored by Jim Miller's avatar Jim Miller
Browse files

Fit and finish for camera affordance animations in keyguard

- better timing
- animate warp back when finger is released.
- Improve on/off screen animation for warped view
- Re-use existing constants for consistent timing.
- Hide the challenge area when the camera page is settling.
- Reduce jank when camera page starts snap transition.
- Prevent warping from going to previous page
- Smoothly blend between PagedView and Warp animations when scrolling starts.

Bug 10991981

Change-Id: I84822790a040a2ce2dcea60a9486f01df9cff105
parent 9dc7e12c
Loading
Loading
Loading
Loading
+16 −8
Original line number Diff line number Diff line
@@ -17,12 +17,14 @@ package com.android.keyguard;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;

public class KeyguardViewStateManager implements
        SlidingChallengeLayout.OnChallengeScrolledListener,
        ChallengeLayout.OnBouncerStateChangedListener {

    private static final String TAG = "KeyguardViewStateManager";
    private KeyguardWidgetPager mKeyguardWidgetPager;
    private ChallengeLayout mChallengeLayout;
    private KeyguardHostView mKeyguardHostView;
@@ -100,18 +102,20 @@ public class KeyguardViewStateManager implements
    }

    public void fadeOutSecurity(int duration) {
        ((View) mKeyguardSecurityContainer).animate().alpha(0).setDuration(duration);
        ((View) mKeyguardSecurityContainer).animate().alpha(0f).setDuration(duration).start();
    }

    public void fadeInSecurity(int duration) {
        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration);
        ((View) mKeyguardSecurityContainer).animate().alpha(1f).setDuration(duration).start();
    }

    public void onPageBeginMoving() {
        if (mChallengeLayout.isChallengeOverlapping() &&
                mChallengeLayout instanceof SlidingChallengeLayout) {
            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
            if (!mKeyguardWidgetPager.isWarping()) {
                scl.fadeOutChallenge();
            }
            mPageIndexOnPageBeginMoving = mKeyguardWidgetPager.getCurrentPage();
        }
        // We use mAppWidgetToShow to show a particular widget after you add it--
@@ -133,7 +137,9 @@ public class KeyguardViewStateManager implements
    public void onPageSwitching(View newPage, int newPageIndex) {
        if (mKeyguardWidgetPager != null && mChallengeLayout instanceof SlidingChallengeLayout) {
            boolean isCameraPage = newPage instanceof CameraWidgetFrame;
            ((SlidingChallengeLayout) mChallengeLayout).setChallengeInteractive(!isCameraPage);
            SlidingChallengeLayout scl = (SlidingChallengeLayout) mChallengeLayout;
            scl.setChallengeInteractive(!isCameraPage);
            if (isCameraPage) scl.fadeOutChallenge();
        }

        // If the page we're settling to is the same as we started on, and the action of
@@ -174,13 +180,15 @@ public class KeyguardViewStateManager implements
    }

    public void onPageBeginWarp() {
        // fadeOutSecurity(WARP_FADE_DURATION);
        // mKeyguardWidgetPager.showNonWarpViews(WARP_FADE_DURATION, false);
        fadeOutSecurity(SlidingChallengeLayout.CHALLENGE_FADE_OUT_DURATION);
        View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
        ((KeyguardWidgetFrame)frame).showFrame(this);
    }

    public void onPageEndWarp() {
        // fadeInSecurity(WARP_FADE_DURATION);
        // mKeyguardWidgetPager.showNonWarpViews(WARP_FADE_DURATION, true);
        fadeInSecurity(SlidingChallengeLayout.CHALLENGE_FADE_IN_DURATION);
        View frame = mKeyguardWidgetPager.getPageAt(mKeyguardWidgetPager.getPageWarpIndex());
        ((KeyguardWidgetFrame)frame).hideFrame(this);
    }

    private int getChallengeTopRelativeToFrame(KeyguardWidgetFrame frame, int top) {
+6 −4
Original line number Diff line number Diff line
@@ -188,11 +188,13 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit

    @Override
    public void onPageBeginWarp() {
        showOutlinesAndSidePages();
        mViewStateManager.onPageBeginWarp();
    }

    @Override
    public void onPageEndWarp() {
        hideOutlinesAndSidePages();
        mViewStateManager.onPageEndWarp();
    }

@@ -495,7 +497,7 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
    }

    public float getAlphaForPage(int screenCenter, int index, boolean showSidePages) {
        if (getPageWarpIndex() != -1) {
        if (isWarping()) {
            return index == getPageWarpIndex() ? 1.0f : 0.0f;
        }
        if (showSidePages) {
@@ -949,17 +951,17 @@ public class KeyguardWidgetPager extends PagedView implements PagedView.PageSwit
                    // to keep event dispatch happy.
                    mCameraEventInProgress = true;
                    userActivity();
                    startWarp(cameraPage);
                    startPageWarp(cameraPage);
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_CANCEL:
                    mCameraEventInProgress = false;
                    endWarp = true;
                    endWarp = isWarping();
                    break;
            }
            dispatchTouchEvent(event);
            // This has to happen after the event has been handled by the real widget pager
            if (endWarp) endWarp();
            if (endWarp) stopPageWarp();
        }
        endCameraEvent();
    }
+83 −26
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
@@ -60,12 +61,13 @@ import java.util.ArrayList;
 * sequential list of "pages"
 */
public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
    private static final int WARP_SNAP_DURATION = 160;
    private static final String TAG = "WidgetPagedView";
    private static final boolean DEBUG = false;
    private static final boolean DEBUG_WARP = false;
    protected static final int INVALID_PAGE = -1;
    private static final int WARP_PEEK_ANIMATION_DURATION = 250;
    private static final float WARP_ANIMATE_AMOUNT = -40.0f; // in dip
    private static final int WARP_PEEK_ANIMATION_DURATION = 150;
    private static final float WARP_ANIMATE_AMOUNT = -75.0f; // in dip

    // the min drag distance for a fling to register, to prevent random page shifts
    private static final int MIN_LENGTH_FOR_FLING = 25;
@@ -261,6 +263,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc

    private boolean mIsCameraEvent;
    private float mWarpPeekAmount;
    private boolean mAnimatingWarp; // true while warped page is being animated
    private boolean mFingerDown;

    public interface PageSwitchListener {
        void onPageSwitching(View newPage, int newPageIndex);
@@ -484,7 +488,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        if (DEBUG_WARP) Log.v(TAG, "pageBeginMoving(" + mIsPageMoving + ")");
        if (!mIsPageMoving) {
            mIsPageMoving = true;
            if (mPageWarpIndex != -1) {
            if (isWarping()) {
                onPageBeginWarp();
                if (mPageSwapIndex != -1) {
                    swapPages(mPageSwapIndex, mPageWarpIndex);
@@ -498,12 +502,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        if (DEBUG_WARP) Log.v(TAG, "pageEndMoving(" + mIsPageMoving + ")");
        if (mIsPageMoving) {
            mIsPageMoving = false;
            if (mPageWarpIndex != -1) {
            if (isWarping()) {
                if (mPageSwapIndex != -1) {
                    swapPages(mPageSwapIndex, mPageWarpIndex);
                    resetPageWarp();
                }
                onPageEndWarp();
                resetPageWarp();
            }
            onPageEndMoving();
        }
@@ -1124,8 +1128,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
            }

            case MotionEvent.ACTION_DOWN: {
                if (mIsCameraEvent) {
                    animateWarpPageOnScreen();
                if (mIsCameraEvent && !mAnimatingWarp) {
                    animateWarpPageOnScreen("interceptTouch(): DOWN");
                }
                // Remember where the motion event started
                saveDownState(ev);
@@ -1219,6 +1223,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        mTotalMotionX = 0;
        mActivePointerId = ev.getPointerId(0);

        mFingerDown = true;

        // Determine if the down event is within the threshold to be an edge swipe
        int leftEdgeBoundary = getViewportOffsetX() + mEdgeSwipeRegionSize;
        int rightEdgeBoundary = getMeasuredWidth() - getViewportOffsetX() - mEdgeSwipeRegionSize;
@@ -1393,8 +1399,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc

            if (mTouchState == TOUCH_STATE_SCROLLING) {
                pageBeginMoving();
            } else {
                animateWarpPageOnScreen();
            }

            if (mIsCameraEvent && !mAnimatingWarp) {
                animateWarpPageOnScreen("onTouch(): DOWN");
            }
            break;

@@ -1571,7 +1579,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
                // move to the left and fling to the right will register as a fling to the right.
                if (((isSignificantMove && deltaX > 0 && !isFling) ||
                        (isFling && velocityX > 0)) && mCurrentPage > 0) {
                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
                    finalPage = returnToOriginalPage || isWarping()
                            ? mCurrentPage : mCurrentPage - 1;
                    snapToPageWithVelocity(finalPage, velocityX);
                } else if (((isSignificantMove && deltaX < 0 && !isFling) ||
                        (isFling && velocityX < 0)) &&
@@ -1661,6 +1670,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        setTouchState(TOUCH_STATE_REST);
        mActivePointerId = INVALID_POINTER;
        mDownEventOnEdge = false;
        mFingerDown = false;
    }

    protected void onUnhandledTap(MotionEvent ev) {}
@@ -1790,7 +1800,14 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
    }

    protected void snapToDestination() {
        snapToPage(getPageNearestToCenterOfScreen(), PAGE_SNAP_ANIMATION_DURATION);
        if (isWarping()) {
            cancelWarpAnimation("snapToDestination");
        }
        snapToPage(getPageNearestToCenterOfScreen(), getPageSnapDuration());
    }

    private int getPageSnapDuration() {
        return isWarping() ? WARP_SNAP_DURATION : PAGE_SNAP_ANIMATION_DURATION;
    }

    private static class ScrollInterpolator implements Interpolator {
@@ -1817,6 +1834,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        whichPage = Math.max(0, Math.min(whichPage, getChildCount() - 1));
        int halfScreenSize = getViewportWidth() / 2;

        if (isWarping()) {
            cancelWarpAnimation("snapToPageWithVelocity");
        }

        if (DEBUG) Log.d(TAG, "snapToPage.getChildOffset(): " + getChildOffset(whichPage));
        if (DEBUG) Log.d(TAG, "snapToPageWithVelocity.getRelativeChildOffset(): "
                + getViewportWidth() + ", " + getChildWidth(whichPage));
@@ -1827,7 +1848,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        if (Math.abs(velocity) < mMinFlingVelocity) {
            // If the velocity is low enough, then treat this more as an automatic page advance
            // as opposed to an apparent physical response to flinging
            snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
            snapToPage(whichPage, getPageSnapDuration());
            return;
        }

@@ -1851,10 +1872,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
    }

    protected void snapToPage(int whichPage) {
        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION);
        snapToPage(whichPage, getPageSnapDuration());
    }
    protected void snapToPageImmediately(int whichPage) {
        snapToPage(whichPage, PAGE_SNAP_ANIMATION_DURATION, true);
        snapToPage(whichPage, getPageSnapDuration(), true);
    }

    protected void snapToPage(int whichPage, int duration) {
@@ -1884,8 +1905,8 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
            mNextPage = whichPage;
        }

        if (mPageWarpIndex != -1) {
            animateWarpPageOffScreen();
        if (isWarping()) {
            onPageEndWarp();
            resetPageWarp();
        }

@@ -1918,6 +1939,10 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        invalidate();
    }

    protected boolean isWarping() {
        return mPageWarpIndex != -1;
    }

    public void scrollLeft() {
        if (mScroller.isFinished()) {
            if (mCurrentPage > 0) snapToPage(mCurrentPage - 1);
@@ -2650,21 +2675,53 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        mIsCameraEvent = false;
    }

    private void animateWarpPageOnScreen() {
        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOnScreen()");
        if (mPageWarpIndex != -1) {
    AnimatorListenerAdapter mFinishWarpAnimationListener = new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            mAnimatingWarp = false;
            if (!mFingerDown) {
                animateWarpPageOffScreen("animation end", true);
            }
        }
    };

    private void cancelWarpAnimation(String msg) {
        if (DEBUG_WARP) Log.v(TAG, "cancelWarpAnimation(" + msg + ")");
        // We're done with the animation, let the scroller take over the positioning
        KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex);
        v.animate().cancel();
        v.setTranslationX(0f);
        scrollBy((int) Math.round(v.getTranslationX() - mWarpPeekAmount), 0);
    }

    private void animateWarpPageOnScreen(String reason) {
        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOnScreen(" + reason + ")");
        if (isWarping()) {
            onPageBeginWarp();
            KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex);
            if (DEBUG_WARP) Log.v(TAG, "moving page on screen: Tx=" + v.getTranslationX());
            v.animate().translationX(mWarpPeekAmount).setDuration(WARP_PEEK_ANIMATION_DURATION);
            DecelerateInterpolator interp = new DecelerateInterpolator(1.5f);
            v.animate().translationX(mWarpPeekAmount)
                    .setInterpolator(interp)
                    .setDuration(WARP_PEEK_ANIMATION_DURATION)
                    .setListener(mFinishWarpAnimationListener);
            mAnimatingWarp = true;
        }
    }

    private void animateWarpPageOffScreen() {
        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOffScreen()");
        if (mPageWarpIndex != -1) {
    private void animateWarpPageOffScreen(String reason, boolean animate) {
        if (DEBUG_WARP) Log.v(TAG, "animateWarpPageOffScreen(" + reason + " anim:" + animate + ")");
        if (isWarping()) {
            onPageEndWarp();
            KeyguardWidgetFrame v = (KeyguardWidgetFrame) getPageAt(mPageWarpIndex);
            if (DEBUG_WARP) Log.v(TAG, "moving page off screen: Tx=" + v.getTranslationX());
            v.animate().translationX(0.0f).setDuration(WARP_PEEK_ANIMATION_DURATION);
            AccelerateInterpolator interp = new AccelerateInterpolator(1.5f);
            v.animate().translationX(0.0f)
                    .setInterpolator(interp)
                    .setDuration(animate ? WARP_PEEK_ANIMATION_DURATION : 0)
                    .setListener(null);
        } else {
            if (DEBUG_WARP) Log.e(TAG, "animateWarpPageOffScreen(): not warping", new Exception());
        }
    }

@@ -2681,7 +2738,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        }
    }

    public void startWarp(int pageIndex) {
    public void startPageWarp(int pageIndex) {
        if (DEBUG_WARP) Log.v(TAG, "START WARP");
        if (pageIndex != mCurrentPage + 1) {
            mPageSwapIndex = mCurrentPage + 1;
@@ -2693,7 +2750,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
        return mPageWarpIndex;
    }

    public void endWarp() {
    public void stopPageWarp() {
        if (DEBUG_WARP) Log.v(TAG, "END WARP");
        // mPageSwapIndex is reset in snapToPage() after the scroll animation completes
    }
+2 −2
Original line number Diff line number Diff line
@@ -88,8 +88,8 @@ public class SlidingChallengeLayout extends ViewGroup implements ChallengeLayout
    public static final int SCROLL_STATE_SETTLING = 2;
    public static final int SCROLL_STATE_FADING = 3;

    private static final int CHALLENGE_FADE_OUT_DURATION = 100;
    private static final int CHALLENGE_FADE_IN_DURATION = 160;
    public static final int CHALLENGE_FADE_OUT_DURATION = 100;
    public static final int CHALLENGE_FADE_IN_DURATION = 160;

    private static final int MAX_SETTLE_DURATION = 600; // ms