Loading src/com/android/launcher3/allapps/AllAppsContainerView.java +1 −1 Original line number Diff line number Diff line Loading @@ -220,7 +220,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc }); // Load the all apps recycler view mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view); mAppsRecyclerView = findViewById(R.id.apps_list_view); mAppsRecyclerView.setApps(mApps); mAppsRecyclerView.setLayoutManager(mLayoutManager); mAppsRecyclerView.setAdapter(mAdapter); Loading src/com/android/launcher3/allapps/AllAppsRecyclerView.java +126 −0 Original line number Diff line number Diff line Loading @@ -15,12 +15,14 @@ */ package com.android.launcher3.allapps; import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.util.Property; import android.util.SparseIntArray; import android.view.MotionEvent; import android.view.View; Loading Loading @@ -54,6 +56,22 @@ public class AllAppsRecyclerView extends BaseRecyclerView { private int mEmptySearchBackgroundTopOffset; private SpringAnimationHandler mSpringAnimationHandler; private OverScrollHelper mOverScrollHelper; private VerticalPullDetector mPullDetector; private float mContentTranslationY = 0; public static final Property<AllAppsRecyclerView, Float> CONTENT_TRANS_Y = new Property<AllAppsRecyclerView, Float>(Float.class, "appsRecyclerViewContentTransY") { @Override public Float get(AllAppsRecyclerView allAppsRecyclerView) { return allAppsRecyclerView.getContentTranslationY(); } @Override public void set(AllAppsRecyclerView allAppsRecyclerView, Float y) { allAppsRecyclerView.setContentTranslationY(y); } }; public AllAppsRecyclerView(Context context) { this(context, null); Loading @@ -74,14 +92,27 @@ public class AllAppsRecyclerView extends BaseRecyclerView { addOnItemTouchListener(this); mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize( R.dimen.all_apps_empty_search_bg_top_offset); mOverScrollHelper = new OverScrollHelper(); mPullDetector = new VerticalPullDetector(getContext()); mPullDetector.setListener(mOverScrollHelper); mPullDetector.setDetectableScrollConditions(VerticalPullDetector.DIRECTION_UP | VerticalPullDetector.DIRECTION_DOWN, true); } public void setSpringAnimationHandler(SpringAnimationHandler springAnimationHandler) { mSpringAnimationHandler = springAnimationHandler; } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) { mPullDetector.onTouchEvent(ev); return super.onInterceptTouchEvent(rv, ev) || mOverScrollHelper.isInOverScroll(); } @Override public boolean onTouchEvent(MotionEvent e) { mPullDetector.onTouchEvent(e); if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) { mSpringAnimationHandler.addMovement(e); } Loading Loading @@ -168,6 +199,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView { @Override public void onDraw(Canvas c) { c.translate(0, mContentTranslationY); // Draw the background if (mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) { mEmptySearchBackground.draw(c); Loading @@ -176,6 +209,19 @@ public class AllAppsRecyclerView extends BaseRecyclerView { super.onDraw(c); } public float getContentTranslationY() { return mContentTranslationY; } /** * Use this method instead of calling {@link #setTranslationY(float)}} directly to avoid drawing * on top of other Views. */ public void setContentTranslationY(float y) { mContentTranslationY = y; invalidate(); } @Override protected boolean verifyDrawable(Drawable who) { return who == mEmptySearchBackground || super.verifyDrawable(who); Loading Loading @@ -434,4 +480,84 @@ public class AllAppsRecyclerView extends BaseRecyclerView { y + mEmptySearchBackground.getIntrinsicHeight()); } private class OverScrollHelper implements VerticalPullDetector.Listener { private static final float MAX_RELEASE_VELOCITY = 5000; // px / s private static final float MAX_OVERSCROLL_PERCENTAGE = 0.07f; private boolean mIsInOverScroll; @Override public void onDragStart(boolean start) { } @Override public boolean onDrag(float displacement, float velocity) { // We are in overscroll iff we are trying to drag further down when we're already at // the bottom of All Apps. mIsInOverScroll = !canScrollVertically(1) && displacement < 0; if (mIsInOverScroll) { displacement = getDampedOverScroll(displacement); setContentTranslationY(displacement); } return mIsInOverScroll; } @Override public void onDragEnd(float velocity, boolean fling) { float y = getContentTranslationY(); if (mIsInOverScroll && Float.compare(y, 0) != 0) { if (FeatureFlags.LAUNCHER3_PHYSICS) { // We calculate our own velocity to give the springs the desired effect. velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY; mSpringAnimationHandler.animateToPositionWithVelocity(0, -velocity); } ObjectAnimator.ofFloat(AllAppsRecyclerView.this, AllAppsRecyclerView.CONTENT_TRANS_Y, 0) .setDuration(100) .start(); } mIsInOverScroll = false; } public boolean isInOverScroll() { return mIsInOverScroll; } private float getDampedOverScroll(float y) { return dampedOverScroll(y, getHeight()) * MAX_OVERSCROLL_PERCENTAGE; } /** * This curve determines how the effect of scrolling over the limits of the page diminishes * as the user pulls further and further from the bounds * * @param f The percentage of how much the user has overscrolled. * @return A transformed percentage based on the influence curve. */ private float overScrollInfluenceCurve(float f) { f -= 1.0f; return f * f * f + 1.0f; } /** * @param amount The original amount overscrolled. * @param max The maximum amount that the View can overscroll. * @return The dampened overscroll amount. */ private float dampedOverScroll(float amount, float max) { float f = amount / max; if (Float.compare(f, 0) == 0) return 0; f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f))); // Clamp this factor, f, to -1 < f < 1 if (Math.abs(f) >= 1) { f /= Math.abs(f); } return Math.round(f * max); } } } src/com/android/launcher3/anim/SpringAnimationHandler.java +15 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,19 @@ public class SpringAnimationHandler<T> { reset(); } /** * Similar to {@link #animateToFinalPosition(float)}, but used in cases where we want to * manually set the velocity. */ public void animateToPositionWithVelocity(float position, float velocity) { if (DEBUG) Log.d(TAG, "animateToPosition#velocity=" + velocity); setStartVelocity(velocity); mShouldComputeVelocity = false; animateToFinalPosition(position); } public boolean isRunning() { // All the animations run at the same time so we can just check the first one. return !mAnimations.isEmpty() && mAnimations.get(0).isRunning(); Loading @@ -153,6 +166,8 @@ public class SpringAnimationHandler<T> { } private void setStartVelocity(float velocity) { if (DEBUG) Log.d(TAG, "setStartVelocity=" + velocity); int size = mAnimations.size(); for (int i = 0; i < size; ++i) { mAnimations.get(i).setStartVelocity(velocity); Loading Loading
src/com/android/launcher3/allapps/AllAppsContainerView.java +1 −1 Original line number Diff line number Diff line Loading @@ -220,7 +220,7 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc }); // Load the all apps recycler view mAppsRecyclerView = (AllAppsRecyclerView) findViewById(R.id.apps_list_view); mAppsRecyclerView = findViewById(R.id.apps_list_view); mAppsRecyclerView.setApps(mApps); mAppsRecyclerView.setLayoutManager(mLayoutManager); mAppsRecyclerView.setAdapter(mAdapter); Loading
src/com/android/launcher3/allapps/AllAppsRecyclerView.java +126 −0 Original line number Diff line number Diff line Loading @@ -15,12 +15,14 @@ */ package com.android.launcher3.allapps; import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.util.Property; import android.util.SparseIntArray; import android.view.MotionEvent; import android.view.View; Loading Loading @@ -54,6 +56,22 @@ public class AllAppsRecyclerView extends BaseRecyclerView { private int mEmptySearchBackgroundTopOffset; private SpringAnimationHandler mSpringAnimationHandler; private OverScrollHelper mOverScrollHelper; private VerticalPullDetector mPullDetector; private float mContentTranslationY = 0; public static final Property<AllAppsRecyclerView, Float> CONTENT_TRANS_Y = new Property<AllAppsRecyclerView, Float>(Float.class, "appsRecyclerViewContentTransY") { @Override public Float get(AllAppsRecyclerView allAppsRecyclerView) { return allAppsRecyclerView.getContentTranslationY(); } @Override public void set(AllAppsRecyclerView allAppsRecyclerView, Float y) { allAppsRecyclerView.setContentTranslationY(y); } }; public AllAppsRecyclerView(Context context) { this(context, null); Loading @@ -74,14 +92,27 @@ public class AllAppsRecyclerView extends BaseRecyclerView { addOnItemTouchListener(this); mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize( R.dimen.all_apps_empty_search_bg_top_offset); mOverScrollHelper = new OverScrollHelper(); mPullDetector = new VerticalPullDetector(getContext()); mPullDetector.setListener(mOverScrollHelper); mPullDetector.setDetectableScrollConditions(VerticalPullDetector.DIRECTION_UP | VerticalPullDetector.DIRECTION_DOWN, true); } public void setSpringAnimationHandler(SpringAnimationHandler springAnimationHandler) { mSpringAnimationHandler = springAnimationHandler; } @Override public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) { mPullDetector.onTouchEvent(ev); return super.onInterceptTouchEvent(rv, ev) || mOverScrollHelper.isInOverScroll(); } @Override public boolean onTouchEvent(MotionEvent e) { mPullDetector.onTouchEvent(e); if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) { mSpringAnimationHandler.addMovement(e); } Loading Loading @@ -168,6 +199,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView { @Override public void onDraw(Canvas c) { c.translate(0, mContentTranslationY); // Draw the background if (mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) { mEmptySearchBackground.draw(c); Loading @@ -176,6 +209,19 @@ public class AllAppsRecyclerView extends BaseRecyclerView { super.onDraw(c); } public float getContentTranslationY() { return mContentTranslationY; } /** * Use this method instead of calling {@link #setTranslationY(float)}} directly to avoid drawing * on top of other Views. */ public void setContentTranslationY(float y) { mContentTranslationY = y; invalidate(); } @Override protected boolean verifyDrawable(Drawable who) { return who == mEmptySearchBackground || super.verifyDrawable(who); Loading Loading @@ -434,4 +480,84 @@ public class AllAppsRecyclerView extends BaseRecyclerView { y + mEmptySearchBackground.getIntrinsicHeight()); } private class OverScrollHelper implements VerticalPullDetector.Listener { private static final float MAX_RELEASE_VELOCITY = 5000; // px / s private static final float MAX_OVERSCROLL_PERCENTAGE = 0.07f; private boolean mIsInOverScroll; @Override public void onDragStart(boolean start) { } @Override public boolean onDrag(float displacement, float velocity) { // We are in overscroll iff we are trying to drag further down when we're already at // the bottom of All Apps. mIsInOverScroll = !canScrollVertically(1) && displacement < 0; if (mIsInOverScroll) { displacement = getDampedOverScroll(displacement); setContentTranslationY(displacement); } return mIsInOverScroll; } @Override public void onDragEnd(float velocity, boolean fling) { float y = getContentTranslationY(); if (mIsInOverScroll && Float.compare(y, 0) != 0) { if (FeatureFlags.LAUNCHER3_PHYSICS) { // We calculate our own velocity to give the springs the desired effect. velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY; mSpringAnimationHandler.animateToPositionWithVelocity(0, -velocity); } ObjectAnimator.ofFloat(AllAppsRecyclerView.this, AllAppsRecyclerView.CONTENT_TRANS_Y, 0) .setDuration(100) .start(); } mIsInOverScroll = false; } public boolean isInOverScroll() { return mIsInOverScroll; } private float getDampedOverScroll(float y) { return dampedOverScroll(y, getHeight()) * MAX_OVERSCROLL_PERCENTAGE; } /** * This curve determines how the effect of scrolling over the limits of the page diminishes * as the user pulls further and further from the bounds * * @param f The percentage of how much the user has overscrolled. * @return A transformed percentage based on the influence curve. */ private float overScrollInfluenceCurve(float f) { f -= 1.0f; return f * f * f + 1.0f; } /** * @param amount The original amount overscrolled. * @param max The maximum amount that the View can overscroll. * @return The dampened overscroll amount. */ private float dampedOverScroll(float amount, float max) { float f = amount / max; if (Float.compare(f, 0) == 0) return 0; f = f / (Math.abs(f)) * (overScrollInfluenceCurve(Math.abs(f))); // Clamp this factor, f, to -1 < f < 1 if (Math.abs(f) >= 1) { f /= Math.abs(f); } return Math.round(f * max); } } }
src/com/android/launcher3/anim/SpringAnimationHandler.java +15 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,19 @@ public class SpringAnimationHandler<T> { reset(); } /** * Similar to {@link #animateToFinalPosition(float)}, but used in cases where we want to * manually set the velocity. */ public void animateToPositionWithVelocity(float position, float velocity) { if (DEBUG) Log.d(TAG, "animateToPosition#velocity=" + velocity); setStartVelocity(velocity); mShouldComputeVelocity = false; animateToFinalPosition(position); } public boolean isRunning() { // All the animations run at the same time so we can just check the first one. return !mAnimations.isEmpty() && mAnimations.get(0).isRunning(); Loading @@ -153,6 +166,8 @@ public class SpringAnimationHandler<T> { } private void setStartVelocity(float velocity) { if (DEBUG) Log.d(TAG, "setStartVelocity=" + velocity); int size = mAnimations.size(); for (int i = 0; i < size; ++i) { mAnimations.get(i).setStartVelocity(velocity); Loading