From 006ee269ba2e9946a83b42f96d4a0296254cba4a Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Mon, 3 Aug 2015 14:40:11 -0700 Subject: Refactoring search bar animations. - This refactoring ensures that LauncherStateTransition does not do its own animation on the QSB, and that all animations to the SearchDropTargetBar go through its own animators. Bug: 22515084 Change-Id: Ia7d13c44d861eac7517076b52a9651a90911ed0a --- src/com/android/launcher3/DeviceProfile.java | 3 +- src/com/android/launcher3/DragLayer.java | 4 +- src/com/android/launcher3/Folder.java | 2 +- src/com/android/launcher3/Launcher.java | 48 ++--- .../LauncherStateTransitionAnimation.java | 214 ++++++++++++--------- .../launcher3/LauncherViewPropertyAnimator.java | 4 +- src/com/android/launcher3/SearchDropTargetBar.java | 209 ++++++++++---------- src/com/android/launcher3/Workspace.java | 25 ++- .../WorkspaceStateTransitionAnimation.java | 77 +------- 9 files changed, 283 insertions(+), 303 deletions(-) diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 6e90fc291..774594fe2 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -25,7 +25,6 @@ import android.graphics.Paint.FontMetrics; import android.graphics.Point; import android.graphics.Rect; import android.util.DisplayMetrics; -import android.util.Size; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -385,7 +384,7 @@ public class DeviceProfile { final boolean isLayoutRtl = Utilities.isRtl(launcher.getResources()); // Layout the search bar space - View searchBar = launcher.getSearchBar(); + View searchBar = launcher.getSearchDropTargetBar(); lp = (FrameLayout.LayoutParams) searchBar.getLayoutParams(); if (hasVerticalBarLayout) { // Vertical search bar space -- The search bar is fixed in the layout to be on the left diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java index aaa14e6a6..1c18747c1 100644 --- a/src/com/android/launcher3/DragLayer.java +++ b/src/com/android/launcher3/DragLayer.java @@ -159,7 +159,7 @@ public class DragLayer extends InsettableFrameLayout { } private boolean isEventOverDropTargetBar(MotionEvent ev) { - getDescendantRectRelativeToSelf(mLauncher.getSearchBar(), mHitRect); + getDescendantRectRelativeToSelf(mLauncher.getSearchDropTargetBar(), mHitRect); if (mHitRect.contains((int) ev.getX(), (int) ev.getY())) { return true; } @@ -321,7 +321,7 @@ public class DragLayer extends InsettableFrameLayout { childrenForAccessibility.add(currentFolder); if (isInAccessibleDrag()) { - childrenForAccessibility.add(mLauncher.getSearchBar()); + childrenForAccessibility.add(mLauncher.getSearchDropTargetBar()); } } else { super.addChildrenForAccessibility(childrenForAccessibility); diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java index 2e19f6eba..535d1a443 100644 --- a/src/com/android/launcher3/Folder.java +++ b/src/com/android/launcher3/Folder.java @@ -275,7 +275,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList @Override public void enableAccessibleDrag(boolean enable) { - mLauncher.getSearchBar().enableAccessibleDrag(enable); + mLauncher.getSearchDropTargetBar().enableAccessibleDrag(enable); for (int i = 0; i < mContent.getChildCount(); i++) { mContent.getPageAt(i).enableAccessibleDrag(enable, CellLayout.FOLDER_ACCESSIBILITY_DRAG); } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 15e43b2b9..aee044097 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -132,8 +132,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ public class Launcher extends Activity implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, - View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener, - LauncherStateTransitionAnimation.Callbacks { + View.OnTouchListener, PageSwitchListener, LauncherProviderChangeListener { static final String TAG = "Launcher"; static final boolean LOGD = false; @@ -452,7 +451,7 @@ public class Launcher extends Activity mDragController = new DragController(this); mInflater = getLayoutInflater(); - mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, this); + mStateTransitionAnimation = new LauncherStateTransitionAnimation(this); mStats = new Stats(this); @@ -1844,7 +1843,7 @@ public class Launcher extends Activity return mOverviewPanel; } - public SearchDropTargetBar getSearchBar() { + public SearchDropTargetBar getSearchDropTargetBar() { return mSearchDropTargetBar; } @@ -3265,14 +3264,6 @@ public class Launcher extends Activity } } - @Override - public void onStateTransitionHideSearchBar() { - // Hide the search bar - if (mSearchDropTargetBar != null) { - mSearchDropTargetBar.hideSearchBar(false /* animated */); - } - } - public void showWorkspace(boolean animated) { showWorkspace(WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, null); } @@ -3290,16 +3281,9 @@ public class Launcher extends Activity 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, - snapToPage, animated, onCompleteRunnable); - - // Show the search bar (only animate if we were showing the drop target bar in spring - // loaded mode) - if (mSearchDropTargetBar != null) { - mSearchDropTargetBar.showSearchBar(animated && wasInSpringLoadedMode); - } + mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(), + Workspace.State.NORMAL, snapToPage, animated, onCompleteRunnable); // Set focus to the AppsCustomize button if (mAllAppsButton != null) { @@ -3323,7 +3307,8 @@ public class Launcher extends Activity void showOverviewMode(boolean animated) { mWorkspace.setVisibility(View.VISIBLE); - mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.OVERVIEW, + mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(), + Workspace.State.OVERVIEW, WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, animated, null /* onCompleteRunnable */); mState = State.WORKSPACE; @@ -3378,9 +3363,10 @@ public class Launcher extends Activity } if (toState == State.APPS) { - mStateTransitionAnimation.startAnimationToAllApps(animated, focusSearchBar); + mStateTransitionAnimation.startAnimationToAllApps(mWorkspace.getState(), animated, + focusSearchBar); } else { - mStateTransitionAnimation.startAnimationToWidgets(animated); + mStateTransitionAnimation.startAnimationToWidgets(mWorkspace.getState(), animated); } // Change the state *after* we've called all the transition code @@ -3402,10 +3388,9 @@ public class Launcher extends Activity * new state. */ public Animator startWorkspaceStateChangeAnimation(Workspace.State toState, int toPage, - boolean animated, boolean hasOverlaySearchBar, HashMap layerViews) { + boolean animated, HashMap layerViews) { Workspace.State fromState = mWorkspace.getState(); - Animator anim = mWorkspace.setStateWithAnimation(toState, toPage, animated, - hasOverlaySearchBar, layerViews); + Animator anim = mWorkspace.setStateWithAnimation(toState, toPage, animated, layerViews); updateInteraction(fromState, toState); return anim; } @@ -3417,7 +3402,8 @@ public class Launcher extends Activity return; } - mStateTransitionAnimation.startAnimationToWorkspace(mState, Workspace.State.SPRING_LOADED, + mStateTransitionAnimation.startAnimationToWorkspace(mState, mWorkspace.getState(), + Workspace.State.SPRING_LOADED, WorkspaceStateTransitionAnimation.SCROLL_TO_CURRENT_PAGE, true /* animated */, null /* onCompleteRunnable */); mState = isAppsViewVisible() ? State.APPS_SPRING_LOADED : State.WIDGETS_SPRING_LOADED; @@ -4517,14 +4503,16 @@ public class Launcher extends Activity if (mWorkspace != null) mWorkspace.setAlpha(1f); if (mHotseat != null) mHotseat.setAlpha(1f); if (mPageIndicators != null) mPageIndicators.setAlpha(1f); - if (mSearchDropTargetBar != null) mSearchDropTargetBar.showSearchBar(false); + if (mSearchDropTargetBar != null) mSearchDropTargetBar.animateToState( + SearchDropTargetBar.State.SEARCH_BAR, 0); } void hideWorkspaceSearchAndHotseat() { if (mWorkspace != null) mWorkspace.setAlpha(0f); if (mHotseat != null) mHotseat.setAlpha(0f); if (mPageIndicators != null) mPageIndicators.setAlpha(0f); - if (mSearchDropTargetBar != null) mSearchDropTargetBar.hideSearchBar(false); + if (mSearchDropTargetBar != null) mSearchDropTargetBar.animateToState( + SearchDropTargetBar.State.INVISIBLE, 0); } // TODO: These method should be a part of LauncherSearchCallback diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java index d69b7432d..acace8299 100644 --- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java +++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java @@ -79,13 +79,6 @@ import java.util.HashMap; */ public class LauncherStateTransitionAnimation { - /** - * Callbacks made during the state transition - */ - interface Callbacks { - public void onStateTransitionHideSearchBar(); - } - /** * Private callbacks made during transition setup. */ @@ -111,12 +104,10 @@ public class LauncherStateTransitionAnimation { public static final int SINGLE_FRAME_DELAY = 16; @Thunk Launcher mLauncher; - @Thunk Callbacks mCb; - @Thunk AnimatorSet mStateAnimation; + @Thunk AnimatorSet mCurrentAnimation; - public LauncherStateTransitionAnimation(Launcher l, Callbacks cb) { + public LauncherStateTransitionAnimation(Launcher l) { mLauncher = l; - mCb = cb; } /** @@ -125,8 +116,8 @@ public class LauncherStateTransitionAnimation { * @param startSearchAfterTransition Immediately starts app search after the transition to * All Apps is completed. */ - public void startAnimationToAllApps(final boolean animated, - final boolean startSearchAfterTransition) { + public void startAnimationToAllApps(final Workspace.State fromWorkspaceState, + final boolean animated, final boolean startSearchAfterTransition) { final AllAppsContainerView toView = mLauncher.getAppsView(); final View buttonView = mLauncher.getAllAppsButton(); PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() { @@ -159,15 +150,16 @@ public class LauncherStateTransitionAnimation { } }; // Only animate the search bar if animating from spring loaded mode back to all apps - startAnimationToOverlay(Workspace.State.NORMAL_HIDDEN, buttonView, toView, - toView.getContentView(), toView.getRevealView(), toView.getSearchBarView(), - animated, true /* hideSearchBar */, cb); + mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState, + Workspace.State.NORMAL_HIDDEN, buttonView, toView, toView.getContentView(), + toView.getRevealView(), toView.getSearchBarView(), animated, cb); } /** * Starts an animation to the widgets view. */ - public void startAnimationToWidgets(final boolean animated) { + public void startAnimationToWidgets(final Workspace.State fromWorkspaceState, + final boolean animated) { final WidgetsContainerView toView = mLauncher.getWidgetsView(); final View buttonView = mLauncher.getWidgetsButton(); @@ -177,17 +169,17 @@ public class LauncherStateTransitionAnimation { return 0.3f; } }; - startAnimationToOverlay(Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, - toView.getContentView(), toView.getRevealView(), null, animated, - true /* hideSearchBar */, cb); + mCurrentAnimation = startAnimationToOverlay(fromWorkspaceState, + Workspace.State.OVERVIEW_HIDDEN, buttonView, toView, toView.getContentView(), + toView.getRevealView(), null, animated, cb); } /** * Starts and animation to the workspace from the current overlay view. */ public void startAnimationToWorkspace(final Launcher.State fromState, - final Workspace.State toWorkspaceState, final int toWorkspacePage, - final boolean animated, final Runnable onCompleteRunnable) { + final Workspace.State fromWorkspaceState, 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) { @@ -195,10 +187,10 @@ public class LauncherStateTransitionAnimation { } if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED) { - startAnimationToWorkspaceFromAllApps(toWorkspaceState, toWorkspacePage, + startAnimationToWorkspaceFromAllApps(fromWorkspaceState, toWorkspaceState, toWorkspacePage, animated, onCompleteRunnable); } else { - startAnimationToWorkspaceFromWidgets(toWorkspaceState, toWorkspacePage, + startAnimationToWorkspaceFromWidgets(fromWorkspaceState, toWorkspaceState, toWorkspacePage, animated, onCompleteRunnable); } } @@ -207,10 +199,11 @@ public class LauncherStateTransitionAnimation { * Creates and starts a new animation to a particular overlay view. */ @SuppressLint("NewApi") - private void startAnimationToOverlay(final Workspace.State toWorkspaceState, - final View buttonView, final View toView, final View contentView, final View revealView, - final View overlaySearchBarView, final boolean animated, final boolean hideSearchBar, - final PrivateTransitionCallbacks pCb) { + private AnimatorSet startAnimationToOverlay(final Workspace.State fromWorkspaceState, + final Workspace.State toWorkspaceState, final View buttonView, final View toView, + final View contentView, final View revealView, final View overlaySearchBarView, + final boolean animated, final PrivateTransitionCallbacks pCb) { + final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet(); final Resources res = mLauncher.getResources(); final boolean material = Utilities.isLmpOrAbove(); final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime); @@ -230,11 +223,13 @@ public class LauncherStateTransitionAnimation { // Create the workspace animation. // NOTE: this call apparently also sets the state for the workspace if !animated Animator workspaceAnim = mLauncher.startWorkspaceStateChangeAnimation(toWorkspaceState, -1, - animated, overlaySearchBarView != null /* hasOverlaySearchBar */, layerViews); + animated, layerViews); - if (animated && initialized) { - mStateAnimation = LauncherAnimUtils.createAnimatorSet(); + // Animate the search bar + startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState, + animated ? revealDuration : 0, overlaySearchBarView); + if (animated && initialized) { // Setup the reveal view animation int width = revealView.getMeasuredWidth(); int height = revealView.getMeasuredHeight(); @@ -274,7 +269,7 @@ public class LauncherStateTransitionAnimation { // Play the animation layerViews.put(revealView, BUILD_AND_SET_LAYER); - mStateAnimation.play(panelAlphaAndDrift); + animation.play(panelAlphaAndDrift); if (overlaySearchBarView != null) { overlaySearchBarView.setAlpha(0f); @@ -282,7 +277,7 @@ public class LauncherStateTransitionAnimation { searchBarAlpha.setDuration(100); searchBarAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER); - mStateAnimation.play(searchBarAlpha); + animation.play(searchBarAlpha); } // Setup the animation for the content view @@ -297,13 +292,13 @@ public class LauncherStateTransitionAnimation { pageDrift.setDuration(revealDuration); pageDrift.setInterpolator(new LogDecelerateInterpolator(100, 0)); pageDrift.setStartDelay(itemsAlphaStagger); - mStateAnimation.play(pageDrift); + animation.play(pageDrift); ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 0f, 1f); itemsAlpha.setDuration(revealDuration); itemsAlpha.setInterpolator(new AccelerateInterpolator(1.5f)); itemsAlpha.setStartDelay(itemsAlphaStagger); - mStateAnimation.play(itemsAlpha); + animation.play(itemsAlpha); if (material) { float startRadius = pCb.getMaterialRevealViewStartFinalRadius(); @@ -316,10 +311,10 @@ public class LauncherStateTransitionAnimation { if (listener != null) { reveal.addListener(listener); } - mStateAnimation.play(reveal); + animation.play(reveal); } - mStateAnimation.addListener(new AnimatorListenerAdapter() { + animation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { dispatchOnLauncherTransitionEnd(fromView, animated, false); @@ -335,12 +330,8 @@ public class LauncherStateTransitionAnimation { } } - if (hideSearchBar) { - mCb.onStateTransitionHideSearchBar(); - } - // This can hold unnecessary references to views. - mStateAnimation = null; + cleanupAnimation(); pCb.onTransitionComplete(); } @@ -348,7 +339,7 @@ public class LauncherStateTransitionAnimation { // Play the workspace animation if (workspaceAnim != null) { - mStateAnimation.play(workspaceAnim); + animation.play(workspaceAnim); } // Dispatch the prepare transition signal @@ -356,12 +347,12 @@ public class LauncherStateTransitionAnimation { dispatchOnLauncherTransitionPrepare(toView, animated, false); - final AnimatorSet stateAnimation = mStateAnimation; + final AnimatorSet stateAnimation = animation; final Runnable startAnimRunnable = new Runnable() { public void run() { - // Check that mStateAnimation hasn't changed while + // Check that mCurrentAnimation hasn't changed while // we waited for a layout/draw pass - if (mStateAnimation != stateAnimation) + if (mCurrentAnimation != stateAnimation) return; dispatchOnLauncherTransitionStart(fromView, animated, false); dispatchOnLauncherTransitionStart(toView, animated, false); @@ -380,12 +371,14 @@ public class LauncherStateTransitionAnimation { // Focus the new view toView.requestFocus(); - mStateAnimation.start(); + stateAnimation.start(); } }; toView.bringToFront(); toView.setVisibility(View.VISIBLE); toView.post(startAnimRunnable); + + return animation; } else { toView.setTranslationX(0.0f); toView.setTranslationY(0.0f); @@ -397,10 +390,6 @@ public class LauncherStateTransitionAnimation { // Show the content view contentView.setVisibility(View.VISIBLE); - if (hideSearchBar) { - mCb.onStateTransitionHideSearchBar(); - } - dispatchOnLauncherTransitionPrepare(fromView, animated, false); dispatchOnLauncherTransitionStart(fromView, animated, false); dispatchOnLauncherTransitionEnd(fromView, animated, false); @@ -408,18 +397,19 @@ public class LauncherStateTransitionAnimation { dispatchOnLauncherTransitionStart(toView, animated, false); dispatchOnLauncherTransitionEnd(toView, animated, false); pCb.onTransitionComplete(); + + return null; } } /** * Starts and animation to the workspace from the apps view. */ - private void startAnimationToWorkspaceFromAllApps(final Workspace.State toWorkspaceState, - final int toWorkspacePage, final boolean animated, final Runnable onCompleteRunnable) { + private void startAnimationToWorkspaceFromAllApps(final Workspace.State fromWorkspaceState, + final Workspace.State toWorkspaceState, final int toWorkspacePage, + final boolean animated, final Runnable onCompleteRunnable) { AllAppsContainerView appsView = mLauncher.getAppsView(); PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() { - int[] mAllAppsToPanelDelta; - @Override float getMaterialRevealViewFinalAlpha(View revealView) { // No alpha anim from all apps @@ -451,8 +441,8 @@ public class LauncherStateTransitionAnimation { } }; // Only animate the search bar if animating to spring loaded mode from all apps - startAnimationToWorkspaceFromOverlay(toWorkspaceState, toWorkspacePage, - mLauncher.getAllAppsButton(), appsView, appsView.getContentView(), + mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState, toWorkspaceState, + toWorkspacePage, mLauncher.getAllAppsButton(), appsView, appsView.getContentView(), appsView.getRevealView(), appsView.getSearchBarView(), animated, onCompleteRunnable, cb); } @@ -460,8 +450,9 @@ public class LauncherStateTransitionAnimation { /** * Starts and animation to the workspace from the widgets view. */ - private void startAnimationToWorkspaceFromWidgets(final Workspace.State toWorkspaceState, - final int toWorkspacePage, final boolean animated, final Runnable onCompleteRunnable) { + private void startAnimationToWorkspaceFromWidgets(final Workspace.State fromWorkspaceState, + final Workspace.State toWorkspaceState, final int toWorkspacePage, + final boolean animated, final Runnable onCompleteRunnable) { final WidgetsContainerView widgetsView = mLauncher.getWidgetsView(); PrivateTransitionCallbacks cb = new PrivateTransitionCallbacks() { @Override @@ -479,19 +470,21 @@ public class LauncherStateTransitionAnimation { }; } }; - startAnimationToWorkspaceFromOverlay(toWorkspaceState, toWorkspacePage, - mLauncher.getWidgetsButton(), widgetsView, widgetsView.getContentView(), - widgetsView.getRevealView(), null, animated, onCompleteRunnable, cb); + mCurrentAnimation = startAnimationToWorkspaceFromOverlay(fromWorkspaceState, + toWorkspaceState, toWorkspacePage, mLauncher.getWidgetsButton(), widgetsView, + widgetsView.getContentView(), widgetsView.getRevealView(), null, animated, + onCompleteRunnable, cb); } /** * Creates and starts a new animation to the workspace. */ - private void startAnimationToWorkspaceFromOverlay(final Workspace.State toWorkspaceState, - final int toWorkspacePage, final View buttonView, final View fromView, - final View contentView, final View revealView, final View overlaySearchBarView, - final boolean animated, final Runnable onCompleteRunnable, - final PrivateTransitionCallbacks pCb) { + private AnimatorSet startAnimationToWorkspaceFromOverlay(final Workspace.State fromWorkspaceState, + final Workspace.State toWorkspaceState, final int toWorkspacePage, final View buttonView, + final View fromView, final View contentView, final View revealView, + final View overlaySearchBarView, final boolean animated, final Runnable onCompleteRunnable, + final PrivateTransitionCallbacks pCb) { + final AnimatorSet animation = LauncherAnimUtils.createAnimatorSet(); final Resources res = mLauncher.getResources(); final boolean material = Utilities.isLmpOrAbove(); final int revealDuration = res.getInteger(R.integer.config_overlayRevealTime); @@ -511,15 +504,16 @@ public class LauncherStateTransitionAnimation { // Create the workspace animation. // NOTE: this call apparently also sets the state for the workspace if !animated Animator workspaceAnim = mLauncher.startWorkspaceStateChangeAnimation(toWorkspaceState, - toWorkspacePage, animated, overlaySearchBarView != null /* hasOverlaySearchBar */, - layerViews); + toWorkspacePage, animated, layerViews); - if (animated && initialized) { - mStateAnimation = LauncherAnimUtils.createAnimatorSet(); + // Animate the search bar + startWorkspaceSearchBarAnimation(animation, fromWorkspaceState, toWorkspaceState, + animated ? revealDuration : 0, overlaySearchBarView); + if (animated && initialized) { // Play the workspace animation if (workspaceAnim != null) { - mStateAnimation.play(workspaceAnim); + animation.play(workspaceAnim); } // hideAppsCustomizeHelper is called in some cases when it is already hidden @@ -558,14 +552,14 @@ public class LauncherStateTransitionAnimation { panelDriftY.setDuration(revealDuration - SINGLE_FRAME_DELAY); panelDriftY.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); panelDriftY.setInterpolator(decelerateInterpolator); - mStateAnimation.play(panelDriftY); + animation.play(panelDriftY); ObjectAnimator panelDriftX = ObjectAnimator.ofFloat(revealView, "translationX", 0, revealViewToXDrift); panelDriftX.setDuration(revealDuration - SINGLE_FRAME_DELAY); panelDriftX.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); panelDriftX.setInterpolator(decelerateInterpolator); - mStateAnimation.play(panelDriftX); + animation.play(panelDriftX); // Setup animation for the reveal panel alpha final float revealViewToAlpha = !material ? 0f : @@ -576,7 +570,7 @@ public class LauncherStateTransitionAnimation { panelAlpha.setDuration(material ? revealDuration : 150); panelAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY); panelAlpha.setInterpolator(decelerateInterpolator); - mStateAnimation.play(panelAlpha); + animation.play(panelAlpha); } // Setup the animation for the content view @@ -589,13 +583,13 @@ public class LauncherStateTransitionAnimation { pageDrift.setDuration(revealDuration - SINGLE_FRAME_DELAY); pageDrift.setInterpolator(decelerateInterpolator); pageDrift.setStartDelay(itemsAlphaStagger + SINGLE_FRAME_DELAY); - mStateAnimation.play(pageDrift); + animation.play(pageDrift); contentView.setAlpha(1f); ObjectAnimator itemsAlpha = ObjectAnimator.ofFloat(contentView, "alpha", 1f, 0f); itemsAlpha.setDuration(100); itemsAlpha.setInterpolator(decelerateInterpolator); - mStateAnimation.play(itemsAlpha); + animation.play(itemsAlpha); if (overlaySearchBarView != null) { overlaySearchBarView.setAlpha(1f); @@ -604,7 +598,7 @@ public class LauncherStateTransitionAnimation { searchAlpha.setInterpolator(decelerateInterpolator); searchAlpha.setStartDelay(material ? 0 : itemsAlphaStagger + SINGLE_FRAME_DELAY); layerViews.put(overlaySearchBarView, BUILD_AND_SET_LAYER); - mStateAnimation.play(searchAlpha); + animation.play(searchAlpha); } if (material) { @@ -620,14 +614,14 @@ public class LauncherStateTransitionAnimation { if (listener != null) { reveal.addListener(listener); } - mStateAnimation.play(reveal); + animation.play(reveal); } dispatchOnLauncherTransitionPrepare(fromView, animated, true); dispatchOnLauncherTransitionPrepare(toView, animated, true); } - mStateAnimation.addListener(new AnimatorListenerAdapter() { + animation.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { fromView.setVisibility(View.GONE); @@ -657,18 +651,19 @@ public class LauncherStateTransitionAnimation { } // This can hold unnecessary references to views. - mStateAnimation = null; + cleanupAnimation(); pCb.onTransitionComplete(); } }); - final AnimatorSet stateAnimation = mStateAnimation; + final AnimatorSet stateAnimation = animation; final Runnable startAnimRunnable = new Runnable() { public void run() { - // Check that mStateAnimation hasn't changed while + // Check that mCurrentAnimation hasn't changed while // we waited for a layout/draw pass - if (mStateAnimation != stateAnimation) + if (mCurrentAnimation != stateAnimation) return; + dispatchOnLauncherTransitionStart(fromView, animated, false); dispatchOnLauncherTransitionStart(toView, animated, false); @@ -682,10 +677,12 @@ public class LauncherStateTransitionAnimation { v.buildLayer(); } } - mStateAnimation.start(); + stateAnimation.start(); } }; fromView.post(startAnimRunnable); + + return animation; } else { fromView.setVisibility(View.GONE); dispatchOnLauncherTransitionPrepare(fromView, animated, true); @@ -700,9 +697,44 @@ public class LauncherStateTransitionAnimation { if (onCompleteRunnable != null) { onCompleteRunnable.run(); } + + return null; } } + /** + * Coordinates the workspace search bar animation along with the launcher state animation. + */ + private void startWorkspaceSearchBarAnimation(AnimatorSet animation, + final Workspace.State fromWorkspaceState, final Workspace.State toWorkspaceState, int duration, + View overlaySearchBar) { + final SearchDropTargetBar.State toSearchBarState = + toWorkspaceState.getSearchDropTargetBarState(); + + if (overlaySearchBar != null) { + if ((toWorkspaceState == Workspace.State.NORMAL) && + (fromWorkspaceState == Workspace.State.NORMAL_HIDDEN)) { + // If we are transitioning from the overlay to the workspace, then show the + // workspace search bar immediately and let the overlay search bar fade out on top + mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, 0); + } else if (fromWorkspaceState == Workspace.State.NORMAL) { + // If we are transitioning from the workspace to the overlay, then keep the + // workspace search bar visible until the overlay search bar fades in on top + animation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, 0); + } + }); + } else { + // Otherwise, then just animate the workspace search bar normally + mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration); + } + } else { + // If there is no overlay search bar, then just animate the workspace search bar + mLauncher.getSearchDropTargetBar().animateToState(toSearchBarState, duration); + } + } /** * Dispatches the prepare-transition event to suitable views. @@ -753,10 +785,14 @@ public class LauncherStateTransitionAnimation { * Cancels the current animation. */ private void cancelAnimation() { - if (mStateAnimation != null) { - mStateAnimation.setDuration(0); - mStateAnimation.cancel(); - mStateAnimation = null; + if (mCurrentAnimation != null) { + mCurrentAnimation.setDuration(0); + mCurrentAnimation.cancel(); + mCurrentAnimation = null; } } + + private void cleanupAnimation() { + mCurrentAnimation = null; + } } diff --git a/src/com/android/launcher3/LauncherViewPropertyAnimator.java b/src/com/android/launcher3/LauncherViewPropertyAnimator.java index 4cafbbfa6..4406a2c5c 100644 --- a/src/com/android/launcher3/LauncherViewPropertyAnimator.java +++ b/src/com/android/launcher3/LauncherViewPropertyAnimator.java @@ -26,6 +26,7 @@ import java.util.ArrayList; import java.util.EnumSet; public class LauncherViewPropertyAnimator extends Animator implements AnimatorListener { + enum Properties { TRANSLATION_X, TRANSLATION_Y, @@ -51,13 +52,12 @@ public class LauncherViewPropertyAnimator extends Animator implements AnimatorLi long mStartDelay; long mDuration; TimeInterpolator mInterpolator; - ArrayList mListeners; + ArrayList mListeners = new ArrayList<>(); boolean mRunning = false; FirstFrameAnimatorHelper mFirstFrameHelper; public LauncherViewPropertyAnimator(View target) { mTarget = target; - mListeners = new ArrayList(); } @Override diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java index 4cdf1cac9..fe89c15a7 100644 --- a/src/com/android/launcher3/SearchDropTargetBar.java +++ b/src/com/android/launcher3/SearchDropTargetBar.java @@ -18,12 +18,11 @@ package com.android.launcher3; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; +import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateInterpolator; import android.widget.FrameLayout; @@ -33,17 +32,41 @@ import android.widget.FrameLayout; */ public class SearchDropTargetBar extends FrameLayout implements DragController.DragListener { - private static final int TRANSITION_DURATION = 200; + /** The different states that the search bar space can be in. */ + public enum State { + INVISIBLE (0f, 0f), + SEARCH_BAR (1f, 0f), + DROP_TARGET (0f, 1f); - private ObjectAnimator mShowDropTargetBarAnim; - private ValueAnimator mHideSearchBarAnim; + private final float mSearchBarAlpha; + private final float mDropTargetBarAlpha; + + State(float sbAlpha, float dtbAlpha) { + mSearchBarAlpha = sbAlpha; + mDropTargetBarAlpha = dtbAlpha; + } + + float getSearchBarAlpha() { + return mSearchBarAlpha; + } + + float getDropTargetBarAlpha() { + return mDropTargetBarAlpha; + } + } + + private static int DEFAULT_DRAG_FADE_DURATION = 175; + + private LauncherViewPropertyAnimator mDropTargetBarAnimator; + private LauncherViewPropertyAnimator mQSBSearchBarAnimator; private static final AccelerateInterpolator sAccelerateInterpolator = new AccelerateInterpolator(); - private boolean mIsSearchBarHidden; - private View mQSBSearchBar; + private State mState = State.SEARCH_BAR; + private View mQSB; private View mDropTargetBar; private boolean mDeferOnDragEnd = false; + private boolean mAccessibilityEnabled = false; // Drop targets private ButtonDropTarget mInfoDropTarget; @@ -75,39 +98,6 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D mUninstallDropTarget.setLauncher(launcher); } - public void setQsbSearchBar(View qsb) { - mQSBSearchBar = qsb; - if (mQSBSearchBar != null) { - mHideSearchBarAnim = LauncherAnimUtils.ofFloat(mQSBSearchBar, "alpha", 1f, 0f); - setupAnimation(mHideSearchBarAnim, mQSBSearchBar); - } else { - // Create a no-op animation of the search bar is null - mHideSearchBarAnim = ValueAnimator.ofFloat(0, 0); - mHideSearchBarAnim.setDuration(TRANSITION_DURATION); - } - } - - private void prepareStartAnimation(View v) { - // Enable the hw layers before the animation starts (will be disabled in the onAnimationEnd - // callback below) - if (v != null) { - v.setLayerType(View.LAYER_TYPE_HARDWARE, null); - } - } - - private void setupAnimation(ValueAnimator anim, final View v) { - anim.setInterpolator(sAccelerateInterpolator); - anim.setDuration(TRANSITION_DURATION); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (v != null) { - v.setLayerType(View.LAYER_TYPE_NONE, null); - } - } - }); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -124,72 +114,84 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D // Create the various fade animations 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); - mShowDropTargetBarAnim.reverse(); - prepareStartAnimation(mQSBSearchBar); - mHideSearchBarAnim.reverse(); - } + mDropTargetBarAnimator = new LauncherViewPropertyAnimator(mDropTargetBar); + mDropTargetBarAnimator.setInterpolator(sAccelerateInterpolator); + mDropTargetBarAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + // Ensure that the view is visible for the animation + mDropTargetBar.setVisibility(View.VISIBLE); + } - /** - * Shows the search bar. - */ - public void showSearchBar(boolean animated) { - if (!mIsSearchBarHidden) return; - if (animated) { - prepareStartAnimation(mQSBSearchBar); - mHideSearchBarAnim.reverse(); - } else { - mHideSearchBarAnim.cancel(); - if (mQSBSearchBar != null) { - mQSBSearchBar.setAlpha(1f); + @Override + public void onAnimationEnd(Animator animation) { + if (mDropTargetBar != null) { + AlphaUpdateListener.updateVisibility(mDropTargetBar, mAccessibilityEnabled); + } } - } - mIsSearchBarHidden = false; + }); } - /** - * Hides the search bar. We only use this for clings. - */ - public void hideSearchBar(boolean animated) { - if (mIsSearchBarHidden) return; - if (animated) { - prepareStartAnimation(mQSBSearchBar); - mHideSearchBarAnim.start(); + public void setQsbSearchBar(View qsb) { + mQSB = qsb; + if (mQSB != null) { + // Update the search ber animation + mQSBSearchBarAnimator = new LauncherViewPropertyAnimator(mQSB); + mQSBSearchBarAnimator.setInterpolator(sAccelerateInterpolator); + mQSBSearchBarAnimator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + // Ensure that the view is visible for the animation + if (mQSB != null) { + mQSB.setVisibility(View.VISIBLE); + } + } + + @Override + public void onAnimationEnd(Animator animation) { + if (mQSB != null) { + AlphaUpdateListener.updateVisibility(mQSB, mAccessibilityEnabled); + } + } + }); } else { - mHideSearchBarAnim.cancel(); - if (mQSBSearchBar != null) { - mQSBSearchBar.setAlpha(0f); - } + mQSBSearchBarAnimator = null; } - mIsSearchBarHidden = true; } /** - * Shows the drop target bar. + * Animates the current search bar state to a new state. If the {@param duration} is 0, then + * the state is applied immediately. */ - public void showDeleteTarget() { - // Animate out the QSB search bar, and animate in the drop target bar - prepareStartAnimation(mDropTargetBar); - mShowDropTargetBarAnim.start(); - hideSearchBar(true); + public void animateToState(State newState, int duration) { + if (mState != newState) { + mState = newState; + + // Update the accessibility state + AccessibilityManager am = (AccessibilityManager) + getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + mAccessibilityEnabled = am.isEnabled(); + + animateViewAlpha(mQSBSearchBarAnimator, mQSB, newState.getSearchBarAlpha(), + duration); + animateViewAlpha(mDropTargetBarAnimator, mDropTargetBar, newState.getDropTargetBarAlpha(), + duration); + } } /** - * Hides the drop target bar. + * Convenience method to animate the alpha of a view using hardware layers. */ - public void hideDeleteTarget() { - // Restore the QSB search bar, and animate out the drop target bar - prepareStartAnimation(mDropTargetBar); - mShowDropTargetBarAnim.reverse(); - showSearchBar(true); + private void animateViewAlpha(LauncherViewPropertyAnimator animator, View v, float alpha, + int duration) { + if (v != null && Float.compare(v.getAlpha(), alpha) != 0) { + if (duration > 0) { + animator.alpha(alpha).withLayer().setDuration(duration).start(); + } else { + v.setAlpha(alpha); + AlphaUpdateListener.updateVisibility(v, mAccessibilityEnabled); + } + } } /* @@ -197,9 +199,13 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D */ @Override public void onDragStart(DragSource source, Object info, int dragAction) { - showDeleteTarget(); + animateToState(State.DROP_TARGET, DEFAULT_DRAG_FADE_DURATION); } + /** + * This is called to defer hiding the delete drop target until the drop animation has completed, + * instead of hiding immediately when the drag has ended. + */ public void deferOnDragEnd() { mDeferOnDragEnd = true; } @@ -207,22 +213,25 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D @Override public void onDragEnd() { if (!mDeferOnDragEnd) { - hideDeleteTarget(); + animateToState(State.SEARCH_BAR, DEFAULT_DRAG_FADE_DURATION); } else { mDeferOnDragEnd = false; } } + /** + * @return the bounds of the QSB search bar. + */ public Rect getSearchBarBounds() { - if (mQSBSearchBar != null) { + if (mQSB != null) { final int[] pos = new int[2]; - mQSBSearchBar.getLocationOnScreen(pos); + mQSB.getLocationOnScreen(pos); final Rect rect = new Rect(); rect.left = pos[0]; rect.top = pos[1]; - rect.right = pos[0] + mQSBSearchBar.getWidth(); - rect.bottom = pos[1] + mQSBSearchBar.getHeight(); + rect.right = pos[0] + mQSB.getWidth(); + rect.bottom = pos[1] + mQSB.getHeight(); return rect; } else { return null; @@ -230,8 +239,8 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D } public void enableAccessibleDrag(boolean enable) { - if (mQSBSearchBar != null) { - mQSBSearchBar.setVisibility(enable ? View.GONE : View.VISIBLE); + if (mQSB != null) { + mQSB.setVisibility(enable ? View.GONE : View.VISIBLE); } mInfoDropTarget.enableAccessibleDrag(enable); mDeleteDropTarget.enableAccessibleDrag(enable); diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 086934773..bbcabe1c2 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -178,7 +178,24 @@ public class Workspace extends PagedView // State variable that indicates whether the pages are small (ie when you're // in all apps or customize mode) - enum State { NORMAL, NORMAL_HIDDEN, SPRING_LOADED, OVERVIEW, OVERVIEW_HIDDEN}; + enum State { + NORMAL (SearchDropTargetBar.State.SEARCH_BAR), + NORMAL_HIDDEN (SearchDropTargetBar.State.INVISIBLE), + SPRING_LOADED (SearchDropTargetBar.State.DROP_TARGET), + OVERVIEW (SearchDropTargetBar.State.INVISIBLE), + OVERVIEW_HIDDEN (SearchDropTargetBar.State.INVISIBLE); + + private final SearchDropTargetBar.State mBarState; + + State(SearchDropTargetBar.State searchBarState) { + mBarState = searchBarState; + } + + public SearchDropTargetBar.State getSearchDropTargetBarState() { + return mBarState; + } + }; + private State mState = State.NORMAL; private boolean mIsSwitchingState = false; @@ -1567,7 +1584,7 @@ public class Workspace extends PagedView // Reset our click listener setOnClickListener(mLauncher); } - mLauncher.getSearchBar().enableAccessibleDrag(enable); + mLauncher.getSearchDropTargetBar().enableAccessibleDrag(enable); mLauncher.getHotseat().getLayout() .enableAccessibleDrag(enable, CellLayout.WORKSPACE_ACCESSIBILITY_DRAG); } @@ -1971,10 +1988,10 @@ public class Workspace extends PagedView * to that new state. */ public Animator setStateWithAnimation(State toState, int toPage, boolean animated, - boolean hasOverlaySearchBar, HashMap layerViews) { + HashMap layerViews) { // Create the animation to the new state Animator workspaceAnim = mStateTransitionAnimation.getAnimationToState(mState, - toState, toPage, animated, hasOverlaySearchBar, layerViews); + toState, toPage, animated, layerViews); // Update the current state mState = toState; diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java index e908ccd81..54f63bbd8 100644 --- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java +++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java @@ -218,16 +218,13 @@ public class WorkspaceStateTransitionAnimation { } public AnimatorSet getAnimationToState(Workspace.State fromState, Workspace.State toState, - int toPage, boolean animated, boolean hasOverlaySearchBar, - HashMap layerViews) { + int toPage, boolean animated, HashMap layerViews) { AccessibilityManager am = (AccessibilityManager) mLauncher.getSystemService(Context.ACCESSIBILITY_SERVICE); final boolean accessibilityEnabled = am.isEnabled(); TransitionStates states = new TransitionStates(fromState, toState); - int duration = getAnimationDuration(states); - animateWorkspace(states, toPage, animated, duration, layerViews, - accessibilityEnabled); - animateSearchBar(states, animated, duration, hasOverlaySearchBar, layerViews, + int workspaceDuration = getAnimationDuration(states); + animateWorkspace(states, toPage, animated, workspaceDuration, layerViews, accessibilityEnabled); animateBackgroundGradient(states, animated, BACKGROUND_FADE_OUT_DURATION); return mStateAnimator; @@ -473,76 +470,10 @@ public class WorkspaceStateTransitionAnimation { } } - /** - * Coordinates with the workspace animation to animate the search bar. - * - * 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. - */ - private void animateSearchBar(TransitionStates states, boolean animated, int duration, - boolean hasOverlaySearchBar, final HashMap layerViews, - final boolean accessibilityEnabled) { - - // The search bar is only visible in the workspace - final View searchBar = mLauncher.getOrCreateQsbBar(); - if (searchBar != null) { - final boolean searchBarWillBeShown = states.stateIsNormal; - final float finalSearchBarAlpha = searchBarWillBeShown ? 1f : 0f; - if (animated) { - if (hasOverlaySearchBar) { - // If there is an overlay search bar, then we will coordinate with it. - mStateAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - // If we are transitioning to a visible search bar, show it immediately - // and let the overlay search bar has faded out - if (searchBarWillBeShown) { - searchBar.setAlpha(finalSearchBarAlpha); - AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled); - } - } - - @Override - public void onAnimationEnd(Animator animation) { - // If we are transitioning to a hidden search bar, hide it only after - // the overlay search bar has faded in - if (!searchBarWillBeShown) { - searchBar.setAlpha(finalSearchBarAlpha); - AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled); - } - } - }); - } else { - // Otherwise, we can just do the normal animation - 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); - } - } else { - // Set the search bar state immediately - searchBar.setAlpha(finalSearchBarAlpha); - AlphaUpdateListener.updateVisibility(searchBar, accessibilityEnabled); - } - } - } - /** * Animates the background scrim. Add to the state animator to prevent jankiness. * - * @param finalAlpha the final alpha for the background scrim + * @param states the current and final workspace states * @param animated whether or not to set the background alpha immediately * @duration duration of the animation */ -- cgit v1.2.3