Merge "Log time spent on different UI surfaces" into ub-launcher3-master
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index eda5bb1..46eb263 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1033,7 +1033,7 @@
return;
}
- int stateOrdinal = savedState.getInt(RUNTIME_STATE, LauncherState.NORMAL.ordinal());
+ int stateOrdinal = savedState.getInt(RUNTIME_STATE, LauncherState.NORMAL.ordinal);
LauncherState[] stateValues = LauncherState.values();
LauncherState state = stateValues[stateOrdinal];
if (!state.doNotRestore) {
@@ -1502,7 +1502,7 @@
outState.putInt(RUNTIME_STATE_CURRENT_SCREEN, mWorkspace.getNextPage());
}
- outState.putInt(RUNTIME_STATE, mWorkspace.getState().ordinal());
+ outState.putInt(RUNTIME_STATE, mWorkspace.getState().ordinal);
AbstractFloatingView widgets = AbstractFloatingView
@@ -2344,7 +2344,7 @@
public boolean onLongClick(View v) {
if (!isDraggingEnabled()) return false;
if (isWorkspaceLocked()) return false;
- if (!isInState(LauncherState.NORMAL)) return false;
+ if (!isInState(LauncherState.NORMAL) && !isInState(LauncherState.OVERVIEW)) return false;
boolean ignoreLongPressToOverview =
mDeviceProfile.shouldIgnoreLongPressToOverview(mLastDispatchTouchEventX);
@@ -2539,7 +2539,7 @@
public void enterSpringLoadedDragMode() {
if (LOGD) Log.d(TAG, String.format("enterSpringLoadedDragMode [mState=%s",
- mWorkspace.getState().name()));
+ mWorkspace.getState().ordinal));
if (isInState(LauncherState.SPRING_LOADED)) {
return;
}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index c51b920..4619f4e 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -21,34 +21,41 @@
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_TRANSITION_MS;
-import static com.android.launcher3.StateFlags.FLAG_DISABLE_ACCESSIBILITY;
-import static com.android.launcher3.StateFlags.FLAG_DO_NOT_RESTORE;
-import static com.android.launcher3.StateFlags.FLAG_HIDE_HOTSEAT;
-import static com.android.launcher3.StateFlags.FLAG_MULTI_PAGE;
-import static com.android.launcher3.StateFlags.FLAG_SHOW_SCRIM;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-interface StateFlags {
- int FLAG_SHOW_SCRIM = 1 << 0;
- int FLAG_MULTI_PAGE = 1 << 1;
- int FLAG_HIDE_HOTSEAT = 1 << 2;
- int FLAG_DISABLE_ACCESSIBILITY = 1 << 3;
- int FLAG_DO_NOT_RESTORE = 1 << 4;
-}
+import java.util.Arrays;
+
/**
* Various states for launcher
*/
-public enum LauncherState {
+public class LauncherState {
- NORMAL (ContainerType.WORKSPACE, 0, FLAG_DO_NOT_RESTORE),
- ALL_APPS (ContainerType.ALLAPPS, ALL_APPS_TRANSITION_MS, FLAG_DISABLE_ACCESSIBILITY),
- SPRING_LOADED (ContainerType.WORKSPACE, SPRING_LOADED_TRANSITION_MS,
- FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE | FLAG_DISABLE_ACCESSIBILITY | FLAG_DO_NOT_RESTORE),
- OVERVIEW (ContainerType.OVERVIEW, OVERVIEW_TRANSITION_MS,
+ protected static final int FLAG_SHOW_SCRIM = 1 << 0;
+ protected static final int FLAG_MULTI_PAGE = 1 << 1;
+ protected static final int FLAG_HIDE_HOTSEAT = 1 << 2;
+ protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 3;
+ protected static final int FLAG_DO_NOT_RESTORE = 1 << 4;
+
+ private static final LauncherState[] sAllStates = new LauncherState[4];
+
+ public static LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE,
+ 0, FLAG_DO_NOT_RESTORE);
+
+ public static LauncherState ALL_APPS = new LauncherState(1, ContainerType.ALLAPPS,
+ ALL_APPS_TRANSITION_MS, FLAG_DISABLE_ACCESSIBILITY);
+
+ public static LauncherState SPRING_LOADED = new LauncherState(2, ContainerType.WORKSPACE,
+ SPRING_LOADED_TRANSITION_MS,
+ FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE | FLAG_DISABLE_ACCESSIBILITY | FLAG_DO_NOT_RESTORE);
+
+ public static LauncherState OVERVIEW = new LauncherState(3, ContainerType.OVERVIEW,
+ OVERVIEW_TRANSITION_MS,
FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE | FLAG_HIDE_HOTSEAT | FLAG_DO_NOT_RESTORE);
+ public final int ordinal;
+
/**
* Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
*/
@@ -75,7 +82,7 @@
public final boolean hideHotseat;
public final int transitionDuration;
- LauncherState(int containerType, int transitionDuration, int flags) {
+ public LauncherState(int id, int containerType, int transitionDuration, int flags) {
this.containerType = containerType;
this.transitionDuration = transitionDuration;
@@ -86,5 +93,12 @@
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO;
this.doNotRestore = (flags & FLAG_DO_NOT_RESTORE) != 0;
+
+ this.ordinal = id;
+ sAllStates[id] = this;
+ }
+
+ public static LauncherState[] values() {
+ return Arrays.copyOf(sAllStates, sAllStates.length);
}
}
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 40d5495..0e6cead 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -234,10 +234,8 @@
private void startAnimationToNewWorkspaceState(
final LauncherState toWorkspaceState, final boolean animated,
final Runnable onCompleteRunnable) {
- final View fromWorkspace = mLauncher.getWorkspace();
// Cancel the current animation
cancelAnimation();
-
mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
if (!animated) {
@@ -249,11 +247,20 @@
return;
}
+ final AnimatorSet animation =
+ createAnimationToNewWorkspace(toWorkspaceState, onCompleteRunnable);
+ mLauncher.getWorkspace().post(new StartAnimRunnable(animation, null));
+ mCurrentAnimation = animation;
+ }
+
+ protected AnimatorSet createAnimationToNewWorkspace(LauncherState state,
+ final Runnable onCompleteRunnable) {
+ cancelAnimation();
+
final AnimationLayerSet layerViews = new AnimationLayerSet();
final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
mConfig.reset();
- mLauncher.getWorkspace().setStateWithAnimation(toWorkspaceState,
- layerViews, animation, mConfig);
+ mLauncher.getWorkspace().setStateWithAnimation(state, layerViews, animation, mConfig);
animation.addListener(new AnimatorListenerAdapter() {
@Override
@@ -268,8 +275,7 @@
}
});
animation.addListener(layerViews);
- fromWorkspace.post(new StartAnimRunnable(animation, null));
- mCurrentAnimation = animation;
+ return animation;
}
/**
diff --git a/src/com/android/launcher3/PinchAnimationManager.java b/src/com/android/launcher3/PinchAnimationManager.java
deleted file mode 100644
index bbe8e89..0000000
--- a/src/com/android/launcher3/PinchAnimationManager.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * 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;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.util.Log;
-import android.view.View;
-import android.view.animation.LinearInterpolator;
-
-import com.android.launcher3.anim.AnimationLayerSet;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-/**
- * Manages the animations that play as the user pinches to/from overview mode.
- *
- * It will look like this pinching in:
- * - Workspace scales down
- * - At some threshold 1, hotseat and QSB fade out (full animation)
- * - At a later threshold 2, panel buttons fade in and scrim fades in
- * - At a final threshold 3, snap to overview
- *
- * Pinching out:
- * - Workspace scales up
- * - At threshold 1, panel buttons fade out
- * - At threshold 2, hotseat and QSB fade in and scrim fades out
- * - At threshold 3, snap to workspace
- *
- * @see PinchToOverviewListener
- * @see PinchThresholdManager
- */
-public class PinchAnimationManager {
- private static final String TAG = "PinchAnimationManager";
-
- private static final int THRESHOLD_ANIM_DURATION = 150;
- private static final LinearInterpolator INTERPOLATOR = new LinearInterpolator();
-
- private static final int INDEX_HOTSEAT = 0;
- private static final int INDEX_OVERVIEW_PANEL_BUTTONS = 1;
- private static final int INDEX_SCRIM = 2;
-
- private final Animator[] mAnimators = new Animator[3];
-
- private Launcher mLauncher;
- private Workspace mWorkspace;
-
- private float mOverviewScale;
- private float mOverviewTranslationY;
- private int mNormalOverviewTransitionDuration;
- private boolean mIsAnimating;
-
- public PinchAnimationManager(Launcher launcher) {
- mLauncher = launcher;
- mWorkspace = launcher.mWorkspace;
-
- mOverviewScale = mWorkspace.getOverviewModeShrinkFactor();
- mOverviewTranslationY = mWorkspace.getOverviewModeTranslationY();
- mNormalOverviewTransitionDuration = LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
- }
-
- public int getNormalOverviewTransitionDuration() {
- return mNormalOverviewTransitionDuration;
- }
-
- /**
- * Interpolate from {@param currentProgress} to {@param toProgress}, calling
- * {@link #setAnimationProgress(float)} throughout the duration. If duration is -1,
- * the default overview transition duration is used.
- */
- public void animateToProgress(float currentProgress, float toProgress, int duration,
- final PinchThresholdManager thresholdManager) {
- if (duration == -1) {
- duration = mNormalOverviewTransitionDuration;
- }
- ValueAnimator animator = ValueAnimator.ofFloat(currentProgress, toProgress);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float pinchProgress = (Float) animation.getAnimatedValue();
- setAnimationProgress(pinchProgress);
- thresholdManager.updateAndAnimatePassedThreshold(pinchProgress,
- PinchAnimationManager.this);
- }
- }
- );
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mIsAnimating = false;
- thresholdManager.reset();
- mWorkspace.onEndStateTransition();
- }
- });
- animator.setDuration(duration).start();
- mIsAnimating = true;
- }
-
- public boolean isAnimating() {
- return mIsAnimating;
- }
-
- /**
- * Animates to the specified progress. This should be called repeatedly throughout the pinch
- * gesture to run animations that interpolate throughout the gesture.
- * @param interpolatedProgress The progress from 0 to 1, where 0 is overview and 1 is workspace.
- */
- public void setAnimationProgress(float interpolatedProgress) {
- float interpolatedScale = interpolatedProgress * (1f - mOverviewScale) + mOverviewScale;
- float interpolatedTranslationY = (1f - interpolatedProgress) * mOverviewTranslationY;
- mWorkspace.setScaleX(interpolatedScale);
- mWorkspace.setScaleY(interpolatedScale);
- mWorkspace.setTranslationY(interpolatedTranslationY);
- int alpha = (int) ((1f - interpolatedProgress) * 255);
- setOverviewPanelsAlpha(alpha, 0);
- }
-
- /**
- * Animates certain properties based on which threshold was passed, and in what direction. The
- * starting state must also be taken into account because the thresholds mean different things
- * when going from workspace to overview and vice versa.
- * @param threshold One of {@link PinchThresholdManager#THRESHOLD_ONE},
- * {@link PinchThresholdManager#THRESHOLD_TWO}, or
- * {@link PinchThresholdManager#THRESHOLD_THREE}
- * @param startState {@link LauncherState#NORMAL} or {@link LauncherState#OVERVIEW}.
- * @param goingTowards {@link LauncherState#NORMAL} or {@link LauncherState#OVERVIEW}.
- * Note that this doesn't have to be the opposite of startState;
- */
- public void animateThreshold(float threshold, LauncherState startState,
- LauncherState goingTowards) {
- if (threshold == PinchThresholdManager.THRESHOLD_ONE) {
- if (startState == OVERVIEW) {
- animateOverviewPanelButtons(goingTowards == OVERVIEW);
- } else if (startState == NORMAL) {
- animateHotseatAndQsb(goingTowards == NORMAL);
- }
- } else if (threshold == PinchThresholdManager.THRESHOLD_TWO) {
- if (startState == OVERVIEW) {
- animateHotseatAndQsb(goingTowards == NORMAL);
- animateScrim(goingTowards == OVERVIEW);
- } else if (startState == NORMAL) {
- animateOverviewPanelButtons(goingTowards == OVERVIEW);
- animateScrim(goingTowards == OVERVIEW);
- }
- } else if (threshold == PinchThresholdManager.THRESHOLD_THREE) {
- // Passing threshold 3 ends the pinch and snaps to the new state.
- if (startState == OVERVIEW && goingTowards == NORMAL) {
- mLauncher.getUserEventDispatcher().logActionOnContainer(
- Action.Touch.PINCH, Action.Direction.NONE,
- ContainerType.OVERVIEW, mWorkspace.getCurrentPage());
- mLauncher.showWorkspace(true);
- mWorkspace.snapToPage(mWorkspace.getCurrentPage());
- } else if (startState == NORMAL && goingTowards == OVERVIEW) {
- mLauncher.getUserEventDispatcher().logActionOnContainer(
- Action.Touch.PINCH, Action.Direction.NONE,
- ContainerType.WORKSPACE, mWorkspace.getCurrentPage());
- mLauncher.showOverviewMode(true);
- }
- } else {
- Log.e(TAG, "Received unknown threshold to animate: " + threshold);
- }
- }
-
- private void setOverviewPanelsAlpha(int alpha, int duration) {
- int childCount = mWorkspace.getChildCount();
- for (int i = 0; i < childCount; i++) {
- final CellLayout cl = (CellLayout) mWorkspace.getChildAt(i);
- if (duration == 0) {
- cl.getScrimBackground().setAlpha(alpha);
- } else {
- ObjectAnimator.ofInt(cl.getScrimBackground(),
- LauncherAnimUtils.DRAWABLE_ALPHA, alpha).setDuration(duration).start();
- }
- }
- }
-
- private void animateHotseatAndQsb(boolean show) {
- startAnimator(INDEX_HOTSEAT,
- mWorkspace.createHotseatAlphaAnimator(show ? 1 : 0), THRESHOLD_ANIM_DURATION);
- }
-
- private void animateOverviewPanelButtons(boolean show) {
- animateShowHideView(INDEX_OVERVIEW_PANEL_BUTTONS, mLauncher.getOverviewPanel(), show);
- }
-
- private void animateScrim(boolean show) {
- int endValue = show ? mWorkspace.getStateTransitionAnimation().mWorkspaceScrimAlpha : 0;
- startAnimator(INDEX_SCRIM, ObjectAnimator.ofInt(
- mLauncher.getDragLayer().getScrim(), LauncherAnimUtils.DRAWABLE_ALPHA, endValue),
- mNormalOverviewTransitionDuration);
- }
-
- private void animateShowHideView(int index, final View view, boolean show) {
- Animator animator = ObjectAnimator.ofFloat(view, View.ALPHA, show ? 1 : 0);
- animator.addListener(new AnimationLayerSet(view));
- if (show) {
- view.setVisibility(View.VISIBLE);
- } else {
- animator.addListener(new AnimatorListenerAdapter() {
- private boolean mCancelled = false;
-
- @Override
- public void onAnimationCancel(Animator animation) {
- mCancelled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- if (!mCancelled) {
- view.setVisibility(View.INVISIBLE);
- }
- }
- });
- }
- startAnimator(index, animator, THRESHOLD_ANIM_DURATION);
- }
-
- private void startAnimator(int index, Animator animator, long duration) {
- if (mAnimators[index] != null) {
- mAnimators[index].cancel();
- }
- mAnimators[index] = animator;
- mAnimators[index].setInterpolator(INTERPOLATOR);
- mAnimators[index].setDuration(duration).start();
- }
-}
diff --git a/src/com/android/launcher3/PinchThresholdManager.java b/src/com/android/launcher3/PinchThresholdManager.java
deleted file mode 100644
index 4937633..0000000
--- a/src/com/android/launcher3/PinchThresholdManager.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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;
-
-/**
- * Keeps track of when thresholds are passed during a pinch gesture,
- * used to inform {@link PinchAnimationManager} throughout.
- *
- * @see PinchToOverviewListener
- * @see PinchAnimationManager
- */
-public class PinchThresholdManager {
- public static final float THRESHOLD_ZERO = 0.0f;
- public static final float THRESHOLD_ONE = 0.40f;
- public static final float THRESHOLD_TWO = 0.70f;
- public static final float THRESHOLD_THREE = 0.95f;
-
- private final Workspace mWorkspace;
- private final Launcher mLauncher;
-
- private float mPassedThreshold = THRESHOLD_ZERO;
-
- public PinchThresholdManager(Workspace workspace) {
- mWorkspace = workspace;
- mLauncher = mWorkspace.mLauncher;
- }
-
- /**
- * Uses the pinch progress to determine whether a threshold has been passed,
- * and asks the {@param animationManager} to animate if so.
- * @param progress From 0 to 1, where 0 is overview and 1 is workspace.
- * @param animationManager Animates the threshold change if one is passed.
- * @return The last passed threshold, one of
- * {@link PinchThresholdManager#THRESHOLD_ZERO},
- * {@link PinchThresholdManager#THRESHOLD_ONE},
- * {@link PinchThresholdManager#THRESHOLD_TWO}, or
- * {@link PinchThresholdManager#THRESHOLD_THREE}
- */
- public float updateAndAnimatePassedThreshold(float progress,
- PinchAnimationManager animationManager) {
- if (!mLauncher.isInState(LauncherState.OVERVIEW)) {
- // Invert the progress, because going from workspace to overview is 1 to 0.
- progress = 1f - progress;
- }
-
- float previousPassedThreshold = mPassedThreshold;
-
- if (progress < THRESHOLD_ONE) {
- mPassedThreshold = THRESHOLD_ZERO;
- } else if (progress < THRESHOLD_TWO) {
- mPassedThreshold = THRESHOLD_ONE;
- } else if (progress < THRESHOLD_THREE) {
- mPassedThreshold = THRESHOLD_TWO;
- } else {
- mPassedThreshold = THRESHOLD_THREE;
- }
-
- if (mPassedThreshold != previousPassedThreshold) {
- LauncherState fromState = mLauncher.getWorkspace().getState();
- LauncherState toState = mLauncher.isInState(LauncherState.OVERVIEW)
- ? LauncherState.NORMAL : LauncherState.OVERVIEW;
- float thresholdToAnimate = mPassedThreshold;
- if (mPassedThreshold < previousPassedThreshold) {
- // User reversed pinch, so heading back to the state that they started from.
- toState = fromState;
- thresholdToAnimate = previousPassedThreshold;
- }
- animationManager.animateThreshold(thresholdToAnimate, fromState, toState);
- }
- return mPassedThreshold;
- }
-
- public float getPassedThreshold() {
- return mPassedThreshold;
- }
-
- public void reset() {
- mPassedThreshold = THRESHOLD_ZERO;
- }
-}
diff --git a/src/com/android/launcher3/PinchToOverviewListener.java b/src/com/android/launcher3/PinchToOverviewListener.java
index a1288b4..47113c9 100644
--- a/src/com/android/launcher3/PinchToOverviewListener.java
+++ b/src/com/android/launcher3/PinchToOverviewListener.java
@@ -16,49 +16,52 @@
package com.android.launcher3;
-import android.animation.TimeInterpolator;
-import android.content.Context;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.util.Range;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
+import android.view.ScaleGestureDetector.OnScaleGestureListener;
import com.android.launcher3.util.TouchController;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
/**
* Detects pinches and animates the Workspace to/from overview mode.
- *
- * Usage: Pass MotionEvents to onInterceptTouchEvent() and onTouchEvent(). This class will handle
- * the pinch detection, and use {@link PinchAnimationManager} to handle the animations.
- *
- * @see PinchThresholdManager
- * @see PinchAnimationManager
*/
-public class PinchToOverviewListener extends ScaleGestureDetector.SimpleOnScaleGestureListener
- implements TouchController {
- private static final float OVERVIEW_PROGRESS = 0f;
- private static final float WORKSPACE_PROGRESS = 1f;
+@TargetApi(Build.VERSION_CODES.O)
+public class PinchToOverviewListener
+ implements TouchController, OnScaleGestureListener, Runnable {
+
+ private static final float ACCEPT_THRESHOLD = 0.65f;
/**
* The velocity threshold at which a pinch will be completed instead of canceled,
- * even if the first threshold has not been passed. Measured in progress / millisecond
+ * even if the first threshold has not been passed. Measured in scale / millisecond
*/
- private static final float FLING_VELOCITY = 0.003f;
+ private static final float FLING_VELOCITY = 0.001f;
- private ScaleGestureDetector mPinchDetector;
+ private final ScaleGestureDetector mPinchDetector;
private Launcher mLauncher;
private Workspace mWorkspace = null;
private boolean mPinchStarted = false;
- private float mPreviousProgress;
- private float mProgressDelta;
- private long mPreviousTimeMillis;
- private long mTimeDelta;
- private boolean mPinchCanceled = false;
- private TimeInterpolator mInterpolator;
- private PinchThresholdManager mThresholdManager;
- private PinchAnimationManager mAnimationManager;
+ private AnimatorSet mCurrentAnimation;
+ private float mCurrentScale;
+ private Range<Integer> mDurationRange;
+ private boolean mShouldGoToFinalState;
+
+ private LauncherState mToState;
public PinchToOverviewListener(Launcher launcher) {
mLauncher = launcher;
- mPinchDetector = new ScaleGestureDetector((Context) mLauncher, this);
+ mPinchDetector = new ScaleGestureDetector(mLauncher, this);
}
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
@@ -67,24 +70,17 @@
}
public boolean onControllerTouchEvent(MotionEvent ev) {
- if (mPinchStarted) {
- if (ev.getPointerCount() > 2) {
- // Using more than two fingers causes weird behavior, so just cancel the pinch.
- cancelPinch(mPreviousProgress, -1);
- } else {
- return mPinchDetector.onTouchEvent(ev);
- }
- }
- return false;
+ return mPinchDetector.onTouchEvent(ev);
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
- if (!mLauncher.isInState(LauncherState.NORMAL)) {
+ if (!mLauncher.isInState(LauncherState.NORMAL)
+ && !mLauncher.isInState(LauncherState.OVERVIEW)) {
// Don't listen for the pinch gesture if on all apps, widget picker, -1, etc.
return false;
}
- if (mAnimationManager != null && mAnimationManager.isAnimating()) {
+ if (mCurrentAnimation != null) {
// Don't listen for the pinch gesture if we are already animating from a previous one.
return false;
}
@@ -94,8 +90,6 @@
}
if (mWorkspace == null) {
mWorkspace = mLauncher.getWorkspace();
- mThresholdManager = new PinchThresholdManager(mWorkspace);
- mAnimationManager = new PinchAnimationManager(mLauncher);
}
if (mWorkspace.isSwitchingState() || mWorkspace.mScrollInteractionBegan) {
// Don't listen for the pinch gesture while switching state, as it will cause a jump
@@ -107,109 +101,87 @@
return false;
}
- mPreviousProgress = mLauncher.isInState(LauncherState.OVERVIEW) ? OVERVIEW_PROGRESS : WORKSPACE_PROGRESS;
- mPreviousTimeMillis = System.currentTimeMillis();
- mInterpolator = mLauncher.isInState(LauncherState.OVERVIEW) ? new LogDecelerateInterpolator(100, 0)
- : new LogAccelerateInterpolator(100, 0);
- mPinchStarted = true;
- mWorkspace.onPrepareStateTransition(true);
- return true;
- }
-
- @Override
- public void onScaleEnd(ScaleGestureDetector detector) {
- super.onScaleEnd(detector);
-
- float progressVelocity = mProgressDelta / mTimeDelta;
- float passedThreshold = mThresholdManager.getPassedThreshold();
- boolean isFling = mLauncher.isInState(LauncherState.OVERVIEW) && progressVelocity >= FLING_VELOCITY
- || !mLauncher.isInState(LauncherState.OVERVIEW) && progressVelocity <= -FLING_VELOCITY;
- boolean shouldCancelPinch = !isFling && passedThreshold < PinchThresholdManager.THRESHOLD_ONE;
- // If we are going towards overview, mPreviousProgress is how much further we need to
- // go, since it is going from 1 to 0. If we are going to workspace, we want
- // 1 - mPreviousProgress.
- float remainingProgress = mPreviousProgress;
- if (mLauncher.isInState(LauncherState.OVERVIEW) || shouldCancelPinch) {
- remainingProgress = 1f - mPreviousProgress;
- }
- int duration = computeDuration(remainingProgress, progressVelocity);
- if (shouldCancelPinch) {
- cancelPinch(mPreviousProgress, duration);
- } else if (passedThreshold < PinchThresholdManager.THRESHOLD_THREE) {
- float toProgress = mLauncher.isInState(LauncherState.OVERVIEW) ?
- WORKSPACE_PROGRESS : OVERVIEW_PROGRESS;
- mAnimationManager.animateToProgress(mPreviousProgress, toProgress, duration,
- mThresholdManager);
- } else {
- mThresholdManager.reset();
- mWorkspace.onEndStateTransition();
- }
- mPinchStarted = false;
- mPinchCanceled = false;
- }
-
- /**
- * Compute the amount of time required to complete the transition based on the current pinch
- * speed. If this time is too long, instead return the normal duration, ignoring the speed.
- */
- private int computeDuration(float remainingProgress, float progressVelocity) {
- float progressSpeed = Math.abs(progressVelocity);
- int remainingMillis = (int) (remainingProgress / progressSpeed);
- return Math.min(remainingMillis, mAnimationManager.getNormalOverviewTransitionDuration());
- }
-
- /**
- * Cancels the current pinch, returning back to where the pinch started (either workspace or
- * overview). If duration is -1, the default overview transition duration is used.
- */
- private void cancelPinch(float currentProgress, int duration) {
- if (mPinchCanceled) return;
- mPinchCanceled = true;
- float toProgress = mLauncher.isInState(LauncherState.OVERVIEW) ? OVERVIEW_PROGRESS : WORKSPACE_PROGRESS;
- mAnimationManager.animateToProgress(currentProgress, toProgress, duration,
- mThresholdManager);
- mPinchStarted = false;
- }
-
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- if (mThresholdManager.getPassedThreshold() == PinchThresholdManager.THRESHOLD_THREE) {
- // We completed the pinch, so stop listening to further movement until user lets go.
- return true;
- }
if (mLauncher.getDragController().isDragging()) {
mLauncher.getDragController().cancelDrag();
}
- float pinchDist = detector.getCurrentSpan() - detector.getPreviousSpan();
- if (pinchDist < 0 && mLauncher.isInState(LauncherState.OVERVIEW) ||
- pinchDist > 0 && !mLauncher.isInState(LauncherState.OVERVIEW)) {
- // Pinching the wrong way, so ignore.
- return false;
- }
- // Pinch distance must equal the workspace width before switching states.
- int pinchDistanceToCompleteTransition = mWorkspace.getWidth();
- float overviewScale = mWorkspace.getOverviewModeShrinkFactor();
- float initialWorkspaceScale = mLauncher.isInState(LauncherState.OVERVIEW) ? overviewScale : 1f;
- float pinchScale = initialWorkspaceScale + pinchDist / pinchDistanceToCompleteTransition;
- // Bound the scale between the overview scale and the normal workspace scale (1f).
- pinchScale = Math.max(overviewScale, Math.min(pinchScale, 1f));
- // Progress ranges from 0 to 1, where 0 corresponds to the overview scale and 1
- // corresponds to the normal workspace scale (1f).
- float progress = (pinchScale - overviewScale) / (1f - overviewScale);
- float interpolatedProgress = mInterpolator.getInterpolation(progress);
+ mToState = mLauncher.isInState(LauncherState.OVERVIEW)
+ ? LauncherState.NORMAL : LauncherState.OVERVIEW;
+ mCurrentAnimation = mLauncher.mStateTransitionAnimation
+ .createAnimationToNewWorkspace(mToState, this);
+ mPinchStarted = true;
+ mCurrentScale = 1;
+ mDurationRange = Range.create(0, LauncherAnimUtils.OVERVIEW_TRANSITION_MS);
+ mShouldGoToFinalState = false;
- mAnimationManager.setAnimationProgress(interpolatedProgress);
- float passedThreshold = mThresholdManager.updateAndAnimatePassedThreshold(
- interpolatedProgress, mAnimationManager);
- if (passedThreshold == PinchThresholdManager.THRESHOLD_THREE) {
- return true;
+ dispatchOnStart(mCurrentAnimation);
+ return true;
+ }
+
+ @Override
+ public void run() {
+ mCurrentAnimation = null;
+ mPinchStarted = false;
+ }
+
+ @Override
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ if (mShouldGoToFinalState) {
+ mCurrentAnimation.start();
+ } else {
+ mCurrentAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mToState == LauncherState.OVERVIEW) {
+ mLauncher.showWorkspace(false);
+ } else {
+ mLauncher.showOverviewMode(false);
+ }
+ }
+ });
+ mCurrentAnimation.reverse();
+ }
+ }
+
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ mCurrentScale = detector.getScaleFactor() * mCurrentScale;
+
+ // If we are zooming out, inverse the mCurrentScale so that animationFraction = [0, 1]
+ // 0 => Animation complete
+ // 1=> Animation started
+ float animationFraction = mToState ==
+ LauncherState.OVERVIEW ? mCurrentScale : (1 / mCurrentScale);
+
+ float velocity = (1 - detector.getScaleFactor()) / detector.getTimeDelta();
+ if (Math.abs(velocity) >= FLING_VELOCITY) {
+ LauncherState toState = velocity > 0 ? LauncherState.OVERVIEW : LauncherState.NORMAL;
+ mShouldGoToFinalState = toState == mToState;
+ } else {
+ mShouldGoToFinalState = animationFraction <= ACCEPT_THRESHOLD;
}
- mProgressDelta = interpolatedProgress - mPreviousProgress;
- mPreviousProgress = interpolatedProgress;
- mTimeDelta = System.currentTimeMillis() - mPreviousTimeMillis;
- mPreviousTimeMillis = System.currentTimeMillis();
- return false;
+ // Move the transition animation to that duration.
+ long playPosition = mDurationRange.clamp(
+ (int) ((1 - animationFraction) * mDurationRange.getUpper()));
+ mCurrentAnimation.setCurrentPlayTime(playPosition);
+
+ return true;
+ }
+
+ private void dispatchOnStart(Animator animator) {
+ for (AnimatorListener l : nonNullList(animator.getListeners())) {
+ l.onAnimationStart(animator);
+ }
+
+ if (animator instanceof AnimatorSet) {
+ for (Animator anim : nonNullList(((AnimatorSet) animator).getChildAnimations())) {
+ dispatchOnStart(anim);
+ }
+ }
+ }
+
+ private static <T> List<T> nonNullList(ArrayList<T> list) {
+ return list == null ? Collections.<T>emptyList() : list;
}
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 8e215b0..af56fd7 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.OVERVIEW;
+import static com.android.launcher3.LauncherState.SPRING_LOADED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -187,18 +189,15 @@
int finalBackgroundAlpha = state.hasScrim ? 255 : 0;
final float finalWorkspaceTranslationY;
- switch (state) {
- case OVERVIEW:
- mNewScale = mOverviewModeShrinkFactor;
- finalWorkspaceTranslationY = mWorkspace.getOverviewModeTranslationY();
- break;
- case SPRING_LOADED:
- mNewScale = mSpringLoadedShrinkFactor;
- finalWorkspaceTranslationY = mWorkspace.getSpringLoadedTranslationY();
- break;
- default:
- mNewScale = 1f;
- finalWorkspaceTranslationY = 0;
+ if (state == OVERVIEW) {
+ mNewScale = mOverviewModeShrinkFactor;
+ finalWorkspaceTranslationY = mWorkspace.getOverviewModeTranslationY();
+ } else if (state == SPRING_LOADED) {
+ mNewScale = mSpringLoadedShrinkFactor;
+ finalWorkspaceTranslationY = mWorkspace.getSpringLoadedTranslationY();
+ } else {
+ mNewScale = 1f;
+ finalWorkspaceTranslationY = 0;
}
int toPage = mWorkspace.getPageNearestToCenterOfScreen();
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index bc5aafc..f2bad6b 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -143,7 +143,7 @@
public void onAccessibilityStateChanged(boolean isAccessibilityEnabled) {
mPinchListener = FeatureFlags.LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW || isAccessibilityEnabled
- ? null : new PinchToOverviewListener(mLauncher);
+ || !Utilities.ATLEAST_OREO ? null : new PinchToOverviewListener(mLauncher);
}
public boolean isEventOverHotseat(MotionEvent ev) {