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);
}
}
}