Changing the overviewState to show appsearch and floating header
Change-Id: I2cfd61cfc9978e4c8e4520f0f7217e49e7344c79
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index fc61155..8ae3073 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -419,7 +419,7 @@
}
}
- private void setTextAlpha(int alpha) {
+ public void setTextAlpha(int alpha) {
super.setTextColor(ColorUtils.setAlphaComponent(mTextColor, alpha));
}
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index a3fe89a..dec6cb4 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -16,10 +16,10 @@
package com.android.launcher3;
-import static com.android.launcher3.AlphaUpdateListener.updateVisibility;
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT;
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_LEFT;
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_RIGHT;
+import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.TimeInterpolator;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ee6dd59..82be592 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -364,6 +364,9 @@
getRootView().dispatchInsets();
getStateManager().reapplyState();
+ // Recreate touch controllers
+ mDragLayer.setup(mDragController);
+
// TODO: We can probably avoid rebind when only screen size changed.
rebindModel();
}
@@ -956,7 +959,7 @@
mDragController.setMoveTarget(mWorkspace);
mDropTargetBar.setup(mDragController);
- mAllAppsController.setupViews(mAppsView, mHotseat);
+ mAllAppsController.setupViews(mAppsView);
}
/**
@@ -1258,7 +1261,7 @@
// Reset the apps view
if (!alreadyOnHome && mAppsView != null) {
- mAppsView.reset();
+ mAppsView.reset(isStarted() /* animate */);
}
if (shouldMoveToDefaultScreen && !mWorkspace.isTouchActive()) {
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index fc4de2d..b1273b6 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -29,6 +29,7 @@
private int mRightInsetBarWidth;
private View mAlignedView;
+ private WindowStateListener mWindowStateListener;
public LauncherRootView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -117,4 +118,31 @@
}
}
}
+
+ public void setWindowStateListener(WindowStateListener listener) {
+ mWindowStateListener = listener;
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ super.onWindowFocusChanged(hasWindowFocus);
+ if (mWindowStateListener != null) {
+ mWindowStateListener.onWindowFocusChanged(hasWindowFocus);
+ }
+ }
+
+ @Override
+ protected void onWindowVisibilityChanged(int visibility) {
+ super.onWindowVisibilityChanged(visibility);
+ if (mWindowStateListener != null) {
+ mWindowStateListener.onWindowVisibilityChanged(visibility);
+ }
+ }
+
+ public interface WindowStateListener {
+
+ void onWindowFocusChanged(boolean hasFocus);
+
+ void onWindowVisibilityChanged(int visibility);
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index e5d8f47..9fef64a 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -40,6 +40,16 @@
*/
public class LauncherState {
+
+ /**
+ * Set of elements indicating various workspace elements which change visibility across states
+ * Note that workspace is not included here as in that case, we animate individual pages
+ */
+ public static final int NONE = 0;
+ public static final int HOTSEAT = 1 << 0;
+ public static final int ALL_APPS_HEADER = 1 << 1;
+ public static final int ALL_APPS_CONTENT = 1 << 2;
+
protected static final int FLAG_SHOW_SCRIM = 1 << 0;
protected static final int FLAG_MULTI_PAGE = 1 << 1;
protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 2;
@@ -51,7 +61,6 @@
protected static final int FLAG_DISABLE_INTERACTION = 1 << 8;
protected static final int FLAG_OVERVIEW_UI = 1 << 9;
-
protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER =
new PageAlphaProvider(ACCEL_2) {
@Override
@@ -68,13 +77,13 @@
public static final LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE,
0, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
- public static final LauncherState ALL_APPS = new AllAppsState(1);
-
- public static final LauncherState SPRING_LOADED = new SpringLoadedState(2);
-
- public static final LauncherState OVERVIEW = new OverviewState(3);
-
- public static final LauncherState FAST_OVERVIEW = new FastOverviewState(4);
+ /**
+ * Various Launcher states arranged in the increasing order of UI layers
+ */
+ public static final LauncherState SPRING_LOADED = new SpringLoadedState(1);
+ public static final LauncherState OVERVIEW = new OverviewState(2);
+ public static final LauncherState FAST_OVERVIEW = new FastOverviewState(3);
+ public static final LauncherState ALL_APPS = new AllAppsState(4);
public final int ordinal;
@@ -161,10 +170,6 @@
return new float[] {1, 0, 0};
}
- public float getHoseatAlpha(Launcher launcher) {
- return 1f;
- }
-
public float getOverviewTranslationX(Launcher launcher) {
return launcher.getDragLayer().getMeasuredWidth();
}
@@ -179,6 +184,10 @@
return launcher.getWorkspace();
}
+ public int getVisibleElements(Launcher launcher) {
+ return HOTSEAT;
+ }
+
/**
* Fraction shift in the vertical translation UI and related properties
*
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 950a8ac..3c43035 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,8 +29,12 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.anim.PropertySetter.AnimatedPropertySetter;
import com.android.launcher3.uioverrides.UiFactory;
+import java.util.ArrayList;
+
/**
* TODO: figure out what kind of tests we can write for this
*
@@ -78,6 +83,7 @@
private final AnimationConfig mConfig = new AnimationConfig();
private final Handler mUiHandler;
private final Launcher mLauncher;
+ private final ArrayList<StateListener> mListeners = new ArrayList<>();
private StateHandler[] mStateHandlers;
private LauncherState mState = NORMAL;
@@ -87,8 +93,6 @@
private LauncherState mRestState;
- private StateListener mStateListener;
-
public LauncherStateManager(Launcher l) {
mUiHandler = new Handler(Looper.getMainLooper());
mLauncher = l;
@@ -105,8 +109,12 @@
return mStateHandlers;
}
- public void setStateListener(StateListener stateListener) {
- mStateListener = stateListener;
+ public void addStateListener(StateListener listener) {
+ mListeners.add(listener);
+ }
+
+ public void removeStateListener(StateListener listener) {
+ mListeners.remove(listener);
}
/**
@@ -188,8 +196,9 @@
for (StateHandler handler : getStateHandlers()) {
handler.setState(state);
}
- if (mStateListener != null) {
- mStateListener.onStateSetImmediately(state);
+
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onStateSetImmediately(state);
}
onStateTransitionEnd(state);
@@ -251,16 +260,16 @@
public void onAnimationStart(Animator animation) {
// Change the internal state only when the transition actually starts
onStateTransitionStart(state);
- if (mStateListener != null) {
- mStateListener.onStateTransitionStart(state);
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onStateTransitionStart(state);
}
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
- if (mStateListener != null) {
- mStateListener.onStateTransitionComplete(mState);
+ for (int i = mListeners.size() - 1; i >= 0; i--) {
+ mListeners.get(i).onStateTransitionComplete(state);
}
}
@@ -376,12 +385,14 @@
public static class AnimationConfig extends AnimatorListenerAdapter {
public long duration;
public boolean userControlled;
+ private PropertySetter mProperSetter;
private AnimatorSet mCurrentAnimation;
public void reset() {
duration = 0;
userControlled = false;
+ mProperSetter = null;
if (mCurrentAnimation != null) {
mCurrentAnimation.setDuration(0);
@@ -390,6 +401,14 @@
}
}
+ public PropertySetter getProperSetter(AnimatorSetBuilder builder) {
+ if (mProperSetter == null) {
+ mProperSetter = duration == 0 ? NO_ANIM_PROPERTY_SETTER
+ : new AnimatedPropertySetter(duration, builder);
+ }
+ return mProperSetter;
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
if (mCurrentAnimation == animation) {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index f6d0248..63c1181 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,6 +18,8 @@
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
+import static com.android.launcher3.LauncherState.HOTSEAT;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.Animator;
@@ -32,65 +34,14 @@
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.graphics.ViewScrim;
/**
- * A convenience class to update a view's visibility state after an alpha animation.
- */
-class AlphaUpdateListener extends AnimatorListenerAdapter implements ValueAnimator.AnimatorUpdateListener {
- private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
-
- private View mView;
- private boolean mAccessibilityEnabled;
- private boolean mCanceled = false;
-
- public AlphaUpdateListener(View v, boolean accessibilityEnabled) {
- mView = v;
- mAccessibilityEnabled = accessibilityEnabled;
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator arg0) {
- updateVisibility(mView, mAccessibilityEnabled);
- }
-
- public static void updateVisibility(View view, boolean accessibilityEnabled) {
- // We want to avoid the extra layout pass by setting the views to GONE unless
- // accessibility is on, in which case not setting them to GONE causes a glitch.
- int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE;
- if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
- view.setVisibility(invisibleState);
- } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
- && view.getVisibility() != View.VISIBLE) {
- view.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCanceled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator arg0) {
- if (mCanceled) return;
- updateVisibility(mView, mAccessibilityEnabled);
- }
-
- @Override
- public void onAnimationStart(Animator arg0) {
- // We want the views to be visible for animation, so fade-in/out is visible
- mView.setVisibility(View.VISIBLE);
- }
-}
-
-/**
* Manages the animations between each of the workspace states.
*/
public class WorkspaceStateTransitionAnimation {
- public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
-
private final Launcher mLauncher;
private final Workspace mWorkspace;
@@ -107,9 +58,7 @@
public void setStateWithAnimation(LauncherState toState, AnimatorSetBuilder builder,
AnimationConfig config) {
- AnimatedPropertySetter propertySetter =
- new AnimatedPropertySetter(config.duration, builder);
- setWorkspaceProperty(toState, propertySetter);
+ setWorkspaceProperty(toState, config.getProperSetter(builder));
}
public float getFinalScale() {
@@ -135,10 +84,12 @@
propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
scaleAndTranslation[2], Interpolators.ZOOM_IN);
- propertySetter.setViewAlpha(mLauncher.getHotseat(), state.getHoseatAlpha(mLauncher),
+ int elements = state.getVisibleElements(mLauncher);
+ float hotseatAlpha = (elements & HOTSEAT) != 0 ? 1 : 0;
+ propertySetter.setViewAlpha(mLauncher.getHotseat(), hotseatAlpha,
pageAlphaProvider.interpolator);
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
- state.getHoseatAlpha(mLauncher), pageAlphaProvider.interpolator);
+ hotseatAlpha, pageAlphaProvider.interpolator);
// Set scrim
propertySetter.setFloat(ViewScrim.get(mWorkspace), ViewScrim.PROGRESS,
@@ -162,71 +113,4 @@
propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
pageAlpha, pageAlphaProvider.interpolator);
}
-
- public static class PropertySetter {
-
- public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
- view.setAlpha(alpha);
- AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext()));
- }
-
- public <T> void setFloat(T target, Property<T, Float> property, float value,
- TimeInterpolator interpolator) {
- property.set(target, value);
- }
-
- public <T> void setInt(T target, Property<T, Integer> property, int value,
- TimeInterpolator interpolator) {
- property.set(target, value);
- }
- }
-
- public static class AnimatedPropertySetter extends PropertySetter {
-
- private final long mDuration;
- private final AnimatorSetBuilder mStateAnimator;
-
- public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
- mDuration = duration;
- mStateAnimator = builder;
- }
-
- @Override
- public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
- if (view.getAlpha() == alpha) {
- return;
- }
- ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
- anim.addListener(new AlphaUpdateListener(
- view, isAccessibilityEnabled(view.getContext())));
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
-
- @Override
- public <T> void setFloat(T target, Property<T, Float> property, float value,
- TimeInterpolator interpolator) {
- if (property.get(target) == value) {
- return;
- }
- Animator anim = ObjectAnimator.ofFloat(target, property, value);
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
-
- @Override
- public <T> void setInt(T target, Property<T, Integer> property, int value,
- TimeInterpolator interpolator) {
- if (property.get(target) == value) {
- return;
- }
- Animator anim = ObjectAnimator.ofInt(target, property, value);
- anim.setDuration(mDuration).setInterpolator(interpolator);
- mStateAnimator.play(anim);
- }
-
- private TimeInterpolator getFadeInterpolator(float finalAlpha) {
- return finalAlpha == 0 ? Interpolators.DEACCEL_2 : null;
- }
- }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 39a8df3..8f5fcf5 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -217,14 +217,14 @@
/**
* Resets the state of AllApps.
*/
- public void reset() {
+ public void reset(boolean animate) {
for (int i = 0; i < mAH.length; i++) {
if (mAH[i].recyclerView != null) {
mAH[i].recyclerView.scrollToTop();
}
}
if (isHeaderVisible()) {
- mHeader.reset();
+ mHeader.reset(animate);
}
// Reset the search bar and base recycler view after transitioning home
mSearchUiManager.resetSearch();
@@ -360,7 +360,7 @@
public void onTabChanged(int pos) {
mHeader.setMainActive(pos == 0);
- reset();
+ reset(true /* animate */);
if (mAH[pos].recyclerView != null) {
mAH[pos].recyclerView.bindFastScrollbar();
@@ -383,6 +383,18 @@
return mHeader;
}
+ public View getSearchView() {
+ return mSearchContainer;
+ }
+
+ public View getContentView() {
+ return mViewPager == null ? getActiveRecyclerView() : mViewPager;
+ }
+
+ public RecyclerViewFastScroller getScrollBar() {
+ return getActiveRecyclerView().getScrollbar();
+ }
+
public void setupHeader() {
mHeader.setVisibility(View.VISIBLE);
mHeader.setup(mAH, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView == null);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 13a42f1..bf8f531 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -1,7 +1,10 @@
package com.android.launcher3.allapps;
+import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT;
+import static com.android.launcher3.LauncherState.ALL_APPS_HEADER;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS;
import android.animation.Animator;
@@ -13,16 +16,15 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
-import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.SearchUiManager.OnScrollRangeChangeListener;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.util.Themes;
/**
@@ -55,7 +57,6 @@
public static final float PARALLAX_COEFFICIENT = .125f;
private AllAppsContainerView mAppsView;
- private Hotseat mHotseat;
private final Launcher mLauncher;
private final boolean mIsDarkTheme;
@@ -88,7 +89,6 @@
private void onProgressAnimationStart() {
// Initialize values that should not change until #onDragEnd
- mHotseat.setVisibility(View.VISIBLE);
mAppsView.setVisibility(View.VISIBLE);
}
@@ -116,14 +116,10 @@
mProgress = progress;
float shiftCurrent = progress * mShiftRange;
- float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f);
- float alpha = 1 - workspaceHotseatAlpha;
-
mAppsView.setTranslationY(shiftCurrent);
float hotseatTranslation = -mShiftRange + shiftCurrent;
if (!mIsVerticalLayout) {
- mAppsView.setAlpha(alpha);
mLauncher.getHotseat().setTranslationY(hotseatTranslation);
mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation);
}
@@ -149,6 +145,7 @@
@Override
public void setState(LauncherState state) {
setProgress(state.getVerticalProgress(mLauncher));
+ setAlphas(state, NO_ANIM_PROPERTY_SETTER);
onProgressAnimationEnd();
}
@@ -161,6 +158,7 @@
AnimatorSetBuilder builder, AnimationConfig config) {
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
+ setAlphas(toState, config.getProperSetter(builder));
// Fail fast
onProgressAnimationEnd();
return;
@@ -174,6 +172,19 @@
anim.addListener(getProgressAnimatorListener());
builder.play(anim);
+
+ setAlphas(toState, config.getProperSetter(builder));
+ }
+
+ private void setAlphas(LauncherState toState, PropertySetter setter) {
+ int visibleElements = toState.getVisibleElements(mLauncher);
+ boolean hasHeader = (visibleElements & ALL_APPS_HEADER) != 0;
+ boolean hasContent = (visibleElements & ALL_APPS_CONTENT) != 0;
+
+ setter.setViewAlpha(mAppsView.getSearchView(), hasHeader ? 1 : 0, LINEAR);
+ setter.setViewAlpha(mAppsView.getContentView(), hasContent ? 1 : 0, LINEAR);
+ setter.setViewAlpha(mAppsView.getScrollBar(), hasContent ? 1 : 0, LINEAR);
+ mAppsView.getFloatingHeaderView().setContentVisibility(hasHeader, hasContent, setter);
}
public AnimatorListenerAdapter getProgressAnimatorListener() {
@@ -190,10 +201,8 @@
};
}
- public void setupViews(AllAppsContainerView appsView, Hotseat hotseat) {
+ public void setupViews(AllAppsContainerView appsView) {
mAppsView = appsView;
- mHotseat = hotseat;
- mHotseat.bringToFront();
mAppsView.getSearchUiManager().addOnScrollRangeChangeListener(this);
}
@@ -210,15 +219,12 @@
private void onProgressAnimationEnd() {
if (Float.compare(mProgress, 1f) == 0) {
mAppsView.setVisibility(View.INVISIBLE);
- mHotseat.setVisibility(View.VISIBLE);
- mAppsView.reset();
+ mAppsView.reset(false /* animate */);
} else if (Float.compare(mProgress, 0f) == 0) {
- mHotseat.setVisibility(View.INVISIBLE);
mAppsView.setVisibility(View.VISIBLE);
mAppsView.onScrollUpEnd();
} else {
mAppsView.setVisibility(View.VISIBLE);
- mHotseat.setVisibility(View.VISIBLE);
}
}
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index a0dc5a3..461f5b5 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Point;
@@ -29,6 +31,7 @@
import android.widget.LinearLayout;
import com.android.launcher3.R;
+import com.android.launcher3.anim.PropertySetter;
public class FloatingHeaderView extends LinearLayout implements
ValueAnimator.AnimatorUpdateListener {
@@ -57,7 +60,7 @@
}
};
- private ViewGroup mTabLayout;
+ protected ViewGroup mTabLayout;
private AllAppsRecyclerView mMainRV;
private AllAppsRecyclerView mWorkRV;
private AllAppsRecyclerView mCurrentRV;
@@ -65,6 +68,8 @@
private boolean mHeaderCollapsed;
private int mSnappedScrolledY;
private int mTranslationY;
+
+ private boolean mAllowTouchForwarding;
private boolean mForwardToRecyclerView;
protected boolean mTabsHidden;
@@ -91,7 +96,7 @@
mWorkRV = setupRV(mWorkRV, mAH[AllAppsContainerView.AdapterHolder.WORK].recyclerView);
mParent = (ViewGroup) mMainRV.getParent();
setMainActive(true);
- reset();
+ reset(false);
}
private AllAppsRecyclerView setupRV(AllAppsRecyclerView old, AllAppsRecyclerView updated) {
@@ -158,12 +163,19 @@
}
}
- public void reset() {
- int translateTo = 0;
- mAnimator.setIntValues(mTranslationY, translateTo);
- mAnimator.addUpdateListener(this);
- mAnimator.setDuration(150);
- mAnimator.start();
+ public void reset(boolean animate) {
+ if (mAnimator.isStarted()) {
+ mAnimator.cancel();
+ }
+ if (animate) {
+ mAnimator.setIntValues(mTranslationY, 0);
+ mAnimator.addUpdateListener(this);
+ mAnimator.setDuration(150);
+ mAnimator.start();
+ } else {
+ mTranslationY = 0;
+ apply();
+ }
mHeaderCollapsed = false;
mSnappedScrolledY = -mMaxTranslation;
mCurrentRV.scrollToTop();
@@ -181,6 +193,10 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (!mAllowTouchForwarding) {
+ mForwardToRecyclerView = false;
+ return super.onInterceptTouchEvent(ev);
+ }
calcOffset(mTempOffset);
ev.offsetLocation(mTempOffset.x, mTempOffset.y);
mForwardToRecyclerView = mCurrentRV.onInterceptTouchEvent(ev);
@@ -208,6 +224,19 @@
p.x = getLeft() - mCurrentRV.getLeft() - mParent.getLeft();
p.y = getTop() - mCurrentRV.getTop() - mParent.getTop();
}
+
+ public void setContentVisibility(boolean hasHeader, boolean hasContent, PropertySetter setter) {
+ setter.setViewAlpha(this, hasContent ? 1 : 0, LINEAR);
+ allowTouchForwarding(hasContent);
+ }
+
+ protected void allowTouchForwarding(boolean allow) {
+ mAllowTouchForwarding = allow;
+ }
+
+ public boolean hasVisibleContent() {
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/anim/AlphaUpdateListener.java b/src/com/android/launcher3/anim/AlphaUpdateListener.java
new file mode 100644
index 0000000..04d97a7
--- /dev/null
+++ b/src/com/android/launcher3/anim/AlphaUpdateListener.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 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.launcher3.anim;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.view.View;
+
+/**
+ * A convenience class to update a view's visibility state after an alpha animation.
+ */
+public class AlphaUpdateListener extends AnimatorListenerAdapter implements AnimatorUpdateListener {
+ private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
+
+ private View mView;
+ private boolean mAccessibilityEnabled;
+ private boolean mCanceled = false;
+
+ public AlphaUpdateListener(View v, boolean accessibilityEnabled) {
+ mView = v;
+ mAccessibilityEnabled = accessibilityEnabled;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator arg0) {
+ updateVisibility(mView, mAccessibilityEnabled);
+ }
+
+ public static void updateVisibility(View view, boolean accessibilityEnabled) {
+ // We want to avoid the extra layout pass by setting the views to GONE unless
+ // accessibility is on, in which case not setting them to GONE causes a glitch.
+ int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE;
+ if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
+ view.setVisibility(invisibleState);
+ } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
+ && view.getVisibility() != View.VISIBLE) {
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCanceled = true;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator arg0) {
+ if (mCanceled) return;
+ updateVisibility(mView, mAccessibilityEnabled);
+ }
+
+ @Override
+ public void onAnimationStart(Animator arg0) {
+ // We want the views to be visible for animation, so fade-in/out is visible
+ mView.setVisibility(View.VISIBLE);
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
new file mode 100644
index 0000000..51580b1
--- /dev/null
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 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.launcher3.anim;
+
+import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.util.Property;
+import android.view.View;
+
+/**
+ * Utility class for setting a property with or without animation
+ */
+public class PropertySetter {
+
+ public static final PropertySetter NO_ANIM_PROPERTY_SETTER = new PropertySetter();
+
+ public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+ view.setAlpha(alpha);
+ AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext()));
+ }
+
+ public <T> void setFloat(T target, Property<T, Float> property, float value,
+ TimeInterpolator interpolator) {
+ property.set(target, value);
+ }
+
+ public <T> void setInt(T target, Property<T, Integer> property, int value,
+ TimeInterpolator interpolator) {
+ property.set(target, value);
+ }
+
+ public static class AnimatedPropertySetter extends PropertySetter {
+
+ private final long mDuration;
+ private final AnimatorSetBuilder mStateAnimator;
+
+ public AnimatedPropertySetter(long duration, AnimatorSetBuilder builder) {
+ mDuration = duration;
+ mStateAnimator = builder;
+ }
+
+ @Override
+ public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
+ if (view.getAlpha() == alpha) {
+ return;
+ }
+ ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
+ anim.addListener(new AlphaUpdateListener(
+ view, isAccessibilityEnabled(view.getContext())));
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ mStateAnimator.play(anim);
+ }
+
+ @Override
+ public <T> void setFloat(T target, Property<T, Float> property, float value,
+ TimeInterpolator interpolator) {
+ if (property.get(target) == value) {
+ return;
+ }
+ Animator anim = ObjectAnimator.ofFloat(target, property, value);
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ mStateAnimator.play(anim);
+ }
+
+ @Override
+ public <T> void setInt(T target, Property<T, Integer> property, int value,
+ TimeInterpolator interpolator) {
+ if (property.get(target) == value) {
+ return;
+ }
+ Animator anim = ObjectAnimator.ofInt(target, property, value);
+ anim.setDuration(mDuration).setInterpolator(interpolator);
+ mStateAnimator.play(anim);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 28645dc..78ea419 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -51,6 +51,4 @@
// When enabled shows a work profile tab in all apps
public static final boolean ALL_APPS_TABS_ENABLED = true;
-
- public static final boolean ENABLE_TWO_SWIPE_TARGETS = true;
}
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
new file mode 100644
index 0000000..db53634
--- /dev/null
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2019 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.launcher3.touch;
+
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.util.TouchController;
+
+/**
+ * TouchController for handling state changes
+ */
+public abstract class AbstractStateChangeTouchController extends AnimatorListenerAdapter
+ implements TouchController, SwipeDetector.Listener {
+
+ private static final String TAG = "ASCTouchController";
+ public static final float RECATCH_REJECTION_FRACTION = .0875f;
+ public static final int SINGLE_FRAME_MS = 16;
+
+ // Progress after which the transition is assumed to be a success in case user does not fling
+ public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
+
+ protected final Launcher mLauncher;
+ protected final SwipeDetector mDetector;
+
+ private boolean mNoIntercept;
+ protected int mStartContainerType;
+
+ protected LauncherState mFromState;
+ protected LauncherState mToState;
+ protected AnimatorPlaybackController mCurrentAnimation;
+
+ private float mStartProgress;
+ // Ratio of transition process [0, 1] to drag displacement (px)
+ private float mProgressMultiplier;
+
+ public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) {
+ mLauncher = l;
+ mDetector = new SwipeDetector(l, this, dir);
+ }
+
+ protected abstract boolean canInterceptTouch(MotionEvent ev);
+
+ /**
+ * Initializes the {@code mFromState} and {@code mToState} and swipe direction to use for
+ * the detector. In can of disabling swipe, return 0.
+ */
+ protected abstract int getSwipeDirection(MotionEvent ev);
+
+ @Override
+ public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+ mNoIntercept = !canInterceptTouch(ev);
+ if (mNoIntercept) {
+ return false;
+ }
+
+ // Now figure out which direction scroll events the controller will start
+ // calling the callbacks.
+ final int directionsToDetectScroll;
+ boolean ignoreSlopWhenSettling = false;
+
+ if (mCurrentAnimation != null) {
+ if (mCurrentAnimation.getProgressFraction() > 1 - RECATCH_REJECTION_FRACTION) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ } else if (mCurrentAnimation.getProgressFraction() < RECATCH_REJECTION_FRACTION ) {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
+ } else {
+ directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
+ ignoreSlopWhenSettling = true;
+ }
+ } else {
+ directionsToDetectScroll = getSwipeDirection(ev);
+ if (directionsToDetectScroll == 0) {
+ mNoIntercept = true;
+ return false;
+ }
+ }
+ mDetector.setDetectableScrollConditions(
+ directionsToDetectScroll, ignoreSlopWhenSettling);
+ }
+
+ if (mNoIntercept) {
+ return false;
+ }
+
+ onControllerTouchEvent(ev);
+ return mDetector.isDraggingOrSettling();
+ }
+
+ @Override
+ public final boolean onControllerTouchEvent(MotionEvent ev) {
+ return mDetector.onTouchEvent(ev);
+ }
+
+ protected float getShiftRange() {
+ return mLauncher.getAllAppsController().getShiftRange();
+ }
+
+ protected abstract float initCurrentAnimation();
+
+ @Override
+ public void onDragStart(boolean start) {
+ if (mCurrentAnimation == null) {
+ mStartProgress = 0;
+ mProgressMultiplier = initCurrentAnimation();
+
+ mCurrentAnimation.getTarget().addListener(this);
+ mCurrentAnimation.dispatchOnStart();
+ } else {
+ mCurrentAnimation.pause();
+ mStartProgress = mCurrentAnimation.getProgressFraction();
+ }
+ }
+
+ @Override
+ public boolean onDrag(float displacement, float velocity) {
+ float deltaProgress = mProgressMultiplier * displacement;
+ mCurrentAnimation.setPlayFraction(deltaProgress + mStartProgress);
+ return true;
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ final int logAction;
+ final LauncherState targetState;
+ final float progress = mCurrentAnimation.getProgressFraction();
+
+ if (fling) {
+ logAction = Touch.FLING;
+ targetState =
+ Float.compare(Math.signum(velocity), Math.signum(mProgressMultiplier)) == 0
+ ? mToState : mFromState;
+ // snap to top or bottom using the release velocity
+ } else {
+ logAction = Touch.SWIPE;
+ targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
+ }
+
+
+ final float endProgress;
+ final float startProgress;
+ final long duration;
+
+ if (targetState == mToState) {
+ endProgress = 1;
+ if (progress >= 1) {
+ duration = 0;
+ startProgress = 1;
+ } else {
+ startProgress = Utilities.boundToRange(
+ progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+ duration = SwipeDetector.calculateDuration(velocity,
+ endProgress - Math.max(progress, 0));
+ }
+ } else {
+ endProgress = 0;
+ if (progress <= 0) {
+ duration = 0;
+ startProgress = 0;
+ } else {
+ startProgress = Utilities.boundToRange(
+ progress + velocity * SINGLE_FRAME_MS / getShiftRange(), 0f, 1f);
+ duration = SwipeDetector.calculateDuration(velocity,
+ Math.min(progress, 1) - endProgress);
+ }
+ }
+
+ mCurrentAnimation.setEndAction(() -> onSwipeInteractionCompleted(targetState, logAction));
+ ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
+ anim.setFloatValues(startProgress, endProgress);
+ anim.setDuration(duration).setInterpolator(scrollInterpolatorForVelocity(velocity));
+ anim.start();
+ }
+
+ protected int getDirectionForLog() {
+ return mToState.ordinal > mFromState.ordinal ? Direction.UP : Direction.DOWN;
+ }
+
+ protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
+ if (targetState != mFromState) {
+ // Transition complete. log the action
+ mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
+ getDirectionForLog(),
+ mStartContainerType,
+ mFromState.containerType,
+ mToState.containerType,
+ mLauncher.getWorkspace().getCurrentPage());
+ }
+ clearState();
+ mLauncher.getStateManager().goToState(targetState, false /* animated */);
+ }
+
+ protected void clearState() {
+ mCurrentAnimation = null;
+ mDetector.finishedScrolling();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mCurrentAnimation != null && animation == mCurrentAnimation.getOriginalTarget()) {
+ Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
+ clearState();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index f10a695..6f012f6 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -18,6 +18,7 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -78,8 +79,8 @@
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!canStartDrag(launcher)) return false;
// When we have exited all apps or are in transition, disregard long clicks
- if (!launcher.isInState(LauncherState.ALL_APPS) ||
- launcher.getWorkspace().isSwitchingState()) return false;
+ if (!launcher.isInState(ALL_APPS) && !launcher.isInState(OVERVIEW)) return false;
+ if (launcher.getWorkspace().isSwitchingState()) return false;
// Start the drag
final DragController dragController = launcher.getDragController();
diff --git a/src/com/android/launcher3/util/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java
deleted file mode 100644
index ae5bfd5..0000000
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2017 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.launcher3.util;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-import android.util.Log;
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.touch.SwipeDetector.Direction;
-
-
-/**
- * Handles vertical touch gesture on the DragLayer allowing transitioning from
- * {@link #mBaseState} to {@link LauncherState#ALL_APPS} and vice-versa.
- */
-public abstract class VerticalSwipeController extends AnimatorListenerAdapter
- implements TouchController, SwipeDetector.Listener {
-
- private static final String TAG = "VerticalSwipeController";
-
- private static final float RECATCH_REJECTION_FRACTION = .0875f;
- private static final int SINGLE_FRAME_MS = 16;
-
- // Progress after which the transition is assumed to be a success in case user does not fling
- private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
-
- protected final Launcher mLauncher;
- protected final SwipeDetector mDetector;
- private final LauncherState mBaseState;
- private final LauncherState mTargetState;
-
- private boolean mNoIntercept;
-
- private AnimatorPlaybackController mCurrentAnimation;
- protected LauncherState mToState;
-
- private float mStartProgress;
- // Ratio of transition process [0, 1] to drag displacement (px)
- private float mProgressMultiplier;
-
- public VerticalSwipeController(Launcher l, LauncherState baseState) {
- this(l, baseState, ALL_APPS, SwipeDetector.VERTICAL);
- }
-
- public VerticalSwipeController(
- Launcher l, LauncherState baseState, LauncherState targetState, Direction dir) {
- mLauncher = l;
- mDetector = new SwipeDetector(l, this, dir);
- mBaseState = baseState;
- mTargetState = targetState;
- }
-
- private boolean canInterceptTouch(MotionEvent ev) {
- if (mCurrentAnimation != null) {
- // If we are already animating from a previous state, we can intercept.
- return true;
- }
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- return false;
- }
- return shouldInterceptTouch(ev);
- }
-
- protected abstract boolean shouldInterceptTouch(MotionEvent ev);
-
- @Override
- public void onAnimationCancel(Animator animation) {
- if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) {
- Log.e(TAG, "Who dare cancel the animation when I am in control", new Exception());
- mDetector.finishedScrolling();
- mCurrentAnimation = null;
- }
- }
-
- @Override
- public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mNoIntercept = !canInterceptTouch(ev);
- if (mNoIntercept) {
- return false;
- }
-
- // Now figure out which direction scroll events the controller will start
- // calling the callbacks.
- final int directionsToDetectScroll;
- boolean ignoreSlopWhenSettling = false;
-
- if (mCurrentAnimation != null) {
- if (mCurrentAnimation.getProgressFraction() > 1 - RECATCH_REJECTION_FRACTION) {
- directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
- } else if (mCurrentAnimation.getProgressFraction() < RECATCH_REJECTION_FRACTION ) {
- directionsToDetectScroll = SwipeDetector.DIRECTION_NEGATIVE;
- } else {
- directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
- ignoreSlopWhenSettling = true;
- }
- } else {
- directionsToDetectScroll = getSwipeDirection(ev);
- }
-
- mDetector.setDetectableScrollConditions(
- directionsToDetectScroll, ignoreSlopWhenSettling);
- }
-
- if (mNoIntercept) {
- return false;
- }
-
- onControllerTouchEvent(ev);
- return mDetector.isDraggingOrSettling();
- }
-
- protected abstract int getSwipeDirection(MotionEvent ev);
-
- @Override
- public boolean onControllerTouchEvent(MotionEvent ev) {
- return mDetector.onTouchEvent(ev);
- }
-
- @Override
- public void onDragStart(boolean start) {
- if (mCurrentAnimation == null) {
- float range = getShiftRange();
- long maxAccuracy = (long) (2 * range);
-
- // Build current animation
- mToState = mLauncher.isInState(mTargetState) ? mBaseState : mTargetState;
- mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(mToState, maxAccuracy);
- mCurrentAnimation.getTarget().addListener(this);
- mStartProgress = 0;
- mProgressMultiplier =
- (mLauncher.isInState(mTargetState) ^ isTransitionFlipped() ? 1 : -1) / range;
- mCurrentAnimation.dispatchOnStart();
- } else {
- mCurrentAnimation.pause();
- mStartProgress = mCurrentAnimation.getProgressFraction();
- }
- }
-
- protected boolean isTransitionFlipped() {
- return false;
- }
-
- protected float getShiftRange() {
- return mLauncher.getAllAppsController().getShiftRange();
- }
-
- @Override
- public boolean onDrag(float displacement, float velocity) {
- float deltaProgress = mProgressMultiplier * displacement;
- mCurrentAnimation.setPlayFraction(deltaProgress + mStartProgress);
- return true;
- }
-
- @Override
- public void onDragEnd(float velocity, boolean fling) {
- final long animationDuration;
- final LauncherState targetState;
- final float progress = mCurrentAnimation.getProgressFraction();
-
- if (fling) {
- if (velocity < 0 ^ isTransitionFlipped()) {
- targetState = mTargetState;
- } else {
- targetState = mBaseState;
- }
- animationDuration = SwipeDetector.calculateDuration(velocity,
- mToState == targetState ? (1 - progress) : progress);
- // snap to top or bottom using the release velocity
- } else {
- if (progress > SUCCESS_TRANSITION_PROGRESS) {
- targetState = mToState;
- animationDuration = SwipeDetector.calculateDuration(velocity, 1 - progress);
- } else {
- targetState = mToState == mTargetState ? mBaseState : mTargetState;
- animationDuration = SwipeDetector.calculateDuration(velocity, progress);
- }
- }
-
- mCurrentAnimation.setEndAction(() -> {
- mLauncher.getStateManager().goToState(targetState, false);
- onTransitionComplete(fling, targetState == mToState);
- mDetector.finishedScrolling();
- mCurrentAnimation = null;
- });
-
- float nextFrameProgress = Utilities.boundToRange(
- progress + velocity * SINGLE_FRAME_MS * mProgressMultiplier, 0f, 1f);
-
- ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
- anim.setFloatValues(nextFrameProgress, targetState == mToState ? 1f : 0f);
- anim.setDuration(animationDuration);
- anim.setInterpolator(scrollInterpolatorForVelocity(velocity));
- anim.start();
- }
-
- protected abstract void onTransitionComplete(boolean wasFling, boolean stateChanged);
-}