Exposing the state manager directly instead of providing various helper methods for state change

Bug: 67678570
Change-Id: If3d05c804c034ffa5e403da8eaa23e85e373c863
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index e3acf70..cd9fffc 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -19,8 +19,10 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
-import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_NEXT_FRAME;
 import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
 import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
 import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS;
 import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS;
@@ -58,7 +60,6 @@
 import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.Parcelable;
 import android.os.Process;
 import android.os.StrictMode;
@@ -203,7 +204,7 @@
     // Type: SparseArray<Parcelable>
     private static final String RUNTIME_STATE_WIDGET_PANEL = "launcher.widget_panel";
 
-    private LauncherStateTransitionAnimation mStateTransitionAnimation;
+    private LauncherStateManager mStateManager;
 
     private boolean mIsSafeModeEnabled;
 
@@ -257,7 +258,6 @@
     private ModelWriter mModelWriter;
     private IconCache mIconCache;
     private LauncherAccessibilityDelegate mAccessibilityDelegate;
-    private final Handler mHandler = new Handler();
     private boolean mHasFocus = false;
 
     private ObjectAnimator mScrimAnimator;
@@ -271,11 +271,6 @@
     // it from the context.
     private SharedPreferences mSharedPrefs;
 
-    // Exiting spring loaded mode happens with a delay. This runnable object triggers the
-    // state transition. If another state transition happened during this delay,
-    // simply unregister this runnable.
-    private Runnable mExitSpringLoadedModeRunnable;
-
     // Activity result which needs to be processed after workspace has loaded.
     private ActivityResultInfo mPendingActivityResult;
     /**
@@ -342,7 +337,7 @@
 
         mDragController = new DragController(this);
         mAllAppsController = new AllAppsTransitionController(this);
-        mStateTransitionAnimation = new LauncherStateTransitionAnimation(this, mAllAppsController);
+        mStateManager = new LauncherStateManager(this, mAllAppsController);
 
         mAppWidgetManager = AppWidgetManagerCompat.getInstance(this);
 
@@ -430,8 +425,8 @@
         recreate();
     }
 
-    public LauncherStateTransitionAnimation getStateTransition() {
-        return mStateTransitionAnimation;
+    public LauncherStateManager getStateManager() {
+        return mStateManager;
     }
 
     protected void overrideTheme(boolean isDark, boolean supportsDarkText) {
@@ -565,7 +560,7 @@
         Runnable exitSpringLoaded = new Runnable() {
             @Override
             public void run() {
-                exitSpringLoadedDragMode(SPRING_LOADED_EXIT_DELAY);
+                mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
             }
         };
 
@@ -585,11 +580,11 @@
             }
             return;
         } else if (requestCode == REQUEST_PICK_WALLPAPER) {
-            if (resultCode == RESULT_OK && isInState(LauncherState.OVERVIEW)) {
+            if (resultCode == RESULT_OK && isInState(OVERVIEW)) {
                 // User could have free-scrolled between pages before picking a wallpaper; make sure
                 // we move to the closest one now.
                 mWorkspace.setCurrentPage(mWorkspace.getPageNearestToCenterOfScreen());
-                showWorkspace(false);
+                mStateManager.goToState(NORMAL, false);
             }
             return;
         }
@@ -617,7 +612,7 @@
                 final Runnable onComplete = new Runnable() {
                     @Override
                     public void run() {
-                        exitSpringLoadedDragMode(SPRING_LOADED_EXIT_NEXT_FRAME);
+                        getStateManager().goToState(NORMAL);
                     }
                 };
 
@@ -745,7 +740,7 @@
                 @Override
                 public void run() {
                     completeAddAppWidget(appWidgetId, requestArgs, layout, null);
-                    exitSpringLoadedDragMode(SPRING_LOADED_EXIT_DELAY);
+                    mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
                 }
             };
         } else if (resultCode == RESULT_CANCELED) {
@@ -990,9 +985,16 @@
                 AbstractFloatingView.closeAllOpenViews(this);
 
                 // Show the overview mode if we are on the workspace
-                if (isInState(LauncherState.NORMAL) && !mWorkspace.isSwitchingState()) {
-                    mOverviewPanel.requestFocus();
-                    showOverviewMode(true, true /* requestButtonFocus */);
+                if (isInState(NORMAL) && !mWorkspace.isSwitchingState()) {
+                    mStateManager.goToState(OVERVIEW, true /* animate */, new Runnable() {
+                        @Override
+                        public void run() {
+                            // Hitting the menu button when in touch mode does not trigger touch
+                            // mode to be disabled, so if requested, force focus on one of the
+                            // overview panel buttons.
+                            mOverviewPanel.requestFocusFromTouch();
+                        }
+                    });
                 }
             }
             return true;
@@ -1025,15 +1027,11 @@
             return;
         }
 
-        int stateOrdinal = savedState.getInt(RUNTIME_STATE, LauncherState.NORMAL.ordinal);
+        int stateOrdinal = savedState.getInt(RUNTIME_STATE, NORMAL.ordinal);
         LauncherState[] stateValues = LauncherState.values();
         LauncherState state = stateValues[stateOrdinal];
         if (!state.doNotRestore) {
-            if (state == LauncherState.ALL_APPS) {
-                showAppsView(false /* animated */);
-            } else if (state == LauncherState.OVERVIEW) {
-                showOverviewMode(false);
-            }
+            mStateManager.goToState(state, false /* animated */);
         }
 
         PendingRequestArgs requestArgs = savedState.getParcelable(RUNTIME_STATE_PENDING_REQUEST_ARGS);
@@ -1311,10 +1309,7 @@
                 // Reset AllApps to its initial state only if we are not in the middle of
                 // processing a multi-step drop
                 if (mAppsView != null && mPendingRequestArgs == null) {
-                    if (!showWorkspace(false)) {
-                        // If we are already on the workspace, then manually reset all apps
-                        mAppsView.reset();
-                    }
+                    mStateManager.goToState(NORMAL);
                 }
                 mShouldFadeInScrim = true;
             } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
@@ -1414,7 +1409,7 @@
                 != Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
 
         // Check this condition before handling isActionMain, as this will get reset.
-        boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(LauncherState.NORMAL)
+        boolean shouldMoveToDefaultScreen = alreadyOnHome && isInState(NORMAL)
                 && AbstractFloatingView.getTopOpenView(this) == null;
 
         boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
@@ -1438,7 +1433,7 @@
 
             // In all these cases, only animate if we're already on home
             AbstractFloatingView.closeAllOpenViews(this, alreadyOnHome);
-            showWorkspace(alreadyOnHome /* animated */);
+            mStateManager.goToState(NORMAL, alreadyOnHome /* animated */);
 
             final View v = getWindow().peekDecorView();
             if (v != null && v.getWindowToken() != null) {
@@ -1615,7 +1610,7 @@
         }
 
         // We need to show the workspace after starting the search
-        showWorkspace(true);
+        mStateManager.goToState(NORMAL);
     }
 
     /**
@@ -1707,7 +1702,7 @@
                 @Override
                 public void run() {
                     // Exit spring loaded mode if necessary after adding the widget
-                    exitSpringLoadedDragMode(SPRING_LOADED_EXIT_DELAY);
+                    mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
                 }
             };
             completeAddAppWidget(appWidgetId, info, boundWidget, addFlowHandler.getProviderInfo(this));
@@ -1888,9 +1883,9 @@
         AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
         if (topView != null) {
             topView.onBackPressed();
-        } else if (!isInState(LauncherState.NORMAL)) {
+        } else if (!isInState(NORMAL)) {
             ued.logActionCommand(Action.Command.BACK, mWorkspace.getState().containerType);
-            showWorkspace(true);
+            mStateManager.goToState(NORMAL);
         } else {
             // Back button is a no-op here, but give at least some feedback for the button press
             mWorkspace.showOutlinesTemporarily();
@@ -1914,23 +1909,23 @@
         }
 
         if (v instanceof Workspace) {
-            if (isInState(LauncherState.OVERVIEW)) {
+            if (isInState(OVERVIEW)) {
                 getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Type.TOUCH,
                         LauncherLogProto.Action.Direction.NONE,
                         LauncherLogProto.ContainerType.OVERVIEW, mWorkspace.getCurrentPage());
-                showWorkspace(true);
+                mStateManager.goToState(NORMAL);
             }
             return;
         }
 
         if (v instanceof CellLayout) {
-            if (isInState(LauncherState.OVERVIEW)) {
+            if (isInState(OVERVIEW)) {
                 int page = mWorkspace.indexOfChild(v);
                 getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Type.TOUCH,
                         LauncherLogProto.Action.Direction.NONE,
                         LauncherLogProto.ContainerType.OVERVIEW, page);
                 mWorkspace.snapToPageFromOverView(page);
-                showWorkspace(true);
+                mStateManager.goToState(NORMAL);
             }
             return;
         }
@@ -2002,12 +1997,12 @@
      */
     protected void onClickAllAppsButton(View v) {
         if (LOGD) Log.d(TAG, "onClickAllAppsButton");
-        if (!isInState(LauncherState.ALL_APPS)) {
+        if (!isInState(ALL_APPS)) {
             getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
                     ControlType.ALL_APPS_BUTTON);
-            showAppsView(true /* animated */);
+            mStateManager.goToState(ALL_APPS);
         } else {
-            showWorkspace(true);
+            mStateManager.goToState(NORMAL);
         }
     }
 
@@ -2333,18 +2328,18 @@
     public boolean onLongClick(View v) {
         if (!isDraggingEnabled()) return false;
         if (isWorkspaceLocked()) return false;
-        if (!isInState(LauncherState.NORMAL) && !isInState(LauncherState.OVERVIEW)) return false;
+        if (!isInState(NORMAL) && !isInState(OVERVIEW)) return false;
 
         boolean ignoreLongPressToOverview =
                 mDeviceProfile.shouldIgnoreLongPressToOverview(mLastDispatchTouchEventX);
 
         if (v instanceof Workspace) {
-            if (!isInState(LauncherState.OVERVIEW)) {
+            if (!isInState(OVERVIEW)) {
                 if (!mWorkspace.isTouchActive() && !ignoreLongPressToOverview) {
                     getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
                             Action.Direction.NONE, ContainerType.WORKSPACE,
                             mWorkspace.getCurrentPage());
-                    showOverviewMode(true);
+                    getStateManager().goToState(OVERVIEW);
                     mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                             HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                     return true;
@@ -2381,7 +2376,7 @@
                     getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
                             Action.Direction.NONE, ContainerType.WORKSPACE,
                             mWorkspace.getCurrentPage());
-                    showOverviewMode(true);
+                    getStateManager().goToState(OVERVIEW);
                 }
                 mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                         HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
@@ -2436,134 +2431,16 @@
         }
     }
 
-    public boolean showWorkspace(boolean animated) {
-        return showWorkspace(animated, null);
-    }
-
-    public boolean showWorkspace(boolean animated, Runnable onCompleteRunnable) {
-        boolean changed = !isInState(LauncherState.NORMAL);
-        if (changed || mAllAppsController.isTransitioning()) {
-            mWorkspace.setVisibility(View.VISIBLE);
-            mStateTransitionAnimation.goToState(LauncherState.NORMAL, animated, onCompleteRunnable);
-
-            // Set focus to the AppsCustomize button
-            if (mAllAppsButton != null) {
-                mAllAppsButton.requestFocus();
-            }
-        }
-
-        if (changed) {
-            // Send an accessibility event to announce the context change
-            getWindow().getDecorView()
-                    .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-        }
-        return changed;
-    }
-
-    /**
-     * Shows the overview button.
-     */
-    public void showOverviewMode(boolean animated) {
-        showOverviewMode(animated, false);
-    }
-
-    /**
-     * Shows the overview button, and if {@param requestButtonFocus} is set, will force the focus
-     * onto one of the overview panel buttons.
-     */
-    void showOverviewMode(boolean animated, boolean requestButtonFocus) {
-        Runnable postAnimRunnable = null;
-        if (requestButtonFocus) {
-            postAnimRunnable = new Runnable() {
-                @Override
-                public void run() {
-                    // Hitting the menu button when in touch mode does not trigger touch mode to
-                    // be disabled, so if requested, force focus on one of the overview panel
-                    // buttons.
-                    mOverviewPanel.requestFocusFromTouch();
-                }
-            };
-        }
-        mWorkspace.setVisibility(View.VISIBLE);
-        mStateTransitionAnimation.goToState(LauncherState.OVERVIEW, animated, postAnimRunnable);
-
-        // If animated from long press, then don't allow any of the controller in the drag
-        // layer to intercept any remaining touch.
-        mWorkspace.requestDisallowInterceptTouchEvent(animated);
-    }
-
-    /**
-     * Shows the apps view.
-     *
-     * @return whether the current from and to state allowed this operation
-     */
-    // TODO: calling method should use the return value so that when {@code false} is returned
-    // the workspace transition doesn't fall into invalid state.
-    public boolean showAppsView(boolean animated) {
-        if (!(isInState(LauncherState.NORMAL) ||
-                (isInState(LauncherState.ALL_APPS) && mAllAppsController.isTransitioning()))) {
-            return false;
-        }
-
-        // This is a safe and supported transition to bypass spring_loaded mode.
-        if (mExitSpringLoadedModeRunnable != null) {
-            mHandler.removeCallbacks(mExitSpringLoadedModeRunnable);
-            mExitSpringLoadedModeRunnable = null;
-        }
-
-        mStateTransitionAnimation.goToState(LauncherState.ALL_APPS, animated, null);
-
-        // Change the state *after* we've called all the transition code
-        AbstractFloatingView.closeAllOpenViews(this);
-
-        // Send an accessibility event to announce the context change
-        getWindow().getDecorView()
-                .sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-        return true;
-    }
-
-    public void enterSpringLoadedDragMode() {
-        if (LOGD) Log.d(TAG, String.format("enterSpringLoadedDragMode [mState=%s",
-                mWorkspace.getState().ordinal));
-        if (isInState(LauncherState.SPRING_LOADED)) {
-            return;
-        }
-        mStateTransitionAnimation.goToState(LauncherState.SPRING_LOADED, true, null);
-    }
-
-    public void exitSpringLoadedDragMode(int delay) {
-        exitSpringLoadedDragMode(delay, null);
-    }
-
-    public void exitSpringLoadedDragMode(int delay, final Runnable onCompleteRunnable) {
-        if (!isInState(LauncherState.SPRING_LOADED)) return;
-
-        if (mExitSpringLoadedModeRunnable != null) {
-            mHandler.removeCallbacks(mExitSpringLoadedModeRunnable);
-        }
-        mExitSpringLoadedModeRunnable = new Runnable() {
-            @Override
-            public void run() {
-                showWorkspace(true, onCompleteRunnable);
-                mExitSpringLoadedModeRunnable = null;
-            }
-        };
-        mHandler.postDelayed(mExitSpringLoadedModeRunnable, delay);
-    }
-
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
         final boolean result = super.dispatchPopulateAccessibilityEvent(event);
         final List<CharSequence> text = event.getText();
         text.clear();
         // Populate event with a fake title based on the current state.
-        if (isInState(LauncherState.ALL_APPS)) {
-            text.add(getString(R.string.all_apps_button_label));
-        } else if (mWorkspace != null) {
-            text.add(mWorkspace.getCurrentPageDescription());
-        } else {
-            text.add(getString(R.string.all_apps_home_button_label));
-        }
+        // TODO: When can workspace be null?
+        text.add(mWorkspace == null
+                ? getString(R.string.all_apps_home_button_label)
+                : mWorkspace.getState().getDescription(this));
         return result;
     }
 
@@ -3114,7 +2991,7 @@
 
         if (mAppsView != null) {
             Executor pendingExecutor = getPendingExecutor();
-            if (pendingExecutor != null && !isInState(LauncherState.ALL_APPS)) {
+            if (pendingExecutor != null && !isInState(ALL_APPS)) {
                 // Wait until the fade in animation has finished before setting all apps list.
                 pendingExecutor.execute(r);
                 return;
@@ -3304,7 +3181,7 @@
     }
 
     private boolean shouldShowDiscoveryBounce() {
-        return isInState(LauncherState.NORMAL)
+        return isInState(NORMAL)
                 && !mSharedPrefs.getBoolean(AllAppsState.APPS_VIEW_SHOWN, false)
                 && !UserManagerCompat.getInstance(this).isDemoUser();
     }
@@ -3364,7 +3241,7 @@
             List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
 
         ArrayList<KeyboardShortcutInfo> shortcutInfos = new ArrayList<>();
-        if (isInState(LauncherState.NORMAL)) {
+        if (isInState(NORMAL)) {
             shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.all_apps_button_label),
                     KeyEvent.KEYCODE_A, KeyEvent.META_CTRL_ON));
         }
@@ -3390,8 +3267,8 @@
         if (event.hasModifiers(KeyEvent.META_CTRL_ON)) {
             switch (keyCode) {
                 case KeyEvent.KEYCODE_A:
-                    if (isInState(LauncherState.NORMAL)) {
-                        showAppsView(true);
+                    if (isInState(NORMAL)) {
+                        getStateManager().goToState(ALL_APPS);
                         return true;
                     }
                     break;