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

Commit 14a89262 authored by Mario Bertschler's avatar Mario Bertschler
Browse files

Using edge effect to trigger spring animation for all apps.

Bug: 72811152
Bug: 72059944

Change-Id: Ied7b51caa2fb48a2fda126d59e4eaf6a35edded3
parent 865ee02d
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -31,7 +31,6 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
@@ -142,11 +141,6 @@ public class EdgeSwipeController extends VerticalSwipeController implements
        }
    }

    @Override
    protected void initSprings() {
        mSpringHandlers = new SpringAnimationHandler[0];
    }

    @Override
    protected float getShiftRange() {
        return getShiftRange(mLauncher);
+0 −49
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION;
import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;

import android.animation.Animator;
@@ -27,7 +26,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.support.animation.SpringAnimation;
import android.util.Log;
import android.view.MotionEvent;

@@ -38,11 +36,9 @@ import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
@@ -52,8 +48,6 @@ import com.android.launcher3.util.FloatRange;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.TouchInteractionService;

import java.util.ArrayList;

/**
 * Handles vertical touch gesture on the DragLayer
 */
@@ -112,8 +106,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
    // Ratio of transition process [0, 1] to drag displacement (px)
    private float mProgressMultiplier;

    private SpringAnimationHandler[] mSpringHandlers;

    public TwoStepSwipeController(Launcher l) {
        mLauncher = l;
        mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
@@ -156,29 +148,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
        }
    }

    private void initSprings() {
        AllAppsContainerView appsView = mLauncher.getAppsView();

        SpringAnimationHandler handler = appsView.getSpringAnimationHandler();
        if (handler == null) {
            mSpringHandlers = new SpringAnimationHandler[0];
            return;
        }

        ArrayList<SpringAnimationHandler> handlers = new ArrayList<>();
        handlers.add(handler);

        SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling();
        if (searchSpring != null) {
            SpringAnimationHandler searchHandler =
                    new SpringAnimationHandler(Y_DIRECTION, handler.getFactory());
            searchHandler.add(searchSpring, true /* setDefaultValues */);
            handlers.add(searchHandler);
        }

        mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]);
    }

    @Override
    public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -214,10 +183,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter

            mDetector.setDetectableScrollConditions(
                    directionsToDetectScroll, ignoreSlopWhenSettling);

            if (mSpringHandlers == null) {
                initSprings();
            }
        }

        if (mNoIntercept) {
@@ -230,9 +195,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter

    @Override
    public boolean onControllerTouchEvent(MotionEvent ev) {
        for (SpringAnimationHandler h : mSpringHandlers) {
            h.addMovement(ev);
        }
        return mDetector.onTouchEvent(ev);
    }

@@ -283,10 +245,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
            mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING);
            updatePauseDetectorRangeFlag();
        }

        for (SpringAnimationHandler h : mSpringHandlers) {
            h.skipToEnd();
        }
    }

    private float getShiftRange() {
@@ -329,13 +287,6 @@ public class TwoStepSwipeController extends AnimatorListenerAdapter
            targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
        }

        if (fling && targetState == ALL_APPS) {
            for (SpringAnimationHandler h : mSpringHandlers) {
                // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
                h.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
            }
        }

        float endProgress;

        if (mDragPauseDetector.isTriggered() && targetState == NORMAL) {
+1 −2
Original line number Diff line number Diff line
@@ -22,5 +22,4 @@
    android:layout_below="@id/search_container_all_apps"
    android:clipToPadding="false"
    android:descendantFocusability="afterDescendants"
    android:focusable="true"
    android:overScrollMode="never" />
    android:focusable="true" />
+7 −12
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.RelativeLayout;

import com.android.launcher3.AppInfo;
import com.android.launcher3.DeviceProfile;
@@ -50,7 +49,6 @@ import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
@@ -61,11 +59,12 @@ import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BottomUserEducationView;
import com.android.launcher3.views.RecyclerViewFastScroller;
import com.android.launcher3.views.SpringRelativeLayout;

/**
 * The all apps view container.
 */
public class AllAppsContainerView extends RelativeLayout implements DragSource,
public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
        OnLongClickListener, Insettable, OnDeviceProfileChangeListener {

    private final Launcher mLauncher;
@@ -119,6 +118,10 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
        // Attach a scrim to be drawn behind all-apps and hotseat
        new ColorScrim(this, Themes.getAttrColor(context, R.attr.allAppsScrimColor), DEACCEL_2)
                .attach();

        addSpringView(R.id.all_apps_header);
        addSpringView(R.id.apps_list_view);
        addSpringView(R.id.all_apps_tabs_view_pager);
    }

    public AllAppsStore getAppsStore() {
@@ -324,10 +327,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
        }
    }

    public SpringAnimationHandler getSpringAnimationHandler() {
        return mUsingTabs ? null : mAH[AdapterHolder.MAIN].animationHandler;
    }

    private void rebindAdapters(boolean showTabs) {
        rebindAdapters(showTabs, false /* force */);
    }
@@ -470,7 +469,6 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,

        public final AllAppsGridAdapter adapter;
        final LinearLayoutManager layoutManager;
        final SpringAnimationHandler animationHandler;
        final AlphabeticalAppsList appsList;
        final Rect padding = new Rect();
        AllAppsRecyclerView recyclerView;
@@ -481,22 +479,19 @@ public class AllAppsContainerView extends RelativeLayout implements DragSource,
            adapter = new AllAppsGridAdapter(mLauncher, appsList, mLauncher,
                    AllAppsContainerView.this, true);
            appsList.setAdapter(adapter);
            animationHandler = adapter.getSpringAnimationHandler();
            layoutManager = adapter.getLayoutManager();
        }

        void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
            appsList.updateItemFilter(matcher);
            recyclerView = (AllAppsRecyclerView) rv;
            recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
            recyclerView.setApps(appsList, mUsingTabs);
            recyclerView.setLayoutManager(layoutManager);
            recyclerView.setAdapter(adapter);
            recyclerView.setHasFixedSize(true);
            // No animations will occur when changes occur to the items in this RecyclerView.
            recyclerView.setItemAnimator(null);
            if (FeatureFlags.LAUNCHER3_PHYSICS && animationHandler != null) {
                recyclerView.setSpringAnimationHandler(animationHandler);
            }
            FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(recyclerView);
            recyclerView.addItemDecoration(focusedItemDecorator);
            adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
+0 −134
Original line number Diff line number Diff line
@@ -18,8 +18,6 @@ package com.android.launcher3.allapps;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.support.animation.DynamicAnimation;
import android.support.animation.SpringAnimation;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
@@ -38,11 +36,8 @@ import com.android.launcher3.AppInfo;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageManagerHelper;

import java.util.List;
@@ -71,7 +66,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
    // Common view type masks
    public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
    public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
    public static final int VIEW_TYPE_MASK_HAS_SPRINGS = VIEW_TYPE_MASK_ICON;


    public interface BindViewCallback {
@@ -195,8 +189,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
    // The intent to send off to the market app, updated each time the search query changes.
    private Intent mMarketSearchIntent;

    private final SpringAnimationHandler<ViewHolder> mSpringAnimationHandler;

    public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener
            iconClickListener, View.OnLongClickListener iconLongClickListener, boolean springAnim) {
        Resources res = launcher.getResources();
@@ -209,21 +201,11 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
        mLayoutInflater = LayoutInflater.from(launcher);
        mIconClickListener = iconClickListener;
        mIconLongClickListener = iconLongClickListener;
        if (FeatureFlags.LAUNCHER3_PHYSICS && springAnim) {
            mSpringAnimationHandler = new SpringAnimationHandler<>(
                    SpringAnimationHandler.Y_DIRECTION, new AllAppsSpringAnimationFactory());
        } else {
            mSpringAnimationHandler = null;
        }

        mAppsPerRow = mLauncher.getDeviceProfile().inv.numColumns;
        mGridLayoutMgr.setSpanCount(mAppsPerRow);
    }

    public SpringAnimationHandler getSpringAnimationHandler() {
        return mSpringAnimationHandler;
    }

    public static boolean isDividerViewType(int viewType) {
        return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
    }
@@ -343,22 +325,6 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
        }
    }

    @Override
    public void onViewAttachedToWindow(ViewHolder holder) {
        int type = holder.getItemViewType();
        if (mSpringAnimationHandler != null && isViewType(type, VIEW_TYPE_MASK_HAS_SPRINGS)) {
            mSpringAnimationHandler.add(holder.itemView, holder);
        }
    }

    @Override
    public void onViewDetachedFromWindow(ViewHolder holder) {
        int type = holder.getItemViewType();
        if (mSpringAnimationHandler != null && isViewType(type, VIEW_TYPE_MASK_HAS_SPRINGS)) {
            mSpringAnimationHandler.remove(holder.itemView);
        }
    }

    @Override
    public boolean onFailedToRecycleView(ViewHolder holder) {
        // Always recycle and we will reset the view when it is bound
@@ -376,104 +342,4 @@ public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.
        return item.viewType;
    }

    /**
     * Helper class to set the SpringAnimation values for an item in the adapter.
     */
    private class AllAppsSpringAnimationFactory
            implements SpringAnimationHandler.AnimationFactory<ViewHolder> {
        private static final float DEFAULT_MAX_VALUE_PX = 100;
        private static final float DEFAULT_MIN_VALUE_PX = -DEFAULT_MAX_VALUE_PX;

        // Damping ratio range is [0, 1]
        private static final float SPRING_DAMPING_RATIO = 0.55f;

        // Stiffness is a non-negative number.
        private static final float MIN_SPRING_STIFFNESS = 580f;
        private static final float MAX_SPRING_STIFFNESS = 900f;

        // The amount by which each adjacent rows' stiffness will differ.
        private static final float ROW_STIFFNESS_COEFFICIENT = 50f;

        // The percentage by which we multiply each row to create the row factor.
        private static final float ROW_PERCENTAGE = 0.3f;

        @Override
        public SpringAnimation initialize(ViewHolder vh) {
            return SpringAnimationHandler.forView(vh.itemView, DynamicAnimation.TRANSLATION_Y, 0);
        }

        /**
         * @param spring A new or recycled SpringAnimation.
         * @param vh The ViewHolder that {@param spring} is related to.
         */
        @Override
        public void update(SpringAnimation spring, ViewHolder vh) {
            int appPosition = vh.getAdapterPosition();
            int col = appPosition % mAppsPerRow;
            int row = appPosition / mAppsPerRow;

            int numTotalRows = mApps.getNumAppRows() - 1; // zero-based count
            if (row > (numTotalRows / 2)) {
                // Mirror the rows so that the top row acts the same as the bottom row.
                row = Math.abs(numTotalRows - row);
            }

            calculateSpringValues(spring, row, col);
        }

        @Override
        public void setDefaultValues(SpringAnimation spring) {
            calculateSpringValues(spring, 0, mAppsPerRow / 2);
        }

        /**
         * We manipulate the stiffness, min, and max values based on the items distance to the
         * first row and the items distance to the center column to create the ^-shaped motion
         * effect.
         */
        private void calculateSpringValues(SpringAnimation spring, int row, int col) {
            float rowFactor = (1 + row) * ROW_PERCENTAGE;
            float colFactor = getColumnFactor(col, mAppsPerRow);

            float minValue = DEFAULT_MIN_VALUE_PX * (rowFactor + colFactor);
            float maxValue = DEFAULT_MAX_VALUE_PX * (rowFactor + colFactor);

            float stiffness = Utilities.boundToRange(
                    MAX_SPRING_STIFFNESS - (row * ROW_STIFFNESS_COEFFICIENT),
                    MIN_SPRING_STIFFNESS,
                    MAX_SPRING_STIFFNESS);

            spring.setMinValue(minValue)
                    .setMaxValue(maxValue)
                    .getSpring()
                    .setStiffness(stiffness)
                    .setDampingRatio(SPRING_DAMPING_RATIO);
        }

        /**
         * Increase the column factor as the distance increases between the column and the center
         * column(s).
         */
        private float getColumnFactor(int col, int numCols) {
            float centerColumn = numCols / 2;
            int distanceToCenter = (int) Math.abs(col - centerColumn);

            boolean evenNumberOfColumns = numCols % 2 == 0;
            if (evenNumberOfColumns && col < centerColumn) {
                distanceToCenter -= 1;
            }

            float factor = 0;
            while (distanceToCenter > 0) {
                if (distanceToCenter == 1) {
                    factor += 0.2f;
                } else {
                    factor += 0.1f;
                }
                --distanceToCenter;
            }

            return factor;
        }
    }
}
Loading