diff options
author | Joe Onorato <joeo@android.com> | 2009-09-08 12:34:22 -0700 |
---|---|---|
committer | Joe Onorato <joeo@android.com> | 2009-09-11 12:14:19 -0400 |
commit | 85a02a8d13eced310aee4c2a795e9c9c5435038f (patch) | |
tree | c7fda8f70dadc9d1b4f85ba85d56e26b63408061 /src/com/android/launcher2 | |
parent | 8355ae39ad77b8e2e9ff3b4cbff8077a002ce151 (diff) | |
download | android_packages_apps_Trebuchet-85a02a8d13eced310aee4c2a795e9c9c5435038f.tar.gz android_packages_apps_Trebuchet-85a02a8d13eced310aee4c2a795e9c9c5435038f.tar.bz2 android_packages_apps_Trebuchet-85a02a8d13eced310aee4c2a795e9c9c5435038f.zip |
Add the animation for when you enter the all apps view.
Diffstat (limited to 'src/com/android/launcher2')
-rw-r--r-- | src/com/android/launcher2/AllAppsView.java | 31 | ||||
-rw-r--r-- | src/com/android/launcher2/DragLayer.java | 53 | ||||
-rw-r--r-- | src/com/android/launcher2/Launcher.java | 102 | ||||
-rw-r--r-- | src/com/android/launcher2/SwipeController.java | 222 | ||||
-rw-r--r-- | src/com/android/launcher2/Workspace.java | 57 |
5 files changed, 424 insertions, 41 deletions
diff --git a/src/com/android/launcher2/AllAppsView.java b/src/com/android/launcher2/AllAppsView.java index dcaaaa118..5128db332 100644 --- a/src/com/android/launcher2/AllAppsView.java +++ b/src/com/android/launcher2/AllAppsView.java @@ -66,6 +66,7 @@ public class AllAppsView extends RSSurfaceView private Launcher mLauncher; private DragController mDragController; + private boolean mLocked = true; private RenderScript mRS; private RolloRS mRollo; @@ -163,12 +164,16 @@ public class AllAppsView extends RSSurfaceView @Override public boolean onTouchEvent(MotionEvent ev) { - super.onTouchEvent(ev); - if (mRollo.mState.visible == 0) { - return false; + return true; } + if (mLocked) { + return true; + } + + super.onTouchEvent(ev); + mTouchHandler = mFlingHandler; /* int action = ev.getAction(); @@ -287,15 +292,31 @@ public class AllAppsView extends RSSurfaceView public void onDropCompleted(View target, boolean success) { } + private static final int SCALE_SCALE = 100000; + public void show() { mRollo.mState.read(); mRollo.mState.visible = 1; + mRollo.mState.zoom = SCALE_SCALE; + mRollo.mState.save(); + } + + public void setScale(float amount) { + mRollo.mState.read(); + if (amount > 0.001f) { + mRollo.mState.visible = 1; + mRollo.mState.zoom = (int)(SCALE_SCALE*amount); + } else { + mRollo.mState.visible = 0; + mRollo.mState.zoom = 0; + } mRollo.mState.save(); } - public void hide(boolean animate) { + public void hide() { mRollo.mState.read(); mRollo.mState.visible = 0; + mRollo.mState.zoom = 0; mRollo.mState.save(); } @@ -341,6 +362,7 @@ public class AllAppsView extends RSSurfaceView } mPageCount = countPages(list.size()); Log.d(TAG, "setApps mRollo=" + mRollo + " list=" + list); + mLocked = false; } private void invokeIcon(int index) { @@ -427,6 +449,7 @@ public class AllAppsView extends RSSurfaceView @AllocationIndex(9) public int selectedIconIndex = -1; @AllocationIndex(10) public int selectedIconTexture; @AllocationIndex(11) public int visible; + @AllocationIndex(12) public int zoom; } public RolloRS() { diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java index 28397119a..f038c2a5c 100644 --- a/src/com/android/launcher2/DragLayer.java +++ b/src/com/android/launcher2/DragLayer.java @@ -40,8 +40,17 @@ import android.widget.FrameLayout; * A ViewGroup that coordinated dragging across its dscendants */ public class DragLayer extends FrameLayout { + private static final String TAG = "Launcher.DragLayer"; + + private static final int DRAG = 1; + private static final int SWIPE = 2; + private static final int BOTH = DRAG | SWIPE; DragController mDragController; + SwipeController mSwipeController; + + private int mAllowed = BOTH; + /** * Used to create a new DragLayer from XML. @@ -57,6 +66,10 @@ public class DragLayer extends FrameLayout { mDragController = controller; } + public void setSwipeController(SwipeController controller) { + mSwipeController = controller; + } + @Override public boolean dispatchKeyEvent(KeyEvent event) { return mDragController.dispatchKeyEvent(event) || super.dispatchKeyEvent(event); @@ -64,11 +77,47 @@ public class DragLayer extends FrameLayout { @Override public boolean onInterceptTouchEvent(MotionEvent ev) { - return mDragController.onInterceptTouchEvent(ev); + boolean result = false; + + if (ev.getAction() == MotionEvent.ACTION_DOWN) { + mAllowed = BOTH; + } + + if ((mAllowed & DRAG) != 0) { + result = mDragController.onInterceptTouchEvent(ev); + if (result) { + mAllowed = DRAG; + } + } + + if ((mAllowed & SWIPE) != 0) { + result = mSwipeController.onInterceptTouchEvent(ev); + if (result) { + mAllowed = SWIPE; + } + } + + return result; } @Override public boolean onTouchEvent(MotionEvent ev) { - return mDragController.onTouchEvent(ev); + boolean result = false; + + if ((mAllowed & DRAG) != 0) { + result = mDragController.onTouchEvent(ev); + if (result) { + mAllowed = DRAG; + } + } + + if ((mAllowed & SWIPE) != 0) { + result = mSwipeController.onTouchEvent(ev); + if (result) { + mAllowed = SWIPE; + } + } + + return result; } } diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index b53fee26c..86914b0cd 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -82,7 +82,8 @@ import java.io.DataInputStream; * Default launcher application. */ public final class Launcher extends Activity - implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks { + implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, + SwipeController.SwipeListener { static final String LOG_TAG = "Launcher"; static final String TAG = LOG_TAG; static final boolean LOGD = false; @@ -108,6 +109,10 @@ public final class Launcher extends Activity private static final int REQUEST_PICK_LIVE_FOLDER = 8; private static final int REQUEST_PICK_APPWIDGET = 9; + private static final int MODE_WORKSPACE = 0; + private static final int MODE_ALL_APPS = 1; + private static final int MODE_ALL_APPS_ZOOMED = 2; + static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate"; static final String EXTRA_CUSTOM_WIDGET = "custom_widget"; @@ -158,6 +163,7 @@ public final class Launcher extends Activity private LayoutInflater mInflater; private DragController mDragController; + private SwipeController mSwipeController; private Workspace mWorkspace; private AppWidgetManager mAppWidgetManager; @@ -171,7 +177,8 @@ public final class Launcher extends Activity private DeleteZone mDeleteZone; private HandleView mHandleView; private AllAppsView mAllAppsGrid; - private boolean mAllAppsVisible; + private boolean mAllAppsVisible; // if it's visible at all + private int mMode = MODE_WORKSPACE; private Bundle mSavedState; @@ -515,13 +522,18 @@ public final class Launcher extends Activity private void setupViews() { mDragController = new DragController(this); DragController dragController = mDragController; + mSwipeController = new SwipeController(this, this); + SwipeController swipeController = mSwipeController; + swipeController.setRange(-1, 0); DragLayer dragLayer = (DragLayer) findViewById(R.id.drag_layer); dragLayer.setDragController(dragController); + dragLayer.setSwipeController(swipeController); mAllAppsGrid = (AllAppsView)dragLayer.findViewById(R.id.all_apps_view); mAllAppsGrid.setLauncher(this); mAllAppsGrid.setDragController(dragController); + mAllAppsGrid.setWillNotDraw(false); // We don't want a hole punched in our window. mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace); final Workspace workspace = mWorkspace; @@ -1422,6 +1434,7 @@ public final class Launcher extends Activity } if (mWorkspace.allowLongPress()) { + mSwipeController.cancelSwipe(); if (cellInfo.cell == null) { if (cellInfo.valid) { // User long pressed on empty space @@ -1607,7 +1620,7 @@ public final class Launcher extends Activity void closeAllAppsDialog(boolean animated) { if (mAllAppsVisible) { Log.d(LOG_TAG, "closing all apps"); - mAllAppsGrid.hide(animated); + mAllAppsGrid.hide(); mAllAppsVisible = false; mWorkspace.getChildAt(mWorkspace.getCurrentScreen()).requestFocus(); mWorkspace.show(); @@ -1744,6 +1757,89 @@ public final class Launcher extends Activity } /** + * Implementation of the method from SwipeController.SwipeListener. + */ + public void onStartSwipe() { + switch (mMode) { + case MODE_WORKSPACE: + mWorkspace.enableChildrenCache(); + break; + case MODE_ALL_APPS: + break; + case MODE_ALL_APPS_ZOOMED: + break; + } + } + + /** + * Implementation of the method from SwipeController.SwipeListener. + * + * @param amount The final value of the swipe (-1, 0 or 1) + */ + public void onFinishSwipe(int amount) { + switch (mMode) { + case MODE_WORKSPACE: + if (amount == -1) { + mWorkspace.clearChildrenCache(); + mMode = MODE_ALL_APPS; + mSwipeController.setRange(0, 1); + } + break; + case MODE_ALL_APPS: + if (amount == 1) { + mWorkspace.clearChildrenCache(); + mMode = MODE_WORKSPACE; + mSwipeController.setRange(-1, 0); + } + break; + case MODE_ALL_APPS_ZOOMED: + break; + } + } + + /** + * Implementation of the method from SwipeController.SwipeListener. + */ + public void onSwipe(float amount) { + switch (mMode) { + case MODE_WORKSPACE: + // We can open the all apps view. + // 0 == workspace is showing + // -1 == all apps is showing + setWorkspaceAndAllAppsScale(-amount); + break; + case MODE_ALL_APPS: + // We can close it, or (someday) zoom it further + // 0 == all apps showing + // 1 == workspace is showing + setWorkspaceAndAllAppsScale(1-amount); + break; + } + } + + /** + * Set the scale factor for the workspace and the all apps grid. + * + * @param amount A float between 0 and 1, where: + * 0 == workspace is showing and + * 1 == the all apps grid is showing. + */ + private void setWorkspaceAndAllAppsScale(float amount) { + //Log.d("setWorkspaceAndAllAppsScale", "setWorkspaceAndAllAppsScale amount=" + amount); + if (amount < 0.001f) { + amount = 0.0f; + } + if (amount > 0.999f) { + amount = 1.0f; + mWorkspace.setVisibility(View.INVISIBLE); + } else { + mWorkspace.setVisibility(View.VISIBLE); + } + mWorkspace.setScale(1-amount); + mAllAppsGrid.setScale(amount); + } + + /** * Implementation of the method from LauncherModel.Callbacks. */ public int getCurrentWorkspaceScreen() { diff --git a/src/com/android/launcher2/SwipeController.java b/src/com/android/launcher2/SwipeController.java new file mode 100644 index 000000000..7443b3bbc --- /dev/null +++ b/src/com/android/launcher2/SwipeController.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher2; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.util.Log; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.ViewConfiguration; + +import java.util.ArrayList; + +public class SwipeController { + private static final String TAG = "Launcher.SwipeController"; + + private static final int FRAME_DELAY = 1000 / 30; + private static final float DECAY_CONSTANT = 0.65f; + private static final float SPRING_CONSTANT = 0.0009f; + + // configuration + private SwipeListener mListener; + private int mSlop; + private float mSwipeDistance; + + // state + private VelocityTracker mVelocityTracker; + private boolean mCanceled; + private boolean mTracking; + private int mDownX; + private int mDownY; + + private float mMinDest; + private float mMaxDest; + private long mFlingTime; + private long mLastTime; + private int mDirection; + private float mVelocity; + private float mDest; + private float mAmount; + + public interface SwipeListener { + public void onStartSwipe(); + public void onFinishSwipe(int amount); + public void onSwipe(float amount); + } + + public SwipeController(Context context, SwipeListener listener) { + ViewConfiguration config = ViewConfiguration.get(context); + mSlop = config.getScaledTouchSlop(); + + DisplayMetrics display = context.getResources().getDisplayMetrics(); + mSwipeDistance = display.heightPixels / 2; // one half of the screen + + mListener = listener; + } + + public void setRange(float min, float max) { + mMinDest = min; + mMaxDest = max; + } + + public void cancelSwipe() { + mCanceled = true; + } + + public boolean onInterceptTouchEvent(MotionEvent ev) { + onTouchEvent(ev); + + // After we return true, onIntercept doesn't get called any more, so this is + // a good place to do the callback. + if (mTracking) { + mListener.onStartSwipe(); + } + + return mTracking; + } + + public boolean onTouchEvent(MotionEvent ev) { + if (mVelocityTracker == null) { + mVelocityTracker = VelocityTracker.obtain(); + } + mVelocityTracker.addMovement(ev); + + final int screenX = (int)ev.getRawX(); + final int screenY = (int)ev.getRawY(); + + final int deltaX = screenX - mDownX; + final int deltaY = screenY - mDownY; + + final int action = ev.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + // Remember location of down touch + mCanceled = false; + mTracking = false; + mDownX = screenX; + mDownY = screenY; + break; + + case MotionEvent.ACTION_MOVE: + if (!mCanceled && !mTracking) { + if (Math.abs(deltaX) > mSlop) { + mCanceled = true; + mTracking = false; + } + if (Math.abs(deltaY) > mSlop) { + mTracking = true; + } + } + if (mTracking && !mCanceled) { + track(screenY); + } + break; + + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + if (mTracking && !mCanceled) { + fling(screenY); + } + mVelocityTracker.recycle(); + mVelocityTracker = null; + break; + } + + return mTracking || mCanceled; + } + + private float clamp(float v) { + if (v < mMinDest) { + return mMinDest; + } else if (v > mMaxDest) { + return mMaxDest; + } else { + return v; + } + } + + /** + * Perform the callbacks. + */ + private void track(int screenY) { + mAmount = clamp((screenY - mDownY) / mSwipeDistance); + mListener.onSwipe(mAmount); + } + + private void fling(int screenY) { + mVelocityTracker.computeCurrentVelocity(1); + + mVelocity = mVelocityTracker.getYVelocity() / mSwipeDistance; + mDirection = mVelocity >= 0.0f ? 1 : -1; + mAmount = clamp((screenY-mDownY)/mSwipeDistance); + if (mAmount < 0) { + mDest = clamp(mVelocity < 0 ? -1.0f : 0.0f); + } else { + mDest = clamp(mVelocity < 0 ? 0.0f : 1.0f); + } + + mFlingTime = SystemClock.uptimeMillis(); + mLastTime = 0; + + scheduleAnim(); + } + + private void scheduleAnim() { + boolean send = true; + if (mDirection > 0) { + if (mAmount > (mDest - 0.01f)) { + send = false; + } + } else { + if (mAmount < (mDest + 0.01f)) { + send = false; + } + } + if (send) { + mHandler.sendEmptyMessageDelayed(1, FRAME_DELAY); + } else { + mListener.onFinishSwipe((int)(mAmount >= 0 ? (mAmount+0.5f) : (mAmount-0.5f))); + } + } + + Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + long now = SystemClock.uptimeMillis(); + + final long t = now - mFlingTime; + final long dt = t - mLastTime; + mLastTime = t; + final float timeSlices = dt / (float)FRAME_DELAY; + + float distance = mDest - mAmount; + + mVelocity += timeSlices * mDirection * SPRING_CONSTANT * distance * distance / 2; + mVelocity *= (timeSlices * DECAY_CONSTANT); + + mAmount += timeSlices * mVelocity; + mAmount += distance * timeSlices * 0.2f; // cheat + + mListener.onSwipe(mAmount); + scheduleAnim(); + } + }; +} + diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 744cf720f..14b77f037 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -46,8 +46,9 @@ import java.util.ArrayList; * screen contains a number of icons, folders or widgets the user can interact with. * A workspace is meant to be used with a fixed width only. */ -public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller, - TweenCallback { +public class Workspace extends ViewGroup implements DropTarget, DragSource, DragScroller { + private static final String TAG = "Launcher.Workspace"; + private static final int INVALID_SCREEN = -1; /** @@ -66,9 +67,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private Scroller mScroller; private VelocityTracker mVelocityTracker; - private SymmetricalLinearTween mTween; - private int mAlpha = 255; - /** * CellInfo for the cell that is currently being dragged */ @@ -150,8 +148,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag final ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); - - mTween = new SymmetricalLinearTween(true, 250/*ms*/, this); } @Override @@ -486,12 +482,24 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag int restoreCount = 0; // For the fade. If view gets setAlpha(), use that instead. - int alpha = mAlpha; - if (alpha < 255) { + float scale = mScale; + if (scale < 0.999f) { int sx = mScrollX; + + int alpha = (scale < 0.5f) ? (int)(255 * 2 * scale) : 255; + restoreCount = canvas.saveLayerAlpha(sx, 0, sx+getWidth(), getHeight(), alpha, Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); restore = true; + + if (scale < 0.999f) { + int w = getWidth(); + w += 2 * mCurrentScreen * w; + int h = getHeight(); + canvas.translate(w/2, h/2); + canvas.scale(scale, scale); + canvas.translate(-w/2, -h/2); + } } // ViewGroup.dispatchDraw() supports many features we don't need: @@ -499,7 +507,8 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag // children, etc. The following implementation attempts to fast-track // the drawing dispatch by drawing only what we know needs to be drawn. - boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN; + boolean fastDraw = mTouchState != TOUCH_STATE_SCROLLING && mNextScreen == INVALID_SCREEN + && scale > 0.999f; // If we are not scrolling or flinging, draw only the current screen if (fastDraw) { drawChild(canvas, getChildAt(mCurrentScreen), getDrawingTime()); @@ -524,6 +533,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } } + private float mScale = 1.0f; + public void setScale(float scale) { + mScale = scale; + invalidate(); + } + protected void onAttachedToWindow() { super.onAttachedToWindow(); mDragController.setWindowToken(getWindowToken()); @@ -1335,31 +1350,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } void show() { - mTween.start(true); setVisibility(VISIBLE); } void hide() { - mTween.start(false); - } - - public void onTweenValueChanged(float value, float oldValue) { - mAlpha = (int)(255*value); - invalidate(); - } - - public void onTweenStarted() { - // TODO: This conflicts with the cache for drawing. Ref count instead? - // TODO: Don't cache all three. - enableChildrenCache(); - } - - public void onTweenFinished() { - // TODO: This conflicts with the cache for drawing. Ref count instead? - // TODO: Don't cache all three. - clearChildrenCache(); - if (mAlpha == 0) { - setVisibility(GONE); - } } } |