Fixing state transition bugs

- explicitly keeping track of state in Workspace
- cancelling animations before starting new ones
- adding additional state variable for workspace for in-progress transitions
- updating Scroller object if we jump to a certain location

Change-Id: I5ddf51bae543ec89b2a44ab651d7269eb4859a6d
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index f5a5935..f81a9bf 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -175,6 +175,8 @@
 
     /** The different states that Launcher can be in. */
     private enum State { WORKSPACE, ALL_APPS, CUSTOMIZE, OVERVIEW };
+    private State mState = State.WORKSPACE;
+    private AnimatorSet mStateAnimation;
 
     static final int APPWIDGET_HOST_ID = 1024;
 
@@ -930,21 +932,21 @@
 
     @SuppressWarnings({"UnusedDeclaration"})
     public void previousScreen(View v) {
-        if (!isAllAppsVisible()) {
+        if (mState != State.ALL_APPS) {
             mWorkspace.scrollLeft();
         }
     }
 
     @SuppressWarnings({"UnusedDeclaration"})
     public void nextScreen(View v) {
-        if (!isAllAppsVisible()) {
+        if (mState != State.ALL_APPS) {
             mWorkspace.scrollRight();
         }
     }
 
     @SuppressWarnings({"UnusedDeclaration"})
     public void launchHotSeat(View v) {
-        if (isAllAppsVisible()) return;
+        if (mState == State.ALL_APPS) return;
 
         int index = -1;
         if (v.getId() == R.id.hotseat_left) {
@@ -1172,8 +1174,6 @@
 
             boolean alreadyOnHome = ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
                         != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-            boolean allAppsVisible = isAllAppsVisible();
-            boolean customizationDrawerVisible = isCustomizationDrawerVisible();
 
             // in all these cases, only animate if we're already on home
             if (LauncherApplication.isScreenXLarge()) {
@@ -1181,11 +1181,10 @@
             }
             if (!mWorkspace.isDefaultPageShowing()) {
                 // on the phone, we don't animate the change to the workspace if all apps is visible
-                mWorkspace.moveToDefaultScreen(
-                        alreadyOnHome && (LauncherApplication.isScreenXLarge() || !allAppsVisible));
+                mWorkspace.moveToDefaultScreen(alreadyOnHome &&
+                        (LauncherApplication.isScreenXLarge() || mState != State.ALL_APPS));
             }
-            closeAllApps(alreadyOnHome && allAppsVisible);
-            hideCustomizationDrawer(alreadyOnHome);
+            showWorkspace(alreadyOnHome);
 
             final View v = getWindow().peekDecorView();
             if (v != null && v.getWindowToken() != null) {
@@ -1227,7 +1226,7 @@
         }
 
         // TODO should not do this if the drawer is currently closing.
-        if (isAllAppsVisible()) {
+        if (mState == State.ALL_APPS) {
             outState.putBoolean(RUNTIME_STATE_ALL_APPS_FOLDER, true);
         }
 
@@ -1289,7 +1288,7 @@
     public void startSearch(String initialQuery, boolean selectInitialQuery,
             Bundle appSearchData, boolean globalSearch) {
 
-        closeAllApps(true);
+        showWorkspace(true);
 
         if (initialQuery == null) {
             // Use any text typed in the launcher as the initial query
@@ -1407,11 +1406,11 @@
     private void addItems() {
         if (LauncherApplication.isScreenXLarge()) {
             // Animate the widget chooser up from the bottom of the screen
-            if (!isCustomizationDrawerVisible()) {
+            if (mState != State.CUSTOMIZE) {
                 showCustomizationDrawer(true);
             }
         } else {
-            closeAllApps(true);
+            showWorkspace(true);
             showAddDialog(-1, -1);
         }
     }
@@ -1614,7 +1613,7 @@
     }
 
     private void startWallpaper() {
-        closeAllApps(true);
+        showWorkspace(true);
         final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
         Intent chooser = Intent.createChooser(pickWallpaper,
                 getText(R.string.chooser_wallpaper));
@@ -1667,10 +1666,8 @@
 
     @Override
     public void onBackPressed() {
-        if (isAllAppsVisible()) {
-            closeAllApps(true);
-        } else if (isCustomizationDrawerVisible()) {
-            hideCustomizationDrawer(true);
+        if (mState == State.ALL_APPS || mState == State.CUSTOMIZE) {
+            showWorkspace(true);
         } else {
             closeFolder();
         }
@@ -1736,8 +1733,8 @@
         } else if (tag instanceof FolderInfo) {
             handleFolderClick((FolderInfo) tag);
         } else if (v == mHandleView) {
-            if (isAllAppsVisible()) {
-                closeAllApps(true);
+            if (mState == State.ALL_APPS) {
+                showWorkspace(true);
             } else {
                 showAllApps(true);
             }
@@ -1746,8 +1743,8 @@
 
     public boolean onTouch(View v, MotionEvent event) {
         // this is an intercepted event being forwarded from mWorkspace;
-        // clicking anywhere on the workspace causes the drawer to slide down
-        hideCustomizationDrawer(true);
+        // clicking anywhere on the workspace causes the customization drawer to slide down
+        showWorkspace(true);
         return false;
     }
 
@@ -1893,21 +1890,21 @@
     public boolean onLongClick(View v) {
         switch (v.getId()) {
             case R.id.previous_screen:
-                if (!isAllAppsVisible()) {
+                if (mState != State.ALL_APPS) {
                     mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                             HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     showPreviews(v);
                 }
                 return true;
             case R.id.next_screen:
-                if (!isAllAppsVisible()) {
+                if (mState != State.ALL_APPS) {
                     mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                             HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     showPreviews(v);
                 }
                 return true;
             case R.id.all_apps_button:
-                if (!isAllAppsVisible()) {
+                if (mState != State.ALL_APPS) {
                     mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                             HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     showPreviews(v);
@@ -2239,7 +2236,7 @@
 
     // Now a part of LauncherModel.Callbacks. Used to reorder loading steps.
     public boolean isAllAppsVisible() {
-        return mAllAppsGrid != null && mAllAppsGrid.isVisible();
+        return mState == State.ALL_APPS;
     }
 
     // AllAppsView.Watcher
@@ -2401,14 +2398,15 @@
             // toView should appear right at the end of the workspace shrink animation
             final int startDelay = res.getInteger(R.integer.config_workspaceShrinkTime) - duration;
 
-            AnimatorSet s = new AnimatorSet();
-            s.playTogether(scaleAnim, toolbarHideAnim);
-            s.play(scaleAnim).after(startDelay);
+            if (mStateAnimation != null) mStateAnimation.cancel();
+            mStateAnimation = new AnimatorSet();
+            mStateAnimation.playTogether(scaleAnim, toolbarHideAnim);
+            mStateAnimation.play(scaleAnim).after(startDelay);
 
             // Show the new toolbar buttons just as the main animation is ending
             final int fadeInTime = res.getInteger(R.integer.config_toolbarButtonFadeInTime);
-            s.play(toolbarShowAnim).after(duration + startDelay - fadeInTime);
-            s.start();
+            mStateAnimation.play(toolbarShowAnim).after(duration + startDelay - fadeInTime);
+            mStateAnimation.start();
         } else {
             toView.setTranslationX(0.0f);
             toView.setTranslationY(0.0f);
@@ -2440,12 +2438,13 @@
         mWorkspace.unshrink(animated);
 
         if (animated) {
-            AnimatorSet s = new AnimatorSet();
+            if (mStateAnimation != null) mStateAnimation.cancel();
+            mStateAnimation = new AnimatorSet();
             ValueAnimator scaleAnim = new ObjectAnimator(duration, fromView,
                     new PropertyValuesHolder<Float>("scaleX", scaleFactor),
                     new PropertyValuesHolder<Float>("scaleY", scaleFactor));
             scaleAnim.setInterpolator(new AccelerateInterpolator());
-            s.addListener(new AnimatorListenerAdapter() {
+            mStateAnimation.addListener(new AnimatorListenerAdapter() {
                 public void onAnimationEnd(Animator animation) {
                     fromView.setVisibility(View.GONE);
                     fromView.setScaleX(1.0f);
@@ -2457,13 +2456,13 @@
             AnimatorSet toolbarShowAnim = new AnimatorSet();
             hideAndShowToolbarButtons(State.WORKSPACE, toolbarShowAnim, toolbarHideAnim);
 
-            s.playTogether(scaleAnim, toolbarHideAnim);
+            mStateAnimation.playTogether(scaleAnim, toolbarHideAnim);
 
             // Show the new toolbar buttons at the very end of the whole animation
             final int fadeInTime = res.getInteger(R.integer.config_toolbarButtonFadeInTime);
             final int unshrinkTime = res.getInteger(R.integer.config_workspaceUnshrinkTime);
-            s.play(toolbarShowAnim).after(unshrinkTime - fadeInTime);
-            s.start();
+            mStateAnimation.play(toolbarShowAnim).after(unshrinkTime - fadeInTime);
+            mStateAnimation.start();
         } else {
             fromView.setVisibility(View.GONE);
             hideAndShowToolbarButtons(State.WORKSPACE, null, null);
@@ -2502,8 +2501,9 @@
         }
 
         if (animated) {
-            AnimatorSet s = new AnimatorSet();
-            s.addListener(new AnimatorListenerAdapter() {
+            if (mStateAnimation != null) mStateAnimation.cancel();
+            mStateAnimation = new AnimatorSet();
+            mStateAnimation.addListener(new AnimatorListenerAdapter() {
                 public void onAnimationStart(Animator animation) {
                     toView.setVisibility(View.VISIBLE);
                     toView.setY(toViewStartY);
@@ -2517,15 +2517,15 @@
             AnimatorSet toolbarShowAnim = new AnimatorSet();
             hideAndShowToolbarButtons(toState, toolbarShowAnim, toolbarHideAnim);
 
-            s.playTogether(
+            mStateAnimation.playTogether(
                     toolbarHideAnim,
                     new ObjectAnimator(duration, fromView, "y", fromViewStartY, fromViewEndY),
                     new ObjectAnimator(duration, toView, "y", toViewStartY, toViewEndY));
 
             // Show the new toolbar buttons just as the main animation is ending
             final int fadeInTime = res.getInteger(R.integer.config_toolbarButtonFadeInTime);
-            s.play(toolbarShowAnim).after(duration - fadeInTime);
-            s.start();
+            mStateAnimation.play(toolbarShowAnim).after(duration - fadeInTime);
+            mStateAnimation.start();
         } else {
             fromView.setY(fromViewEndY);
             fromView.setVisibility(View.GONE);
@@ -2536,11 +2536,11 @@
     }
 
     void showAllApps(boolean animated) {
-        if (mAllAppsGrid.isVisible())
+        if (mState == State.ALL_APPS)
             return;
 
         if (LauncherApplication.isScreenXLarge()) {
-            if (isCustomizationDrawerVisible()) {
+            if (mState == State.CUSTOMIZE) {
                 cameraPan(State.CUSTOMIZE, State.ALL_APPS, animated);
             } else {
                 cameraZoomOut(State.ALL_APPS, animated);
@@ -2554,6 +2554,28 @@
 
         // TODO: fade these two too
         mDeleteZone.setVisibility(View.GONE);
+        // Change the state *after* we've called all the transition code
+        mState = State.ALL_APPS;
+    }
+
+
+    void showWorkspace(boolean animated) {
+        showWorkspace(animated, null);
+    }
+
+    void showWorkspace(boolean animated, CellLayout layout) {
+        if (layout != null && animated) {
+            mWorkspace.unshrink(layout);
+        } else {
+            mWorkspace.unshrink(animated);
+        }
+        if (mState == State.ALL_APPS) {
+            closeAllApps(animated);
+        } else if (mState == State.CUSTOMIZE) {
+            hideCustomizationDrawer(animated);
+        }
+        // Change the state *after* we've called all the transition code
+        mState = State.WORKSPACE;
     }
 
     /**
@@ -2596,7 +2618,7 @@
      *          - From another workspace
      */
     void closeAllApps(boolean animated) {
-        if (mAllAppsGrid.isVisible()) {
+        if (mState == State.ALL_APPS) {
             mWorkspace.setVisibility(View.VISIBLE);
             if (LauncherApplication.isScreenXLarge()) {
                 cameraZoomIn(State.ALL_APPS, animated);
@@ -2616,23 +2638,20 @@
         // TODO
     }
 
-    private boolean isCustomizationDrawerVisible() {
-        return mHomeCustomizationDrawer != null &&
-                mHomeCustomizationDrawer.getVisibility() == View.VISIBLE;
-    }
-
     // Show the customization drawer (only exists in x-large configuration)
     private void showCustomizationDrawer(boolean animated) {
-        if (isAllAppsVisible()) {
+        if (mState == State.ALL_APPS) {
             cameraPan(State.ALL_APPS, State.CUSTOMIZE, animated);
         } else {
             cameraZoomOut(State.CUSTOMIZE, animated);
         }
+        // Change the state *after* we've called all the transition code
+        mState = State.CUSTOMIZE;
     }
 
     // Hide the customization drawer (only exists in x-large configuration)
     void hideCustomizationDrawer(boolean animated) {
-        if (isCustomizationDrawerVisible()) {
+        if (mState == State.CUSTOMIZE) {
             cameraZoomIn(State.CUSTOMIZE, animated);
         }
     }
@@ -2645,12 +2664,7 @@
 
         if (itemInfo == null) {
             // No items are chosen in All Apps or Customize, so just zoom into the workspace
-            mWorkspace.unshrink(layout);
-            if (isAllAppsVisible()) {
-                closeAllApps(true);
-            } else if (isCustomizationDrawerVisible()) {
-                hideCustomizationDrawer(true);
-            }
+            showWorkspace(true, layout);
         } else {
             // Act as if the chosen item was dropped on the given CellLayout
             if (mWorkspace.addExternalItemToScreen(itemInfo, layout)) {
@@ -2834,8 +2848,7 @@
                 if (mPaused || "lock".equals(reason)) {
                     animate = false;
                 }
-                closeAllApps(animate);
-                hideCustomizationDrawer(animate);
+                showWorkspace(animate);
             }
         }
     }