Add a market button and add toolbar button animations.
Also clean up a lot of the animation code to be more centralized.
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index ee70b5e..cb627dd 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -103,14 +103,6 @@
import java.util.HashMap;
import java.util.List;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
/**
* Default launcher application.
*/
@@ -187,6 +179,9 @@
private static final String SHORTCUTS_TAG = "shortcuts";
private static final String WALLPAPERS_TAG = "wallpapers";
+ /** The different states that Launcher can be in. */
+ private enum State { WORKSPACE, ALL_APPS, CUSTOMIZE, OVERVIEW };
+
static final int APPWIDGET_HOST_ID = 1024;
private static final Object sLock = new Object();
@@ -1147,7 +1142,7 @@
mWorkspace.moveToDefaultScreen(alreadyOnHome && !allAppsVisible);
}
closeAllApps(alreadyOnHome && allAppsVisible);
- hideCustomizationDrawer();
+ hideCustomizationDrawer(alreadyOnHome);
final View v = getWindow().peekDecorView();
if (v != null && v.getWindowToken() != null) {
@@ -1381,8 +1376,7 @@
if (LauncherApplication.isScreenXLarge()) {
// Animate the widget chooser up from the bottom of the screen
if (!isCustomizationDrawerVisible()) {
- showCustomizationDrawer();
- mWorkspace.shrinkToTop();
+ showCustomizationDrawer(true);
}
} else {
closeAllApps(true);
@@ -1622,7 +1616,7 @@
if (isAllAppsVisible()) {
closeAllApps(true);
} else if (isCustomizationDrawerVisible()) {
- hideCustomizationDrawer();
+ hideCustomizationDrawer(true);
} else {
closeFolder();
}
@@ -1699,7 +1693,7 @@
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();
+ hideCustomizationDrawer(true);
return false;
}
@@ -2176,35 +2170,122 @@
mWorkspace.setVisibility(View.GONE);
}
}
+
+ /**
+ * Helper function for creating a show or hide animations for a toolbar button.
+ *
+ * @param show If true, create an animation to the show the item. Otherwise, hide it.
+ * @param view The toolbar button to be animated
+ * @return An Animatable that will perform the show or hide action
+ */
+ private Animatable getToolbarButtonAnim(boolean show, final View view) {
+ final boolean showing = show;
+ final boolean hiding = !show;
+
+ final int duration = show ?
+ getResources().getInteger(R.integer.config_toolbarButtonFadeInTime) :
+ getResources().getInteger(R.integer.config_toolbarButtonFadeOutTime);
+
+ Animatable anim = new PropertyAnimator<Float>(duration, view, "alpha", show ? 1.0f : 0.0f);
+ anim.addListener(new AnimatableListenerAdapter() {
+ public void onAnimationStart(Animatable animation) {
+ if (showing) {
+ view.setVisibility(View.VISIBLE);
+ view.setFocusable(true);
+ view.setClickable(true);
+ }
+ }
+ public void onAnimationEnd(Animatable animation) {
+ if (hiding) {
+ // We can't set it to GONE, otherwise the RelativeLayout gets screwed up
+ view.setVisibility(View.INVISIBLE);
+ view.setFocusable(false);
+ view.setClickable(false);
+ }
+ }
+ });
+ return anim;
+ }
+
+ /**
+ * Create the animations to show/hide the appropriate toolbar buttons for the new state.
+ *
+ * @param newState The state that is being switched to
+ * @param showSeq Sequencer in which to put "show" animations
+ * @param hideSeq Sequencer in which to put "hide" animations
+ */
+ private void getToolbarButtonAnimations(State newState, Sequencer showSeq, Sequencer hideSeq) {
+ final View searchButton = findViewById(R.id.search_button);
+ final View allAppsButton = findViewById(R.id.all_apps_button);
+ final View marketButton = findViewById(R.id.market_button);
+ final View configureButton = findViewById(R.id.configure_button);
+
+ switch (newState) {
+ case WORKSPACE:
+ showSeq.playTogether(new Animatable[] {
+ getToolbarButtonAnim(true, searchButton),
+ getToolbarButtonAnim(true, allAppsButton),
+ getToolbarButtonAnim(true, configureButton)
+ });
+ hideSeq.play(getToolbarButtonAnim(false, marketButton));
+ break;
+ case ALL_APPS:
+ // TODO: Market button should also be shown
+ showSeq.play(getToolbarButtonAnim(true, configureButton))
+ .with(getToolbarButtonAnim(true, marketButton));
+ hideSeq.play(getToolbarButtonAnim(false, searchButton))
+ .with(getToolbarButtonAnim(false, allAppsButton));
+ break;
+ case CUSTOMIZE:
+ showSeq.play(getToolbarButtonAnim(true, allAppsButton));
+ hideSeq.playTogether(new Animatable[] {
+ getToolbarButtonAnim(false, searchButton),
+ getToolbarButtonAnim(false, marketButton),
+ getToolbarButtonAnim(false, configureButton)
+ });
+ break;
+ }
+ }
+
+ /**
+ * Helper method for the cameraZoomIn/cameraZoomOut animations
+ * @param view The view being animated
+ * @param state The state that we are moving in or out of -- either ALL_APPS or CUSTOMIZE
+ * @param scaleFactor The scale factor used for the zoom
+ */
+ private void setPivotsForZoom(View view, State state, float scaleFactor) {
+ final int height = view.getHeight();
+ view.setPivotX(view.getWidth() / 2.0f);
+ // Set pivotY so that at the starting zoom factor, the view is off-screen by a small margin
+ // Assumes that the view is normally anchored to either the top or bottom of the screen
+ final int margin = getResources().getInteger(R.integer.config_allAppsVerticalOffset);
+ if (state == State.ALL_APPS) {
+ view.setPivotY(height + ((view.getTop() + height) / scaleFactor) + margin);
+ } else {
+ view.setPivotY(0.0f - (view.getTop() / scaleFactor) - margin);
+ }
+ }
/**
* Zoom the camera out from the workspace to reveal 'toView'.
* Assumes that the view to show is anchored at either the very top or very bottom
* of the screen.
- * @param toView The view to show when the animation is complete
- * @param above If true, toView will appear from the top of the screen
+ * @param toState The state to zoom out to. Must be ALL_APPS or CUSTOMIZE.
*/
- private void cameraZoomOut(final View toView, boolean above) {
+ private void cameraZoomOut(State toState, final boolean animated) {
final Resources res = getResources();
final int duration = res.getInteger(R.integer.config_allAppsZoomInTime);
final float scale = (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor);
+ final boolean toAllApps = (toState == State.ALL_APPS);
+ final View toView = toAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
final int height = toView.getHeight();
// toView should appear right at the end of the workspace shrink animation
final int startDelay = res.getInteger(R.integer.config_workspaceShrinkTime) - duration;
+ setPivotsForZoom(toView, toState, scale);
+
Interpolator interp = new DecelerateInterpolator();
-
- toView.setPivotX(toView.getWidth() / 2.0f);
- // Set pivotY so that at the starting zoom factor, the view is off-screen by a small margin
- // Assumes that the view is normally anchored to either the top or bottom of the screen
- final int margin = 200;
- if (above) {
- toView.setPivotY(height + ((toView.getTop() + height) / scale) + margin);
- } else {
- toView.setPivotY(0.0f - (toView.getTop() / scale) - margin);
- }
-
Animator scaleXAnim = new PropertyAnimator(duration, toView, "scaleX", scale, 1.0f);
scaleXAnim.setInterpolator(interp);
scaleXAnim.addListener(new AnimatableListenerAdapter() {
@@ -2213,27 +2294,48 @@
toView.setTranslationX(0.0f);
toView.setTranslationY(0.0f);
toView.setVisibility(View.VISIBLE);
+
+ if (!animated) animation.end(); // Go immediately to the final state
}
});
Animator scaleYAnim = new PropertyAnimator(duration, toView, "scaleY", scale, 1.0f);
scaleYAnim.setInterpolator(interp);
+ Sequencer toolbarHideAnim = new Sequencer();
+ Sequencer toolbarShowAnim = new Sequencer();
+ getToolbarButtonAnimations(toState, toolbarShowAnim, toolbarHideAnim);
+
Sequencer s = new Sequencer();
- s.playTogether(scaleXAnim, scaleYAnim);
+ s.playTogether(scaleXAnim, scaleYAnim, toolbarHideAnim);
s.play(scaleXAnim).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);
+
+ if (toState == State.ALL_APPS) {
+ mWorkspace.shrinkToBottom(animated);
+ } else {
+ mWorkspace.shrinkToTop(animated);
+ }
s.start();
}
/**
* Zoom the camera back into the workspace, hiding 'fromView'.
* This is the opposite of cameraZoomOut.
- * @param fromView The currently-focused view, which will be hidden.
+ * @param fromState The current state (must be ALL_APPS or CUSTOMIZE).
+ * @param animated If true, the transition will be animated.
*/
- private void cameraZoomIn(final View fromView) {
+ private void cameraZoomIn(State fromState, final boolean animated) {
Resources res = getResources();
int duration = res.getInteger(R.integer.config_allAppsZoomOutTime);
float scaleFactor = (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor);
+ final View fromView =
+ (fromState == State.ALL_APPS) ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+
+ setPivotsForZoom(fromView, fromState, scaleFactor);
Interpolator interp = new AccelerateInterpolator();
@@ -2242,14 +2344,30 @@
scaleXAnim.setInterpolator(interp);
Animator scaleYAnim = new PropertyAnimator(duration, fromView, "scaleY", scaleFactor);
scaleYAnim.setInterpolator(interp);
- s.playTogether(scaleXAnim, scaleYAnim);
s.addListener(new AnimatableListenerAdapter() {
+ public void onAnimationStart(Animatable animation) {
+ if (!animated) animation.end(); // Go immediately to the final state
+ }
+
public void onAnimationEnd(Animatable animation) {
fromView.setVisibility(View.GONE);
fromView.setScaleX(1.0f);
fromView.setScaleY(1.0f);
}
});
+
+ Sequencer toolbarHideAnim = new Sequencer();
+ Sequencer toolbarShowAnim = new Sequencer();
+ getToolbarButtonAnimations(State.WORKSPACE, toolbarShowAnim, toolbarHideAnim);
+
+ s.playTogether(scaleXAnim, scaleYAnim, 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);
+
+ mWorkspace.unshrink(animated);
s.start();
}
@@ -2257,34 +2375,57 @@
* Pan the camera in the vertical plane between 'fromView' and 'toView'.
* This is the transition used on xlarge screens to go between all apps and
* the home customization drawer.
- * @param fromView The view to pan away from.
- * @param toView The view to pan into the frame.
+ * @param fromState The view to pan away from. Must be ALL_APPS or CUSTOMIZE.
+ * @param toState The view to pan into the frame. Must be ALL_APPS or CUSTOMIZE.
+ * @param animated If true, the transition will be animated.
*/
- private void cameraPan(final View fromView, final View toView) {
- final int duration = getResources().getInteger(R.integer.config_allAppsCameraPanTime);
+ private void cameraPan(State fromState, State toState, final boolean animated) {
+ final Resources res = getResources();
+ final int duration = res.getInteger(R.integer.config_allAppsCameraPanTime);
final int workspaceHeight = mWorkspace.getHeight();
- final boolean panDown = fromView.getY() < toView.getY();
+ final boolean fromAllApps = (fromState == State.ALL_APPS);
+ final View fromView = fromAllApps ? (View) mAllAppsGrid : mHomeCustomizationDrawer;
+ final View toView = fromAllApps ? mHomeCustomizationDrawer : (View) mAllAppsGrid;
- final float fromViewStartY = panDown ? 0.0f : fromView.getY();
- final float fromViewEndY = panDown ? -fromView.getHeight() * 2 : workspaceHeight * 2;
- final float toViewStartY = panDown ? workspaceHeight * 2 : -toView.getHeight() * 2;
- final float toViewEndY = panDown ? workspaceHeight - toView.getHeight() : 0.0f;
+ final float fromViewStartY = fromAllApps ? 0.0f : fromView.getY();
+ final float fromViewEndY = fromAllApps ? -fromView.getHeight() * 2 : workspaceHeight * 2;
+ final float toViewStartY = fromAllApps ? workspaceHeight * 2 : -toView.getHeight() * 2;
+ final float toViewEndY = fromAllApps ? workspaceHeight - toView.getHeight() : 0.0f;
Sequencer s = new Sequencer();
- s.playTogether(
- new PropertyAnimator(duration, fromView, "y", fromViewStartY, fromViewEndY),
- new PropertyAnimator(duration, toView, "y", toViewStartY, toViewEndY));
s.addListener(new AnimatableListenerAdapter() {
public void onAnimationStart(Animatable animation) {
toView.setVisibility(View.VISIBLE);
toView.setY(toViewStartY);
+
+ if (!animated) animation.end(); // Go immediately to the final state
}
public void onAnimationEnd(Animatable animation) {
fromView.setVisibility(View.GONE);
}
});
+
+ Sequencer toolbarHideAnim = new Sequencer();
+ Sequencer toolbarShowAnim = new Sequencer();
+ getToolbarButtonAnimations(toState, toolbarShowAnim, toolbarHideAnim);
+
+ s.playTogether(
+ toolbarHideAnim,
+ new PropertyAnimator(duration, fromView, "y", fromViewStartY, fromViewEndY),
+ new PropertyAnimator(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);
+
+ if (toState == State.ALL_APPS) {
+ mWorkspace.shrinkToBottom(animated);
+ } else {
+ mWorkspace.shrinkToTop(animated);
+ }
s.start();
+ if (!animated) s.end(); // Go immediately to the final state
}
void showAllApps(boolean animated) {
@@ -2292,18 +2433,13 @@
return;
if (LauncherApplication.isScreenXLarge()) {
- mWorkspace.shrinkToBottom(animated);
- }
-
- if (LauncherApplication.isScreenXLarge() && animated) {
if (isCustomizationDrawerVisible()) {
- cameraPan(mHomeCustomizationDrawer, (View) mAllAppsGrid);
+ cameraPan(State.CUSTOMIZE, State.ALL_APPS, animated);
} else {
- cameraZoomOut((View) mAllAppsGrid, true);
+ cameraZoomOut(State.ALL_APPS, animated);
}
} else {
mAllAppsGrid.zoom(1.0f, animated);
- hideCustomizationDrawer(); // TODO: Should be able to do this un-animated
}
((View) mAllAppsGrid).setFocusable(true);
@@ -2356,8 +2492,7 @@
if (mAllAppsGrid.isVisible()) {
mWorkspace.setVisibility(View.VISIBLE);
if (LauncherApplication.isScreenXLarge() && animated) {
- mWorkspace.unshrink();
- cameraZoomIn((View) mAllAppsGrid);
+ cameraZoomIn(State.ALL_APPS, animated);
} else {
mAllAppsGrid.zoom(0.0f, animated);
}
@@ -2379,34 +2514,29 @@
mHomeCustomizationDrawer.getVisibility() == View.VISIBLE;
}
- private void showCustomizationDrawer() {
- mWorkspace.shrinkToTop();
+ // Show the customization drawer (only exists in x-large configuration)
+ private void showCustomizationDrawer(boolean animated) {
if (isAllAppsVisible()) {
- cameraPan((View) mAllAppsGrid, mHomeCustomizationDrawer);
+ cameraPan(State.ALL_APPS, State.CUSTOMIZE, animated);
} else {
- cameraZoomOut(mHomeCustomizationDrawer, false);
+ cameraZoomOut(State.CUSTOMIZE, animated);
}
}
- void hideCustomizationDrawer() {
- hideCustomizationDrawer(true);
- }
-
- void hideCustomizationDrawer(boolean unshrinkWorkspace) {
+ // Hide the customization drawer (only exists in x-large configuration)
+ void hideCustomizationDrawer(boolean animated) {
if (isCustomizationDrawerVisible()) {
- if (unshrinkWorkspace) {
- mWorkspace.unshrink();
- }
- cameraZoomIn(mHomeCustomizationDrawer);
+ cameraZoomIn(State.CUSTOMIZE, animated);
}
}
void onWorkspaceUnshrink() {
+ final boolean animated = true;
if (isAllAppsVisible()) {
- closeAllApps(true);
+ closeAllApps(animated);
}
if (isCustomizationDrawerVisible()) {
- hideCustomizationDrawer();
+ hideCustomizationDrawer(animated);
}
}
@@ -2527,8 +2657,7 @@
animate = false;
}
closeAllApps(animate);
- mWorkspace.unshrink(animate);
- hideCustomizationDrawer();
+ hideCustomizationDrawer(animate);
}
}
}