summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/values-sw720dp/config.xml4
-rw-r--r--res/values/config.xml5
-rw-r--r--src/com/android/launcher3/Launcher.java42
-rw-r--r--src/com/android/launcher3/LauncherClings.java2
-rw-r--r--src/com/android/launcher3/LauncherStateTransitionAnimation.java43
-rw-r--r--src/com/android/launcher3/PagedView.java4
-rw-r--r--src/com/android/launcher3/SearchDropTargetBar.java123
-rw-r--r--src/com/android/launcher3/Workspace.java532
-rw-r--r--src/com/android/launcher3/WorkspaceStateTransitionAnimation.java519
9 files changed, 653 insertions, 621 deletions
diff --git a/res/values-sw720dp/config.xml b/res/values-sw720dp/config.xml
index 3d2ca8318..af6751e60 100644
--- a/res/values-sw720dp/config.xml
+++ b/res/values-sw720dp/config.xml
@@ -6,10 +6,6 @@
<!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
<integer name="config_workspaceSpringLoadShrinkPercentage">90</integer>
-<!-- Workspace -->
- <!-- Whether or not the drop targets drop down as opposed to fade in -->
- <bool name="config_useDropTargetDownTransition">false</bool>
-
<!-- Hotseat -->
<bool name="hotseat_transpose_layout_with_orientation">false</bool>
</resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 1acace6f9..47394a1f8 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -27,7 +27,7 @@
<!-- AllApps/Customize/AppsCustomize -->
<!-- The alpha of the AppsCustomize bg in spring loaded mode -->
<integer name="config_workspaceScrimAlpha">55</integer>
- <integer name="config_workspaceUnshrinkTime">300</integer>
+ <integer name="config_workspaceUnshrinkTime">100</integer>
<integer name="config_overviewTransitionTime">250</integer>
<!-- Out of 100, the percent to shrink the workspace during spring loaded mode. -->
@@ -55,9 +55,6 @@
<integer name="config_appsCustomizeDragSlopeThreshold">150</integer>
<!-- Workspace -->
- <!-- Whether or not the drop targets drop down as opposed to fade in -->
- <bool name="config_useDropTargetDownTransition">false</bool>
-
<!-- The transition duration for the background of the drop targets -->
<integer name="config_dropTargetBgTransitionDuration">0</integer>
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2bfb29ef6..7364a9f20 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -214,7 +214,6 @@ public class Launcher extends Activity
/** The different states that Launcher can be in. */
enum State { NONE, WORKSPACE, APPS, APPS_SPRING_LOADED, WIDGETS, WIDGETS_SPRING_LOADED };
@Thunk State mState = State.WORKSPACE;
- @Thunk AnimatorSet mStateAnimation;
@Thunk LauncherStateTransitionAnimation mStateTransitionAnimation;
private boolean mIsSafeModeEnabled;
@@ -528,7 +527,8 @@ public class Launcher extends Activity
@Override
public void dismissAllApps() {
- showWorkspace(true);
+ showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, true, null,
+ false /* notifyLauncherCallbacks */);
}
});
return true;
@@ -785,7 +785,7 @@ public class Launcher extends Activity
return;
} else if (requestCode == REQUEST_PICK_WALLPAPER) {
if (resultCode == RESULT_OK && mWorkspace.isInOverviewMode()) {
- mWorkspace.exitOverviewMode(false);
+ showWorkspace(false);
}
return;
}
@@ -1220,7 +1220,6 @@ public class Launcher extends Activity
return false;
}
-
public void addToCustomContentPage(View customContent,
CustomContentCallbacks callbacks, String description) {
mWorkspace.addToCustomContentPage(customContent, callbacks, description);
@@ -2480,7 +2479,7 @@ public class Launcher extends Activity
} else if (isWidgetsViewVisible()) {
showOverviewMode(true);
} else if (mWorkspace.isInOverviewMode()) {
- mWorkspace.exitOverviewMode(true);
+ showWorkspace(true);
} else if (mWorkspace.getOpenFolder() != null) {
Folder openFolder = mWorkspace.getOpenFolder();
if (openFolder.isEditingName()) {
@@ -2523,14 +2522,14 @@ public class Launcher extends Activity
if (v instanceof Workspace) {
if (mWorkspace.isInOverviewMode()) {
- mWorkspace.exitOverviewMode(true);
+ showWorkspace(true);
}
return;
}
if (v instanceof CellLayout) {
if (mWorkspace.isInOverviewMode()) {
- mWorkspace.exitOverviewMode(mWorkspace.indexOfChild(v), true);
+ showWorkspace(mWorkspace.indexOfChild(v), true);
}
}
@@ -3178,7 +3177,9 @@ public class Launcher extends Activity
if (v instanceof Workspace) {
if (!mWorkspace.isInOverviewMode()) {
- if (mWorkspace.enterOverviewMode()) {
+
+ if (!mWorkspace.isTouchActive()) {
+ showOverviewMode(true);
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
return true;
@@ -3211,7 +3212,7 @@ public class Launcher extends Activity
if (mWorkspace.isInOverviewMode()) {
mWorkspace.startReordering(v);
} else {
- mWorkspace.enterOverviewMode();
+ showOverviewMode(true);
}
} else {
final boolean isAllAppsButton = inHotseat && isAllAppsButtonRank(
@@ -3302,17 +3303,28 @@ public class Launcher extends Activity
}
protected void showWorkspace(boolean animated) {
- showWorkspace(animated, null);
+ showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, null,
+ true);
+ }
+
+ protected void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
+ showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated,
+ onCompleteRunnable, true);
+ }
+
+ protected void showWorkspace(int snapToPage, boolean animated) {
+ showWorkspace(snapToPage, animated, null, true);
}
- void showWorkspace(boolean animated, Runnable onCompleteRunnable) {
+ void showWorkspace(int snapToPage, boolean animated, Runnable onCompleteRunnable,
+ boolean notifyLauncherCallbacks) {
boolean changed = mState != State.WORKSPACE ||
mWorkspace.getState() != Workspace.State.NORMAL;
if (changed) {
boolean wasInSpringLoadedMode = (mState != State.WORKSPACE);
mWorkspace.setVisibility(View.VISIBLE);
mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.NORMAL,
- animated, onCompleteRunnable);
+ snapToPage, animated, onCompleteRunnable);
// Show the search bar (only animate if we were showing the drop target bar in spring
// loaded mode)
@@ -3345,7 +3357,8 @@ public class Launcher extends Activity
void showOverviewMode(boolean animated) {
mWorkspace.setVisibility(View.VISIBLE);
mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.OVERVIEW,
- animated, null /* onCompleteRunnable */);
+ WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated,
+ null /* onCompleteRunnable */);
mState = State.WORKSPACE;
onWorkspaceShown(animated);
}
@@ -3419,7 +3432,8 @@ public class Launcher extends Activity
}
mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.SPRING_LOADED,
- true /* animated */, null /* onCompleteRunnable */);
+ WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, true /* animated */,
+ null /* onCompleteRunnable */);
mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED;
}
diff --git a/src/com/android/launcher3/LauncherClings.java b/src/com/android/launcher3/LauncherClings.java
index 2ce8b1c59..a2c56a91c 100644
--- a/src/com/android/launcher3/LauncherClings.java
+++ b/src/com/android/launcher3/LauncherClings.java
@@ -126,7 +126,7 @@ class LauncherClings implements OnClickListener {
@Override
public boolean onLongClick(View v) {
- mLauncher.getWorkspace().enterOverviewMode();
+ mLauncher.showOverviewMode(true);
dismissLongPressCling();
return true;
}
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 8ba5c60f3..f91cfa07b 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -23,7 +23,6 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.TimeInterpolator;
import android.content.res.Resources;
-import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.ViewAnimationUtils;
@@ -174,7 +173,8 @@ public class LauncherStateTransitionAnimation {
}
};
startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, toView, toView.getContentView(),
- toView.getRevealView(), animated, false /* hideSearchBar */, cb);
+ toView.getRevealView(), animated,
+ !mLauncher.isAllAppsSearchOverridden() /* hideSearchBar */, cb);
}
/**
@@ -207,8 +207,8 @@ public class LauncherStateTransitionAnimation {
* Starts and animation to the workspace from the current overlay view.
*/
public void startAnimationToWorkspace(final Launcher.State fromState,
- final Workspace.State toWorkspaceState, final boolean animated,
- final Runnable onCompleteRunnable) {
+ final Workspace.State toWorkspaceState, final int toWorkspacePage,
+ final boolean animated, final Runnable onCompleteRunnable) {
if (toWorkspaceState != Workspace.State.NORMAL &&
toWorkspaceState != Workspace.State.SPRING_LOADED &&
toWorkspaceState != Workspace.State.OVERVIEW) {
@@ -216,11 +216,11 @@ public class LauncherStateTransitionAnimation {
}
if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) {
- startAnimationToWorkspaceFromAllApps(fromState, toWorkspaceState, animated,
- onCompleteRunnable);
+ startAnimationToWorkspaceFromAllApps(fromState, toWorkspaceState, toWorkspacePage,
+ animated, onCompleteRunnable);
} else {
- startAnimationToWorkspaceFromWidgets(fromState, toWorkspaceState, animated,
- onCompleteRunnable);
+ startAnimationToWorkspaceFromWidgets(fromState, toWorkspaceState, toWorkspacePage,
+ animated, onCompleteRunnable);
}
}
@@ -249,8 +249,8 @@ public class LauncherStateTransitionAnimation {
// Create the workspace animation.
// NOTE: this call apparently also sets the state for the workspace if !animated
- Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
- toWorkspaceState, animated, layerViews);
+ Animator workspaceAnim = mLauncher.getWorkspace().setStateWithAnimation(
+ toWorkspaceState, -1, animated, layerViews);
if (animated && initialized) {
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
@@ -424,8 +424,8 @@ public class LauncherStateTransitionAnimation {
* Starts and animation to the workspace from the apps view.
*/
private void startAnimationToWorkspaceFromAllApps(final Launcher.State fromState,
- final Workspace.State toWorkspaceState, final boolean animated,
- final Runnable onCompleteRunnable) {
+ final Workspace.State toWorkspaceState, final int toWorkspacePage,
+ final boolean animated, final Runnable onCompleteRunnable) {
AppsContainerView appsView = mLauncher.getAppsView();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
int[] mAllAppsToPanelDelta;
@@ -477,16 +477,17 @@ public class LauncherStateTransitionAnimation {
};
}
};
- startAnimationToWorkspaceFromOverlay(toWorkspaceState, appsView, appsView.getContentView(),
- appsView.getRevealView(), animated, onCompleteRunnable, cb);
+ startAnimationToWorkspaceFromOverlay(toWorkspaceState, toWorkspacePage, appsView,
+ appsView.getContentView(), appsView.getRevealView(), animated, onCompleteRunnable,
+ cb);
}
/**
* Starts and animation to the workspace from the widgets view.
*/
private void startAnimationToWorkspaceFromWidgets(final Launcher.State fromState,
- final Workspace.State toWorkspaceState, final boolean animated,
- final Runnable onCompleteRunnable) {
+ final Workspace.State toWorkspaceState, final int toWorkspacePage,
+ final boolean animated, final Runnable onCompleteRunnable) {
final WidgetsContainerView widgetsView = mLauncher.getWidgetsView();
final Resources res = mLauncher.getResources();
PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() {
@@ -514,7 +515,7 @@ public class LauncherStateTransitionAnimation {
};
}
};
- startAnimationToWorkspaceFromOverlay(toWorkspaceState, widgetsView,
+ startAnimationToWorkspaceFromOverlay(toWorkspaceState, toWorkspacePage, widgetsView,
widgetsView.getContentView(), widgetsView.getRevealView(), animated,
onCompleteRunnable, cb);
}
@@ -523,8 +524,8 @@ public class LauncherStateTransitionAnimation {
* Creates and starts a new animation to the workspace.
*/
private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState,
- final View fromView, final View contentView, final View revealView,
- final boolean animated, final Runnable onCompleteRunnable,
+ final int toWorkspacePage, final View fromView, final View contentView,
+ final View revealView, final boolean animated, final Runnable onCompleteRunnable,
final PrivateTransitionCallbacks pCb) {
final Resources res = mLauncher.getResources();
final boolean material = Utilities.isLmpOrAbove();
@@ -545,8 +546,8 @@ public class LauncherStateTransitionAnimation {
// Create the workspace animation.
// NOTE: this call apparently also sets the state for the workspace if !animated
- Animator workspaceAnim = mLauncher.getWorkspace().getChangeStateAnimation(
- toWorkspaceState, animated, layerViews);
+ Animator workspaceAnim = mLauncher.getWorkspace().setStateWithAnimation(
+ toWorkspaceState, toWorkspacePage, animated, layerViews);
if (animated && initialized) {
mStateAnimation = LauncherAnimUtils.createAnimatorSet();
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 88295c084..a4593ecb4 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1696,11 +1696,11 @@ public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarc
return OVERSCROLL_DAMP_FACTOR * f;
}
- protected void enableFreeScroll() {
+ public void enableFreeScroll() {
setEnableFreeScroll(true);
}
- protected void disableFreeScroll() {
+ public void disableFreeScroll() {
setEnableFreeScroll(false);
}
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
index a8dcd0f06..af8bc7580 100644
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ b/src/com/android/launcher3/SearchDropTargetBar.java
@@ -33,18 +33,16 @@ import android.widget.FrameLayout;
*/
public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener {
- private static final int sTransitionInDuration = 200;
- private static final int sTransitionOutDuration = 175;
+ private static final int TRANSITION_DURATION = 200;
- private ObjectAnimator mDropTargetBarAnim;
- private ValueAnimator mQSBSearchBarAnim;
+ private ObjectAnimator mShowDropTargetBarAnim;
+ private ValueAnimator mHideSearchBarAnim;
private static final AccelerateInterpolator sAccelerateInterpolator =
new AccelerateInterpolator();
private boolean mIsSearchBarHidden;
private View mQSBSearchBar;
private View mDropTargetBar;
- private int mBarHeight;
private boolean mDeferOnDragEnd = false;
// Drop targets
@@ -52,8 +50,6 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
private ButtonDropTarget mDeleteDropTarget;
private ButtonDropTarget mUninstallDropTarget;
- private boolean mEnableDropDownDropTargets;
-
public SearchDropTargetBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -82,17 +78,12 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
public void setQsbSearchBar(View qsb) {
mQSBSearchBar = qsb;
if (mQSBSearchBar != null) {
- if (mEnableDropDownDropTargets) {
- mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "translationY", 0,
- -mBarHeight);
- } else {
- mQSBSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
- }
- setupAnimation(mQSBSearchBarAnim, mQSBSearchBar);
+ mHideSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f);
+ setupAnimation(mHideSearchBarAnim, mQSBSearchBar);
} else {
// Create a no-op animation of the search bar is null
- mQSBSearchBarAnim = ValueAnimator.ofFloat(0, 0);
- mQSBSearchBarAnim.setDuration(sTransitionInDuration);
+ mHideSearchBarAnim = ValueAnimator.ofFloat(0, 0);
+ mHideSearchBarAnim.setDuration(TRANSITION_DURATION);
}
}
@@ -106,7 +97,7 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
private void setupAnimation(ValueAnimator anim, final View v) {
anim.setInterpolator(sAccelerateInterpolator);
- anim.setDuration(sTransitionInDuration);
+ anim.setDuration(TRANSITION_DURATION);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -131,76 +122,74 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
mDeleteDropTarget.setSearchDropTargetBar(this);
mUninstallDropTarget.setSearchDropTargetBar(this);
- mEnableDropDownDropTargets =
- getResources().getBoolean(R.bool.config_useDropTargetDownTransition);
-
// Create the various fade animations
- if (mEnableDropDownDropTargets) {
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- mBarHeight = grid.searchBarSpaceHeightPx;
- mDropTargetBar.setTranslationY(-mBarHeight);
- mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "translationY",
- -mBarHeight, 0f);
-
- } else {
- mDropTargetBar.setAlpha(0f);
- mDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
- }
- setupAnimation(mDropTargetBarAnim, mDropTargetBar);
+ mDropTargetBar.setAlpha(0f);
+ mShowDropTargetBarAnim = LauncherAnimUtils.ofFloat(mDropTargetBar, "alpha", 0f, 1f);
+ setupAnimation(mShowDropTargetBarAnim, mDropTargetBar);
}
+ /**
+ * Finishes all the animations on the search and drop target bars.
+ */
public void finishAnimations() {
prepareStartAnimation(mDropTargetBar);
- mDropTargetBarAnim.reverse();
+ mShowDropTargetBarAnim.reverse();
prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.reverse();
+ mHideSearchBarAnim.reverse();
}
- /*
- * Shows and hides the search bar.
+ /**
+ * Shows the search bar.
*/
public void showSearchBar(boolean animated) {
- boolean needToCancelOngoingAnimation = mQSBSearchBarAnim.isRunning() && !animated;
- if (!mIsSearchBarHidden && !needToCancelOngoingAnimation) return;
+ if (!mIsSearchBarHidden) return;
if (animated) {
prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.reverse();
+ mHideSearchBarAnim.reverse();
} else {
- mQSBSearchBarAnim.cancel();
- if (mQSBSearchBar != null && mEnableDropDownDropTargets) {
- mQSBSearchBar.setTranslationY(0);
- } else if (mQSBSearchBar != null) {
+ mHideSearchBarAnim.cancel();
+ if (mQSBSearchBar != null) {
mQSBSearchBar.setAlpha(1f);
}
}
mIsSearchBarHidden = false;
}
+
+ /**
+ * Hides the search bar. We only use this for clings.
+ */
public void hideSearchBar(boolean animated) {
- boolean needToCancelOngoingAnimation = mQSBSearchBarAnim.isRunning() && !animated;
- if (mIsSearchBarHidden && !needToCancelOngoingAnimation) return;
+ if (mIsSearchBarHidden) return;
if (animated) {
prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.start();
+ mHideSearchBarAnim.start();
} else {
- mQSBSearchBarAnim.cancel();
- if (mQSBSearchBar != null && mEnableDropDownDropTargets) {
- mQSBSearchBar.setTranslationY(-mBarHeight);
- } else if (mQSBSearchBar != null) {
+ mHideSearchBarAnim.cancel();
+ if (mQSBSearchBar != null) {
mQSBSearchBar.setAlpha(0f);
}
}
mIsSearchBarHidden = true;
}
- /*
- * Gets various transition durations.
+ /**
+ * Shows the drop target bar.
*/
- public int getTransitionInDuration() {
- return sTransitionInDuration;
+ public void showDeleteTarget() {
+ // Animate out the QSB search bar, and animate in the drop target bar
+ prepareStartAnimation(mDropTargetBar);
+ mShowDropTargetBarAnim.start();
+ hideSearchBar(true);
}
- public int getTransitionOutDuration() {
- return sTransitionOutDuration;
+
+ /**
+ * Hides the drop target bar.
+ */
+ public void hideDeleteTarget() {
+ // Restore the QSB search bar, and animate out the drop target bar
+ prepareStartAnimation(mDropTargetBar);
+ mShowDropTargetBarAnim.reverse();
+ showSearchBar(true);
}
/*
@@ -211,26 +200,6 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
showDeleteTarget();
}
- public void showDeleteTarget() {
- // Animate out the QSB search bar, and animate in the drop target bar
- prepareStartAnimation(mDropTargetBar);
- mDropTargetBarAnim.start();
- if (!mIsSearchBarHidden) {
- prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.start();
- }
- }
-
- public void hideDeleteTarget() {
- // Restore the QSB search bar, and animate out the drop target bar
- prepareStartAnimation(mDropTargetBar);
- mDropTargetBarAnim.reverse();
- if (!mIsSearchBarHidden) {
- prepareStartAnimation(mQSBSearchBar);
- mQSBSearchBarAnim.reverse();
- }
- }
-
public void deferOnDragEnd() {
mDeferOnDragEnd = true;
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 6b03e3100..9e680fb82 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -17,15 +17,10 @@
package com.android.launcher3;
import android.animation.Animator;
-import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.TargetApi;
import android.app.WallpaperManager;
import android.appwidget.AppWidgetHostView;
@@ -99,12 +94,9 @@ public class Workspace extends SmoothPagedView
protected static final int SNAP_OFF_EMPTY_SCREEN_DURATION = 400;
protected static final int FADE_EMPTY_SCREEN_DURATION = 150;
- private static final int BACKGROUND_FADE_OUT_DURATION = 350;
private static final int ADJACENT_SCREEN_DROP_DURATION = 300;
private static final int FLING_THRESHOLD_VELOCITY = 500;
- private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
-
static final boolean MAP_NO_RECURSE = false;
static final boolean MAP_RECURSE = true;
@@ -113,10 +105,6 @@ public class Workspace extends SmoothPagedView
private ObjectAnimator mChildrenOutlineFadeOutAnimation;
private float mChildrenOutlineAlpha = 0;
- // These properties refer to the background protection gradient used for AllApps and Customize
- private ValueAnimator mBackgroundFadeInAnimation;
- private ValueAnimator mBackgroundFadeOutAnimation;
-
private static final long CUSTOM_CONTENT_GESTURE_DELAY = 200;
private long mTouchDownTime = -1;
private long mCustomContentShowTime = -1;
@@ -129,7 +117,6 @@ public class Workspace extends SmoothPagedView
private int mDefaultPage;
private ShortcutAndWidgetContainer mDragSourceInternal;
- @Thunk static boolean sAccessibilityEnabled;
// The screen id used for the empty screen always present to the right.
final static long EXTRA_EMPTY_SCREEN_ID = -201;
@@ -272,14 +259,7 @@ public class Workspace extends SmoothPagedView
private float mSavedTranslationX;
private float mCurrentScale;
- private float mNewScale;
- @Thunk float[] mOldBackgroundAlphas;
- private float[] mOldAlphas;
- @Thunk float[] mNewBackgroundAlphas;
- private float[] mNewAlphas;
- private int mLastChildCount = -1;
private float mTransitionProgress;
- @Thunk Animator mStateAnimator = null;
float mOverScrollEffect = 0f;
@@ -294,6 +274,9 @@ public class Workspace extends SmoothPagedView
boolean mShouldSendPageSettled;
int mLastOverlaySroll = 0;
+ // Handles workspace state transitions
+ private WorkspaceStateTransitionAnimation mStateTransitionAnimation;
+
private final Runnable mBindPages = new Runnable() {
@Override
public void run() {
@@ -329,6 +312,7 @@ public class Workspace extends SmoothPagedView
setDataIsReady();
mLauncher = (Launcher) context;
+ mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this);
final Resources res = getResources();
mWorkspaceFadeInAdjacentScreens = LauncherAppState.getInstance().getDynamicGrid().
getDeviceProfile().shouldFadeAdjacentWorkspaceScreens();
@@ -1583,37 +1567,6 @@ public class Workspace extends SmoothPagedView
return mChildrenOutlineAlpha;
}
- private void animateBackgroundGradient(float finalAlpha, boolean animated) {
- final DragLayer dragLayer = mLauncher.getDragLayer();
-
- if (mBackgroundFadeInAnimation != null) {
- mBackgroundFadeInAnimation.cancel();
- mBackgroundFadeInAnimation = null;
- }
- if (mBackgroundFadeOutAnimation != null) {
- mBackgroundFadeOutAnimation.cancel();
- mBackgroundFadeOutAnimation = null;
- }
- float startAlpha = dragLayer.getBackgroundAlpha();
- if (finalAlpha != startAlpha) {
- if (animated) {
- mBackgroundFadeOutAnimation =
- LauncherAnimUtils.ofFloat(this, startAlpha, finalAlpha);
- mBackgroundFadeOutAnimation.addUpdateListener(new AnimatorUpdateListener() {
- public void onAnimationUpdate(ValueAnimator animation) {
- dragLayer.setBackgroundAlpha(
- ((Float)animation.getAnimatedValue()).floatValue());
- }
- });
- mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
- mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
- mBackgroundFadeOutAnimation.start();
- } else {
- dragLayer.setBackgroundAlpha(finalAlpha);
- }
- }
- }
-
float backgroundAlphaInterpolator(float r) {
float pivotA = 0.1f;
float pivotB = 0.4f;
@@ -1737,7 +1690,7 @@ public class Workspace extends SmoothPagedView
OnClickListener listener = new OnClickListener() {
@Override
public void onClick(View arg0) {
- enterOverviewMode();
+ mLauncher.showOverviewMode(true);
}
};
return listener;
@@ -1797,9 +1750,6 @@ public class Workspace extends SmoothPagedView
getPageIndicator().setOnClickListener(listener);
}
}
- AccessibilityManager am = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
- sAccessibilityEnabled = am.isEnabled();
// Update wallpaper dimensions if they were changed since last onResume
// (we also always set the wallpaper dimensions in the constructor)
@@ -1970,64 +1920,6 @@ public class Workspace extends SmoothPagedView
}
/*
- * This interpolator emulates the rate at which the perceived scale of an object changes
- * as its distance from a camera increases. When this interpolator is applied to a scale
- * animation on a view, it evokes the sense that the object is shrinking due to moving away
- * from the camera.
- */
- static class ZInterpolator implements TimeInterpolator {
- private float focalLength;
-
- public ZInterpolator(float foc) {
- focalLength = foc;
- }
-
- public float getInterpolation(float input) {
- return (1.0f - focalLength / (focalLength + input)) /
- (1.0f - focalLength / (focalLength + 1.0f));
- }
- }
-
- /*
- * The exact reverse of ZInterpolator.
- */
- static class InverseZInterpolator implements TimeInterpolator {
- private ZInterpolator zInterpolator;
- public InverseZInterpolator(float foc) {
- zInterpolator = new ZInterpolator(foc);
- }
- public float getInterpolation(float input) {
- return 1 - zInterpolator.getInterpolation(1 - input);
- }
- }
-
- /*
- * ZInterpolator compounded with an ease-out.
- */
- static class ZoomOutInterpolator implements TimeInterpolator {
- private final DecelerateInterpolator decelerate = new DecelerateInterpolator(0.75f);
- private final ZInterpolator zInterpolator = new ZInterpolator(0.13f);
-
- public float getInterpolation(float input) {
- return decelerate.getInterpolation(zInterpolator.getInterpolation(input));
- }
- }
-
- /*
- * InvereZInterpolator compounded with an ease-out.
- */
- static class ZoomInInterpolator implements TimeInterpolator {
- private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
- private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
-
- public float getInterpolation(float input) {
- return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
- }
- }
-
- private final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
-
- /*
*
* We call these methods (onDragStartedWithItemSpans/onDragStartedWithSize) whenever we
* start a drag in Launcher, regardless of whether the drag has ever entered the Workspace
@@ -2090,21 +1982,6 @@ public class Workspace extends SmoothPagedView
dragLayer.clearAllResizeFrames();
}
- private void initAnimationArrays() {
- final int childCount = getChildCount();
- if (mLastChildCount == childCount) return;
-
- mOldBackgroundAlphas = new float[childCount];
- mOldAlphas = new float[childCount];
- mNewBackgroundAlphas = new float[childCount];
- mNewAlphas = new float[childCount];
- }
-
- Animator getChangeStateAnimation(final State state, boolean animated,
- HashMap<View, Integer> layerViews) {
- return getChangeStateAnimation(state, animated, 0, -1, layerViews);
- }
-
@Override
protected void getFreeScrollPageRange(int[] range) {
getOverviewModePages(range);
@@ -2151,41 +2028,6 @@ public class Workspace extends SmoothPagedView
return mState == State.OVERVIEW;
}
- public boolean enterOverviewMode() {
- if (mTouchState != TOUCH_STATE_REST) {
- return false;
- }
- enableOverviewMode(true, -1, true);
- return true;
- }
-
- public void exitOverviewMode(boolean animated) {
- exitOverviewMode(-1, animated);
- }
-
- public void exitOverviewMode(int snapPage, boolean animated) {
- enableOverviewMode(false, snapPage, animated);
- }
-
- private void enableOverviewMode(boolean enable, int snapPage, boolean animated) {
- State finalState = Workspace.State.OVERVIEW;
- if (!enable) {
- finalState = Workspace.State.NORMAL;
- }
-
- Animator workspaceAnim = getChangeStateAnimation(finalState, animated, 0, snapPage);
- if (workspaceAnim != null) {
- onTransitionPrepare();
- workspaceAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator arg0) {
- onTransitionEnd();
- }
- });
- workspaceAnim.start();
- }
- }
-
int getOverviewModeTranslationY() {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
@@ -2208,10 +2050,22 @@ public class Workspace extends SmoothPagedView
}
}
- private void setState(State state) {
- mState = state;
+ /**
+ * Sets the current workspace {@link State}, returning an animation transitioning the workspace
+ * to that new state.
+ */
+ public Animator setStateWithAnimation(State toState, int toPage, boolean animated,
+ HashMap<View, Integer> layerViews) {
+ // Create the animation to the new state
+ Animator workspaceAnim = mStateTransitionAnimation.getAnimationToState(getState(),
+ toState, toPage, animated, layerViews);
+
+ // Update the current state
+ mState = toState;
updateInteractionForState();
updateAccessibilityFlags();
+
+ return workspaceAnim;
}
State getState() {
@@ -2225,321 +2079,15 @@ public class Workspace extends SmoothPagedView
setImportantForAccessibility(accessible);
}
- private static final int HIDE_WORKSPACE_DURATION = 100;
-
- Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage) {
- return getChangeStateAnimation(state, animated, delay, snapPage, null);
- }
-
- Animator getChangeStateAnimation(final State state, boolean animated, int delay, int snapPage,
- HashMap<View, Integer> layerViews) {
- if (mState == state) {
- return null;
- }
-
- // Initialize animation arrays for the first time if necessary
- initAnimationArrays();
-
- AnimatorSet anim = animated ? LauncherAnimUtils.createAnimatorSet() : null;
-
- // We only want a single instance of a workspace animation to be running at once, so
- // we cancel any incomplete transition.
- if (mStateAnimator != null) {
- mStateAnimator.cancel();
- }
- mStateAnimator = anim;
-
- final State oldState = mState;
- final boolean oldStateIsNormal = (oldState == State.NORMAL);
- final boolean oldStateIsSpringLoaded = (oldState == State.SPRING_LOADED);
- final boolean oldStateIsNormalHidden = (oldState == State.NORMAL_HIDDEN);
- final boolean oldStateIsOverviewHidden = (oldState == State.OVERVIEW_HIDDEN);
- final boolean oldStateIsOverview = (oldState == State.OVERVIEW);
- setState(state);
- final boolean stateIsNormal = (state == State.NORMAL);
- final boolean stateIsSpringLoaded = (state == State.SPRING_LOADED);
- final boolean stateIsNormalHidden = (state == State.NORMAL_HIDDEN);
- final boolean stateIsOverviewHidden = (state == State.OVERVIEW_HIDDEN);
- final boolean stateIsOverview = (state == State.OVERVIEW);
- float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;
- float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;
- float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;
- // We keep the search bar visible on the workspace and in AllApps now
- boolean showSearchBar = stateIsNormal ||
- (mLauncher.isAllAppsSearchOverridden() && stateIsNormalHidden);
- float finalSearchBarAlpha = showSearchBar ? 1f : 0f;
- float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?
- getOverviewModeTranslationY() : 0;
-
- boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden);
- boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden);
- boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal);
- boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview);
- boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal);
-
- mNewScale = 1.0f;
-
- if (oldStateIsOverview) {
- disableFreeScroll();
- } else if (stateIsOverview) {
- enableFreeScroll();
- }
-
- if (state != State.NORMAL) {
- if (stateIsSpringLoaded) {
- mNewScale = mSpringLoadedShrinkFactor;
- } else if (stateIsOverview || stateIsOverviewHidden) {
- mNewScale = mOverviewModeShrinkFactor;
- }
- }
-
- final int duration;
- if (workspaceToAllApps || overviewToAllApps) {
- duration = HIDE_WORKSPACE_DURATION; //getResources().getInteger(R.integer.config_workspaceUnshrinkTime);
- } else if (workspaceToOverview || overviewToWorkspace) {
- duration = getResources().getInteger(R.integer.config_overviewTransitionTime);
- } else {
- duration = getResources().getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
- }
-
- if (snapPage == -1) {
- snapPage = getPageNearestToCenterOfScreen();
- }
- snapToPage(snapPage, duration, mZoomInInterpolator);
-
- for (int i = 0; i < getChildCount(); i++) {
- final CellLayout cl = (CellLayout) getChildAt(i);
- boolean isCurrentPage = (i == snapPage);
- float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();
- float finalAlpha;
- if (stateIsNormalHidden || stateIsOverviewHidden) {
- finalAlpha = 0f;
- } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
- finalAlpha = (i == snapPage || i < numCustomPages()) ? 1f : 0f;
- } else {
- finalAlpha = 1f;
- }
-
- // If we are animating to/from the small state, then hide the side pages and fade the
- // current page in
- if (!mIsSwitchingState) {
- if (workspaceToAllApps || allAppsToWorkspace) {
- if (allAppsToWorkspace && isCurrentPage) {
- initialAlpha = 0f;
- } else if (!isCurrentPage) {
- initialAlpha = finalAlpha = 0f;
- }
- cl.setShortcutAndWidgetAlpha(initialAlpha);
- }
- }
-
- mOldAlphas[i] = initialAlpha;
- mNewAlphas[i] = finalAlpha;
- if (animated) {
- mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
- mNewBackgroundAlphas[i] = finalBackgroundAlpha;
- } else {
- cl.setBackgroundAlpha(finalBackgroundAlpha);
- cl.setShortcutAndWidgetAlpha(finalAlpha);
- }
- }
-
- final View searchBar = mLauncher.getOrCreateQsbBar();
- final View overviewPanel = mLauncher.getOverviewPanel();
- final View hotseat = mLauncher.getHotseat();
- final View pageIndicator = getPageIndicator();
- if (animated) {
- LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(this);
- scale.scaleX(mNewScale)
- .scaleY(mNewScale)
- .translationY(finalWorkspaceTranslationY)
- .setDuration(duration)
- .setInterpolator(mZoomInInterpolator);
- anim.play(scale);
- for (int index = 0; index < getChildCount(); index++) {
- final int i = index;
- final CellLayout cl = (CellLayout) getChildAt(i);
- float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
- if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
- cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
- cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
- } else {
- if (layerViews != null) {
- layerViews.put(cl, LauncherStateTransitionAnimation.BUILD_LAYER);
- }
- if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
- LauncherViewPropertyAnimator alphaAnim =
- new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
- alphaAnim.alpha(mNewAlphas[i])
- .setDuration(duration)
- .setInterpolator(mZoomInInterpolator);
- anim.play(alphaAnim);
- }
- if (mOldBackgroundAlphas[i] != 0 ||
- mNewBackgroundAlphas[i] != 0) {
- ValueAnimator bgAnim =
- LauncherAnimUtils.ofFloat(cl, 0f, 1f);
- bgAnim.setInterpolator(mZoomInInterpolator);
- bgAnim.setDuration(duration);
- bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
- public void onAnimationUpdate(float a, float b) {
- cl.setBackgroundAlpha(
- a * mOldBackgroundAlphas[i] +
- b * mNewBackgroundAlphas[i]);
- }
- });
- anim.play(bgAnim);
- }
- }
- }
- Animator pageIndicatorAlpha = null;
- if (pageIndicator != null) {
- pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator)
- .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();
- pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator));
- } else {
- // create a dummy animation so we don't need to do null checks later
- pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0);
- }
-
- LauncherViewPropertyAnimator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat)
- .alpha(finalHotseatAndPageIndicatorAlpha);
- hotseatAlpha.addListener(new AlphaUpdateListener(hotseat));
-
- LauncherViewPropertyAnimator overviewPanelAlpha =
- new LauncherViewPropertyAnimator(overviewPanel).alpha(finalOverviewPanelAlpha);
- overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel));
-
- // For animation optimations, we may need to provide the Launcher transition
- // with a set of views on which to force build layers in certain scenarios.
- hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- if (layerViews != null) {
- // If layerViews is not null, we add these views, and indicate that
- // the caller can manage layer state.
- layerViews.put(hotseat, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
- layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
- } else {
- // Otherwise let the animator handle layer management.
- hotseatAlpha.withLayer();
- overviewPanelAlpha.withLayer();
- }
-
- if (workspaceToOverview) {
- pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2));
- hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));
- overviewPanelAlpha.setInterpolator(null);
- } else if (overviewToWorkspace) {
- pageIndicatorAlpha.setInterpolator(null);
- hotseatAlpha.setInterpolator(null);
- overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));
- }
-
- overviewPanelAlpha.setDuration(duration);
- pageIndicatorAlpha.setDuration(duration);
- hotseatAlpha.setDuration(duration);
-
- if (searchBar != null) {
- LauncherViewPropertyAnimator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)
- .alpha(finalSearchBarAlpha);
- searchBarAlpha.addListener(new AlphaUpdateListener(searchBar));
- searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- if (layerViews != null) {
- // If layerViews is not null, we add these views, and indicate that
- // the caller can manage layer state.
- layerViews.put(searchBar, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
- } else {
- // Otherwise let the animator handle layer management.
- searchBarAlpha.withLayer();
- }
- searchBarAlpha.setDuration(duration);
- anim.play(searchBarAlpha);
- }
-
- anim.play(overviewPanelAlpha);
- anim.play(hotseatAlpha);
- anim.play(pageIndicatorAlpha);
- anim.setStartDelay(delay);
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mStateAnimator = null;
- }
- });
- } else {
- overviewPanel.setAlpha(finalOverviewPanelAlpha);
- AlphaUpdateListener.updateVisibility(overviewPanel);
- hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha);
- AlphaUpdateListener.updateVisibility(hotseat);
- if (pageIndicator != null) {
- pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha);
- AlphaUpdateListener.updateVisibility(pageIndicator);
- }
- if (searchBar != null) {
- searchBar.setAlpha(finalSearchBarAlpha);
- AlphaUpdateListener.updateVisibility(searchBar);
- }
- updateCustomContentVisibility();
- setScaleX(mNewScale);
- setScaleY(mNewScale);
- setTranslationY(finalWorkspaceTranslationY);
- }
-
- if (stateIsNormal) {
- animateBackgroundGradient(0f, animated);
- } else {
- animateBackgroundGradient(getResources().getInteger(
- R.integer.config_workspaceScrimAlpha) / 100f, animated);
- }
- return anim;
- }
-
- static class AlphaUpdateListener implements AnimatorUpdateListener, AnimatorListener {
- View view;
- public AlphaUpdateListener(View v) {
- view = v;
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator arg0) {
- updateVisibility(view);
- }
-
- public static void updateVisibility(View view) {
- // 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 = sAccessibilityEnabled ? GONE : INVISIBLE;
- if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
- view.setVisibility(invisibleState);
- } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
- && view.getVisibility() != VISIBLE) {
- view.setVisibility(VISIBLE);
- }
- }
-
- @Override
- public void onAnimationCancel(Animator arg0) {
- }
-
- @Override
- public void onAnimationEnd(Animator arg0) {
- updateVisibility(view);
- }
-
- @Override
- public void onAnimationRepeat(Animator arg0) {
- }
-
- @Override
- public void onAnimationStart(Animator arg0) {
- // We want the views to be visible for animation, so fade-in/out is visible
- view.setVisibility(VISIBLE);
- }
- }
-
@Override
public void onLauncherTransitionPrepare(Launcher l, boolean animated, boolean toWorkspace) {
- onTransitionPrepare();
+ mIsSwitchingState = true;
+
+ // Invalidate here to ensure that the pages are rendered during the state change transition.
+ invalidate();
+
+ updateChildrenLayersEnabled(false);
+ hideCustomContentIfNecessary();
}
@Override
@@ -2553,17 +2101,9 @@ public class Workspace extends SmoothPagedView
@Override
public void onLauncherTransitionEnd(Launcher l, boolean animated, boolean toWorkspace) {
- onTransitionEnd();
- }
-
- private void onTransitionPrepare() {
- mIsSwitchingState = true;
-
- // Invalidate here to ensure that the pages are rendered during the state change transition.
- invalidate();
-
+ mIsSwitchingState = false;
updateChildrenLayersEnabled(false);
- hideCustomContentIfNecessary();
+ showCustomContentIfNecessary();
}
void updateCustomContentVisibility() {
@@ -2589,12 +2129,6 @@ public class Workspace extends SmoothPagedView
}
}
- @Thunk void onTransitionEnd() {
- mIsSwitchingState = false;
- updateChildrenLayersEnabled(false);
- showCustomContentIfNecessary();
- }
-
@Override
public View getContent() {
return this;
@@ -3106,7 +2640,7 @@ public class Workspace extends SmoothPagedView
}
}
- int snapScreen = -1;
+ int snapScreen = WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE;
boolean resizeOnDrop = false;
if (d.dragSource != this) {
final int[] touchXY = new int[] { (int) mDragViewVisualCenter[0],
@@ -3267,7 +2801,9 @@ public class Workspace extends SmoothPagedView
animateWidgetDrop(info, parent, d.dragView,
onCompleteRunnable, animationType, cell, false);
} else {
- int duration = snapScreen < 0 ? -1 : ADJACENT_SCREEN_DROP_DURATION;
+ int duration = snapScreen < 0 ?
+ WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE :
+ ADJACENT_SCREEN_DROP_DURATION;
mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, cell, duration,
onCompleteRunnable, this);
}
@@ -4165,8 +3701,8 @@ public class Workspace extends SmoothPagedView
public void setFinalTransitionTransform(CellLayout layout) {
if (isSwitchingState()) {
mCurrentScale = getScaleX();
- setScaleX(mNewScale);
- setScaleY(mNewScale);
+ setScaleX(mStateTransitionAnimation.getFinalScale());
+ setScaleY(mStateTransitionAnimation.getFinalScale());
}
}
public void resetTransitionTransform(CellLayout layout) {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
new file mode 100644
index 000000000..a0cedeb63
--- /dev/null
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2015 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.AnimatorSet;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.DecelerateInterpolator;
+import com.android.launcher3.util.Thunk;
+
+import java.util.HashMap;
+
+/**
+ * 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;
+
+ 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 onAnimationEnd(Animator arg0) {
+ 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);
+ }
+}
+
+/**
+ * This interpolator emulates the rate at which the perceived scale of an object changes
+ * as its distance from a camera increases. When this interpolator is applied to a scale
+ * animation on a view, it evokes the sense that the object is shrinking due to moving away
+ * from the camera.
+ */
+class ZInterpolator implements TimeInterpolator {
+ private float focalLength;
+
+ public ZInterpolator(float foc) {
+ focalLength = foc;
+ }
+
+ public float getInterpolation(float input) {
+ return (1.0f - focalLength / (focalLength + input)) /
+ (1.0f - focalLength / (focalLength + 1.0f));
+ }
+}
+
+/**
+ * The exact reverse of ZInterpolator.
+ */
+class InverseZInterpolator implements TimeInterpolator {
+ private ZInterpolator zInterpolator;
+ public InverseZInterpolator(float foc) {
+ zInterpolator = new ZInterpolator(foc);
+ }
+ public float getInterpolation(float input) {
+ return 1 - zInterpolator.getInterpolation(1 - input);
+ }
+}
+
+/**
+ * InverseZInterpolator compounded with an ease-out.
+ */
+class ZoomInInterpolator implements TimeInterpolator {
+ private final InverseZInterpolator inverseZInterpolator = new InverseZInterpolator(0.35f);
+ private final DecelerateInterpolator decelerate = new DecelerateInterpolator(3.0f);
+
+ public float getInterpolation(float input) {
+ return decelerate.getInterpolation(inverseZInterpolator.getInterpolation(input));
+ }
+}
+
+/**
+ * Manages the animations between each of the workspace states.
+ */
+public class WorkspaceStateTransitionAnimation {
+
+ public static final String TAG = "WorkspaceStateTransitionAnimation";
+
+ public static final int SCROLL_TO_CURRENT_PAGE = -1;
+ @Thunk static final int BACKGROUND_FADE_OUT_DURATION = 350;
+
+ final @Thunk Launcher mLauncher;
+ final @Thunk Workspace mWorkspace;
+
+ @Thunk AnimatorSet mStateAnimator;
+ @Thunk float[] mOldBackgroundAlphas;
+ @Thunk float[] mOldAlphas;
+ @Thunk float[] mNewBackgroundAlphas;
+ @Thunk float[] mNewAlphas;
+ @Thunk int mLastChildCount = -1;
+
+ @Thunk float mCurrentScale;
+ @Thunk float mNewScale;
+
+ @Thunk final ZoomInInterpolator mZoomInInterpolator = new ZoomInInterpolator();
+
+ // These properties refer to the background protection gradient used for AllApps and Customize
+ @Thunk ValueAnimator mBackgroundFadeInAnimation;
+ @Thunk ValueAnimator mBackgroundFadeOutAnimation;
+
+ @Thunk float mSpringLoadedShrinkFactor;
+ @Thunk float mOverviewModeShrinkFactor;
+ @Thunk float mWorkspaceScrimAlpha;
+ @Thunk int mAllAppsTransitionTime;
+ @Thunk int mOverviewTransitionTime;
+ @Thunk int mOverlayTransitionTime;
+ @Thunk boolean mWorkspaceFadeInAdjacentScreens;
+
+ public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
+ mLauncher = launcher;
+ mWorkspace = workspace;
+
+ LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+ Resources res = launcher.getResources();
+ mAllAppsTransitionTime = res.getInteger(R.integer.config_workspaceUnshrinkTime);
+ mOverviewTransitionTime = res.getInteger(R.integer.config_overviewTransitionTime);
+ mOverlayTransitionTime = res.getInteger(R.integer.config_appsCustomizeWorkspaceShrinkTime);
+ mSpringLoadedShrinkFactor =
+ res.getInteger(R.integer.config_workspaceSpringLoadShrinkPercentage) / 100f;
+ mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha) / 100f;
+ mOverviewModeShrinkFactor = grid.getOverviewModeScale();
+ mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
+ }
+
+ public AnimatorSet getAnimationToState(Workspace.State fromState, Workspace.State toState,
+ int toPage, boolean animated,
+ HashMap<View, Integer> layerViews) {
+ getAnimation(fromState, toState, toPage, animated, layerViews);
+ return mStateAnimator;
+ }
+
+ public float getFinalScale() {
+ return mNewScale;
+ }
+
+ /**
+ * Starts a transition animation for the workspace.
+ */
+ private void getAnimation(final Workspace.State fromState, final Workspace.State toState,
+ int toPage, final boolean animated,
+ final HashMap<View, Integer> layerViews) {
+ AccessibilityManager am = (AccessibilityManager)
+ mLauncher.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ boolean accessibilityEnabled = am.isEnabled();
+
+ // Reinitialize animation arrays for the current workspace state
+ reinitializeAnimationArrays();
+
+ // Cancel existing workspace animations and create a new animator set if requested
+ cancelAnimation();
+ if (animated) {
+ mStateAnimator = LauncherAnimUtils.createAnimatorSet();
+ }
+
+ // Update the workspace state
+ final boolean oldStateIsNormal = (fromState == Workspace.State.NORMAL);
+ final boolean oldStateIsSpringLoaded = (fromState == Workspace.State.SPRING_LOADED);
+ final boolean oldStateIsNormalHidden = (fromState == Workspace.State.NORMAL_HIDDEN);
+ final boolean oldStateIsOverviewHidden = (fromState == Workspace.State.OVERVIEW_HIDDEN);
+ final boolean oldStateIsOverview = (fromState == Workspace.State.OVERVIEW);
+
+ final boolean stateIsNormal = (toState == Workspace.State.NORMAL);
+ final boolean stateIsSpringLoaded = (toState == Workspace.State.SPRING_LOADED);
+ final boolean stateIsNormalHidden = (toState == Workspace.State.NORMAL_HIDDEN);
+ final boolean stateIsOverviewHidden = (toState == Workspace.State.OVERVIEW_HIDDEN);
+ final boolean stateIsOverview = (toState == Workspace.State.OVERVIEW);
+
+ final boolean workspaceToAllApps = (oldStateIsNormal && stateIsNormalHidden);
+ final boolean overviewToAllApps = (oldStateIsOverview && stateIsOverviewHidden);
+ final boolean allAppsToWorkspace = (stateIsNormalHidden && stateIsNormal);
+ final boolean workspaceToOverview = (oldStateIsNormal && stateIsOverview);
+ final boolean overviewToWorkspace = (oldStateIsOverview && stateIsNormal);
+
+ float finalBackgroundAlpha = (stateIsSpringLoaded || stateIsOverview) ? 1.0f : 0f;
+ float finalHotseatAndPageIndicatorAlpha = (stateIsNormal || stateIsSpringLoaded) ? 1f : 0f;
+ float finalOverviewPanelAlpha = stateIsOverview ? 1f : 0f;
+ // We keep the search bar visible on the workspace and in AllApps now
+ boolean showSearchBar = stateIsNormal ||
+ (mLauncher.isAllAppsSearchOverridden() && stateIsNormalHidden);
+ float finalSearchBarAlpha = showSearchBar ? 1f : 0f;
+ float finalWorkspaceTranslationY = stateIsOverview || stateIsOverviewHidden ?
+ mWorkspace.getOverviewModeTranslationY() : 0;
+
+ final int childCount = mWorkspace.getChildCount();
+ final int customPageCount = mWorkspace.numCustomPages();
+
+ mNewScale = 1.0f;
+
+ if (oldStateIsOverview) {
+ mWorkspace.disableFreeScroll();
+ } else if (stateIsOverview) {
+ mWorkspace.enableFreeScroll();
+ }
+
+ if (!stateIsNormal) {
+ if (stateIsSpringLoaded) {
+ mNewScale = mSpringLoadedShrinkFactor;
+ } else if (stateIsOverview || stateIsOverviewHidden) {
+ mNewScale = mOverviewModeShrinkFactor;
+ }
+ }
+
+ final int duration;
+ if (workspaceToAllApps || overviewToAllApps) {
+ duration = mAllAppsTransitionTime;
+ } else if (workspaceToOverview || overviewToWorkspace) {
+ duration = mOverviewTransitionTime;
+ } else {
+ duration = mOverlayTransitionTime;
+ }
+
+ if (toPage == SCROLL_TO_CURRENT_PAGE) {
+ toPage = mWorkspace.getPageNearestToCenterOfScreen();
+ }
+ mWorkspace.snapToPage(toPage, duration, mZoomInInterpolator);
+
+ for (int i = 0; i < childCount; i++) {
+ final CellLayout cl = (CellLayout) mWorkspace.getChildAt(i);
+ boolean isCurrentPage = (i == toPage);
+ float initialAlpha = cl.getShortcutsAndWidgets().getAlpha();
+ float finalAlpha;
+ if (stateIsNormalHidden || stateIsOverviewHidden) {
+ finalAlpha = 0f;
+ } else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
+ finalAlpha = (i == toPage || i < customPageCount) ? 1f : 0f;
+ } else {
+ finalAlpha = 1f;
+ }
+
+ // If we are animating to/from the small state, then hide the side pages and fade the
+ // current page in
+ if (!mWorkspace.isSwitchingState()) {
+ if (workspaceToAllApps || allAppsToWorkspace) {
+ if (allAppsToWorkspace && isCurrentPage) {
+ initialAlpha = 0f;
+ } else if (!isCurrentPage) {
+ initialAlpha = finalAlpha = 0f;
+ }
+ cl.setShortcutAndWidgetAlpha(initialAlpha);
+ }
+ }
+
+ mOldAlphas[i] = initialAlpha;
+ mNewAlphas[i] = finalAlpha;
+ if (animated) {
+ mOldBackgroundAlphas[i] = cl.getBackgroundAlpha();
+ mNewBackgroundAlphas[i] = finalBackgroundAlpha;
+ } else {
+ cl.setBackgroundAlpha(finalBackgroundAlpha);
+ cl.setShortcutAndWidgetAlpha(finalAlpha);
+ }
+ }
+
+ final View searchBar = mLauncher.getOrCreateQsbBar();
+ final View overviewPanel = mLauncher.getOverviewPanel();
+ final View hotseat = mLauncher.getHotseat();
+ final View pageIndicator = mWorkspace.getPageIndicator();
+ if (animated) {
+ LauncherViewPropertyAnimator scale = new LauncherViewPropertyAnimator(mWorkspace);
+ scale.scaleX(mNewScale)
+ .scaleY(mNewScale)
+ .translationY(finalWorkspaceTranslationY)
+ .setDuration(duration)
+ .setInterpolator(mZoomInInterpolator);
+ mStateAnimator.play(scale);
+ for (int index = 0; index < childCount; index++) {
+ final int i = index;
+ final CellLayout cl = (CellLayout) mWorkspace.getChildAt(i);
+ float currentAlpha = cl.getShortcutsAndWidgets().getAlpha();
+ if (mOldAlphas[i] == 0 && mNewAlphas[i] == 0) {
+ cl.setBackgroundAlpha(mNewBackgroundAlphas[i]);
+ cl.setShortcutAndWidgetAlpha(mNewAlphas[i]);
+ } else {
+ if (layerViews != null) {
+ layerViews.put(cl, LauncherStateTransitionAnimation.BUILD_LAYER);
+ }
+ if (mOldAlphas[i] != mNewAlphas[i] || currentAlpha != mNewAlphas[i]) {
+ LauncherViewPropertyAnimator alphaAnim =
+ new LauncherViewPropertyAnimator(cl.getShortcutsAndWidgets());
+ alphaAnim.alpha(mNewAlphas[i])
+ .setDuration(duration)
+ .setInterpolator(mZoomInInterpolator);
+ mStateAnimator.play(alphaAnim);
+ }
+ if (mOldBackgroundAlphas[i] != 0 ||
+ mNewBackgroundAlphas[i] != 0) {
+ ValueAnimator bgAnim =
+ LauncherAnimUtils.ofFloat(cl, 0f, 1f);
+ bgAnim.setInterpolator(mZoomInInterpolator);
+ bgAnim.setDuration(duration);
+ bgAnim.addUpdateListener(new LauncherAnimatorUpdateListener() {
+ public void onAnimationUpdate(float a, float b) {
+ cl.setBackgroundAlpha(
+ a * mOldBackgroundAlphas[i] +
+ b * mNewBackgroundAlphas[i]);
+ }
+ });
+ mStateAnimator.play(bgAnim);
+ }
+ }
+ }
+ Animator pageIndicatorAlpha = null;
+ if (pageIndicator != null) {
+ pageIndicatorAlpha = new LauncherViewPropertyAnimator(pageIndicator)
+ .alpha(finalHotseatAndPageIndicatorAlpha).withLayer();
+ pageIndicatorAlpha.addListener(new AlphaUpdateListener(pageIndicator,
+ accessibilityEnabled));
+ } else {
+ // create a dummy animation so we don't need to do null checks later
+ pageIndicatorAlpha = ValueAnimator.ofFloat(0, 0);
+ }
+
+ LauncherViewPropertyAnimator hotseatAlpha = new LauncherViewPropertyAnimator(hotseat)
+ .alpha(finalHotseatAndPageIndicatorAlpha);
+ hotseatAlpha.addListener(new AlphaUpdateListener(hotseat, accessibilityEnabled));
+
+ LauncherViewPropertyAnimator overviewPanelAlpha =
+ new LauncherViewPropertyAnimator(overviewPanel).alpha(finalOverviewPanelAlpha);
+ overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel,
+ accessibilityEnabled));
+
+ // For animation optimations, we may need to provide the Launcher transition
+ // with a set of views on which to force build layers in certain scenarios.
+ hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ overviewPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ if (layerViews != null) {
+ // If layerViews is not null, we add these views, and indicate that
+ // the caller can manage layer state.
+ layerViews.put(hotseat, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+ layerViews.put(overviewPanel, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+ } else {
+ // Otherwise let the animator handle layer management.
+ hotseatAlpha.withLayer();
+ overviewPanelAlpha.withLayer();
+ }
+
+ if (workspaceToOverview) {
+ pageIndicatorAlpha.setInterpolator(new DecelerateInterpolator(2));
+ hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));
+ overviewPanelAlpha.setInterpolator(null);
+ } else if (overviewToWorkspace) {
+ pageIndicatorAlpha.setInterpolator(null);
+ hotseatAlpha.setInterpolator(null);
+ overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));
+ }
+
+ overviewPanelAlpha.setDuration(duration);
+ pageIndicatorAlpha.setDuration(duration);
+ hotseatAlpha.setDuration(duration);
+
+ // TODO: This should really be coordinated with the SearchDropTargetBar, otherwise the
+ // bar has no idea that it is hidden, and this has no idea what state the bar is
+ // actually in.
+ if (searchBar != null) {
+ LauncherViewPropertyAnimator searchBarAlpha = new LauncherViewPropertyAnimator(searchBar)
+ .alpha(finalSearchBarAlpha);
+ searchBarAlpha.addListener(new AlphaUpdateListener(searchBar, accessibilityEnabled));
+ searchBar.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ if (layerViews != null) {
+ // If layerViews is not null, we add these views, and indicate that
+ // the caller can manage layer state.
+ layerViews.put(searchBar, LauncherStateTransitionAnimation.BUILD_AND_SET_LAYER);
+ } else {
+ // Otherwise let the animator handle layer management.
+ searchBarAlpha.withLayer();
+ }
+ searchBarAlpha.setDuration(duration);
+ mStateAnimator.play(searchBarAlpha);
+ }
+
+ mStateAnimator.play(overviewPanelAlpha);
+ mStateAnimator.play(hotseatAlpha);
+ mStateAnimator.play(pageIndicatorAlpha);
+ mStateAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mStateAnimator = null;
+ }
+ });
+ } else {
+ overviewPanel.setAlpha(finalOverviewPanelAlpha);
+ AlphaUpdateListener.updateVisibility(overviewPanel, accessibilityEnabled);
+ hotseat.setAlpha(finalHotseatAndPageIndicatorAlpha);
+ AlphaUpdateListener.updateVisibility(hotseat, accessibilityEnabled);
+ if (pageIndicator != null) {
+ pageIndicator.setAlpha(finalHotseatAndPageIndicatorAlpha);
+ AlphaUpdateListener.updateVisibility(pageIndicator, accessibilityEnabled);
+ }
+ if (searchBar != null) {
+ searchBar.setAlpha(finalSearchBarAlpha);
+ AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled);
+ }
+ mWorkspace.updateCustomContentVisibility();
+ mWorkspace.setScaleX(mNewScale);
+ mWorkspace.setScaleY(mNewScale);
+ mWorkspace.setTranslationY(finalWorkspaceTranslationY);
+ }
+
+ if (stateIsNormal) {
+ animateBackgroundGradient(0f, animated);
+ } else {
+ animateBackgroundGradient(mWorkspaceScrimAlpha, animated);
+ }
+ }
+
+ /**
+ * Reinitializes the arrays that we need for the animations on each page.
+ */
+ private void reinitializeAnimationArrays() {
+ final int childCount = mWorkspace.getChildCount();
+ if (mLastChildCount == childCount) return;
+
+ mOldBackgroundAlphas = new float[childCount];
+ mOldAlphas = new float[childCount];
+ mNewBackgroundAlphas = new float[childCount];
+ mNewAlphas = new float[childCount];
+ }
+
+ /**
+ * Animates the background scrim.
+ * TODO(winsonc): Is there a better place for this?
+ *
+ * @param finalAlpha the final alpha for the background scrim
+ * @param animated whether or not to set the background alpha immediately
+ */
+ private void animateBackgroundGradient(float finalAlpha, boolean animated) {
+ // Cancel any running background animations
+ cancelAnimator(mBackgroundFadeInAnimation);
+ cancelAnimator(mBackgroundFadeOutAnimation);
+
+ final DragLayer dragLayer = mLauncher.getDragLayer();
+ final float startAlpha = dragLayer.getBackgroundAlpha();
+ if (finalAlpha != startAlpha) {
+ if (animated) {
+ mBackgroundFadeOutAnimation =
+ LauncherAnimUtils.ofFloat(mWorkspace, startAlpha, finalAlpha);
+ mBackgroundFadeOutAnimation.addUpdateListener(
+ new ValueAnimator.AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ dragLayer.setBackgroundAlpha(
+ ((Float)animation.getAnimatedValue()).floatValue());
+ }
+ });
+ mBackgroundFadeOutAnimation.setInterpolator(new DecelerateInterpolator(1.5f));
+ mBackgroundFadeOutAnimation.setDuration(BACKGROUND_FADE_OUT_DURATION);
+ mBackgroundFadeOutAnimation.start();
+ } else {
+ dragLayer.setBackgroundAlpha(finalAlpha);
+ }
+ }
+ }
+
+ /**
+ * Cancels the current animation.
+ */
+ private void cancelAnimation() {
+ cancelAnimator(mStateAnimator);
+ mStateAnimator = null;
+ }
+
+ /**
+ * Cancels the specified animation.
+ */
+ private void cancelAnimator(Animator animator) {
+ if (animator != null) {
+ animator.setDuration(0);
+ animator.cancel();
+ }
+ }
+} \ No newline at end of file