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

Commit 1c9bf6a1 authored by Tony Wickham's avatar Tony Wickham
Browse files

Add carousel curve effect to RecentsView.

Pages scale down and tuck underneath the centermost page.

Change-Id: I12686cd72634f758ef71828033eb4e22339ef185
parent af3a3277
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -16,10 +16,12 @@

package com.android.quickstep;

import android.animation.TimeInterpolator;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;

import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -41,6 +43,12 @@ import java.util.ArrayList;
 */
public class RecentsView extends PagedView {

    /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
    private static final float CURVE_FACTOR = 0.25f;
    /** A circular curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
    private static final TimeInterpolator CURVE_INTERPOLATOR
        = x -> (float) (1 - Math.sqrt(1 - Math.pow(x, 2)));

    private boolean mOverviewStateEnabled;
    private boolean mTaskStackListenerRegistered;

@@ -69,6 +77,7 @@ public class RecentsView extends PagedView {
        super(context, attrs, defStyleAttr);
        setWillNotDraw(false);
        setPageSpacing((int) getResources().getDimension(R.dimen.recents_page_spacing));
        enableFreeScroll(true);
    }

    @Override
@@ -170,4 +179,39 @@ public class RecentsView extends PagedView {
        padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2);
        return padding;
    }

    @Override
    public void scrollTo(int x, int y) {
        super.scrollTo(x, y);
        updateCurveProperties();
    }

    /**
     * Scales and adjusts translation of adjacent pages as if on a curved carousel.
     */
    private void updateCurveProperties() {
        if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
            return;
        }
        final int halfScreenWidth = getMeasuredWidth() / 2;
        final int screenCenter = halfScreenWidth + getScrollX();
        final int pageSpacing = getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
        final int pageCount = getPageCount();
        for (int i = 0; i < pageCount; i++) {
            View page = getPageAt(i);
            int pageWidth = page.getMeasuredWidth();
            int halfPageWidth = pageWidth / 2;
            int pageCenter = page.getLeft() + halfPageWidth;
            float distanceFromScreenCenter = Math.abs(pageCenter - screenCenter);
            float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
            float linearInterpolation = Math.min(1, distanceFromScreenCenter / distanceToReachEdge);
            float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation);
            float scale = 1 - curveInterpolation * CURVE_FACTOR;
            page.setScaleX(scale);
            page.setScaleY(scale);
            // Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
            page.setTranslationZ(scale);
            page.setTranslationX((screenCenter - pageCenter) * curveInterpolation * CURVE_FACTOR);
        }
    }
}
+22 −2
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;
@@ -87,6 +86,7 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
    public static final int INVALID_RESTORE_PAGE = -1001;

    private boolean mFreeScroll = false;
    private boolean mSettleOnPageInFreeScroll = false;

    protected int mFlingThresholdVelocity;
    protected int mMinFlingVelocity;
@@ -1170,7 +1170,12 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
     * return true if freescroll has been enabled, false otherwise
     */
    protected void enableFreeScroll() {
        enableFreeScroll(false);
    }

    protected void enableFreeScroll(boolean settleOnPageInFreeScroll) {
        setEnableFreeScroll(true);
        mSettleOnPageInFreeScroll = settleOnPageInFreeScroll;
    }

    protected void disableFreeScroll() {
@@ -1414,7 +1419,22 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
                    mScroller.setInterpolator(mDefaultInterpolator);
                    mScroller.fling(initialScrollX,
                            getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0);
                    mNextPage = getPageNearestToCenterOfScreen((int) (mScroller.getFinalX() / scaleX));
                    int unscaledScrollX = (int) (mScroller.getFinalX() / scaleX);
                    mNextPage = getPageNearestToCenterOfScreen(unscaledScrollX);
                    int firstPageScroll = getScrollForPage(!mIsRtl ? 0 : getPageCount() - 1);
                    int lastPageScroll = getScrollForPage(!mIsRtl ? getPageCount() - 1 : 0);
                    if (mSettleOnPageInFreeScroll && unscaledScrollX > firstPageScroll
                            && unscaledScrollX < lastPageScroll) {
                        // Make sure we land directly on a page. If flinging past one of the ends,
                        // don't change the velocity as it will get stopped at the end anyway.
                        mScroller.setFinalX((int) (getScrollForPage(mNextPage) * getScaleX()));
                        // Ensure the scroll/snap doesn't happen too fast;
                        int extraScrollDuration = OVERSCROLL_PAGE_SNAP_ANIMATION_DURATION
                                - mScroller.getDuration();
                        if (extraScrollDuration > 0) {
                            mScroller.extendDuration(extraScrollDuration);
                        }
                    }
                    invalidate();
                }
                onScrollInteractionEnd();