summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Jurka <mikejurka@google.com>2010-11-23 16:23:58 -0800
committerMichael Jurka <mikejurka@google.com>2010-12-09 02:12:19 -0800
commitd3ef3065ab0941567c45e9aec98783138b623c68 (patch)
treebe6aeb8f76931cc504a8723824920e60d292b116 /src
parent120980bd00f5eecec5717f49a3d7db96571025a9 (diff)
downloadandroid_packages_apps_Trebuchet-d3ef3065ab0941567c45e9aec98783138b623c68.tar.gz
android_packages_apps_Trebuchet-d3ef3065ab0941567c45e9aec98783138b623c68.tar.bz2
android_packages_apps_Trebuchet-d3ef3065ab0941567c45e9aec98783138b623c68.zip
added spring loaded mode for adding items to workspace
Change-Id: Ie92294fe2b1d6697d84756a2fcea91a09f72825b
Diffstat (limited to 'src')
-rw-r--r--src/com/android/launcher2/Alarm.java76
-rw-r--r--src/com/android/launcher2/AllAppsPagedView.java14
-rw-r--r--src/com/android/launcher2/CellLayout.java10
-rw-r--r--src/com/android/launcher2/CustomizePagedView.java38
-rw-r--r--src/com/android/launcher2/Launcher.java74
-rw-r--r--src/com/android/launcher2/PagedView.java63
-rw-r--r--src/com/android/launcher2/SpringLoadedDragController.java58
-rw-r--r--src/com/android/launcher2/Workspace.java152
8 files changed, 409 insertions, 76 deletions
diff --git a/src/com/android/launcher2/Alarm.java b/src/com/android/launcher2/Alarm.java
new file mode 100644
index 000000000..38ff36733
--- /dev/null
+++ b/src/com/android/launcher2/Alarm.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2010 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.os.Handler;
+
+public class Alarm implements Runnable{
+ // if we reach this time and the alarm hasn't been cancelled, call the listener
+ private long mAlarmTriggerTime;
+
+ // if we've scheduled a call to run() (ie called mHandler.postDelayed), this variable is true.
+ // We use this to avoid having multiple pending callbacks
+ private boolean mWaitingForCallback;
+
+ private Handler mHandler;
+ private OnAlarmListener mAlarmListener;
+
+ public Alarm() {
+ mHandler = new Handler();
+ }
+
+ public void setOnAlarmListener(OnAlarmListener alarmListener) {
+ mAlarmListener = alarmListener;
+ }
+
+ // Sets the alarm to go off in a certain number of milliseconds. If the alarm is already set,
+ // it's overwritten and only the new alarm setting is used
+ public void setAlarm(long millisecondsInFuture) {
+ long currentTime = System.currentTimeMillis();
+ mAlarmTriggerTime = currentTime + millisecondsInFuture;
+ if (!mWaitingForCallback) {
+ mHandler.postDelayed(this, mAlarmTriggerTime - currentTime);
+ mWaitingForCallback = true;
+ }
+ }
+
+ public void cancelAlarm() {
+ mAlarmTriggerTime = 0;
+ }
+
+ // this is called when our timer runs out
+ public void run() {
+ mWaitingForCallback = false;
+ if (mAlarmTriggerTime != 0) {
+ long currentTime = System.currentTimeMillis();
+ if (mAlarmTriggerTime > currentTime) {
+ // We still need to wait some time to trigger spring loaded mode--
+ // post a new callback
+ mHandler.postDelayed(this, Math.max(0, mAlarmTriggerTime - currentTime));
+ mWaitingForCallback = true;
+ } else {
+ if (mAlarmListener != null) {
+ mAlarmListener.onAlarm(this);
+ }
+ }
+ }
+ }
+}
+
+interface OnAlarmListener {
+ public void onAlarm(Alarm alarm);
+}
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 8d4ddba7f..2fd0b6569 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -21,7 +21,11 @@ import com.android.launcher.R;
import android.content.ComponentName;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.AnimationUtils;
@@ -258,8 +262,14 @@ public class AllAppsPagedView extends PagedView
ApplicationInfo app = (ApplicationInfo) v.getTag();
app = new ApplicationInfo(app);
- mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1);
- mDragController.startDrag(v, this, app, DragController.DRAG_ACTION_COPY);
+ // get icon (top compound drawable, index is 1)
+ final Drawable icon = ((TextView) v).getCompoundDrawables()[1];
+ Bitmap b = Bitmap.createBitmap(icon.getIntrinsicWidth(), icon.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(b);
+ icon.draw(c);
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
+ mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, null);
return true;
}
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index 8fe489dff..a104c554f 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -801,7 +801,10 @@ public class CellLayout extends ViewGroup implements Dimmable {
cellXY[0] + childLeft + lp.width / 2,
cellXY[1] + childTop + lp.height / 2, 0, null);
- ((Workspace) mParent).animateViewIntoPosition(child);
+ if (lp.animateDrop) {
+ lp.animateDrop = false;
+ ((Workspace) mParent).animateViewIntoPosition(child);
+ }
}
}
}
@@ -1224,11 +1227,12 @@ public class CellLayout extends ViewGroup implements Dimmable {
*
* @param child The child that is being dropped
*/
- void onDropChild(View child) {
+ void onDropChild(View child, boolean animate) {
if (child != null) {
LayoutParams lp = (LayoutParams) child.getLayoutParams();
lp.isDragging = false;
lp.dropped = true;
+ lp.animateDrop = animate;
child.setVisibility(View.VISIBLE);
child.requestLayout();
}
@@ -1466,6 +1470,8 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
boolean dropped;
+ boolean animateDrop;
+
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
cellHSpan = 1;
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 62dcf4a0d..342974a4b 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -60,6 +60,7 @@ import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.TextView;
import com.android.launcher.R;
@@ -587,30 +588,47 @@ public class CustomizePagedView extends PagedView
mIsDragging = true;
switch (mCustomizationType) {
- case WidgetCustomization:
+ case WidgetCustomization: {
// Get the widget preview as the drag representation
+ final LinearLayout l = (LinearLayout) v;
+ final Drawable icon = ((ImageView) l.findViewById(R.id.widget_preview)).getDrawable();
+ Bitmap b = drawableToBitmap(icon);
PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) v.getTag();
final View dragView = v.findViewById(R.id.widget_preview);
- mLauncher.getWorkspace().onDragStartedWithItemMinSize(
- createWidgetInfo.minWidth, createWidgetInfo.minHeight);
- mDragController.startDrag(dragView, this, createWidgetInfo, DragController.DRAG_ACTION_COPY, null);
+ int[] spanXY = CellLayout.rectToCell(
+ getResources(), createWidgetInfo.minWidth, createWidgetInfo.minHeight, null);
+ createWidgetInfo.spanX = spanXY[0];
+ createWidgetInfo.spanY = spanXY[1];
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(spanXY[0], spanXY[1], b);
+ mDragController.startDrag(
+ v, b, this, createWidgetInfo, DragController.DRAG_ACTION_COPY, null);
return true;
- case ShortcutCustomization:
+ }
+ case ShortcutCustomization: {
+ // get icon (top compound drawable, index is 1)
+ final Drawable icon = ((TextView) v).getCompoundDrawables()[1];
+ Bitmap b = drawableToBitmap(icon);
PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
- mDragController.startDrag(v, this, createItemInfo, DragController.DRAG_ACTION_COPY);
- mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1);
+ mDragController.startDrag(
+ v, b, this, createItemInfo, DragController.DRAG_ACTION_COPY, null);
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
return true;
- case ApplicationCustomization:
+ }
+ case ApplicationCustomization: {
// Pick up the application for dropping
+ // get icon (top compound drawable, index is 1)
+ final Drawable icon = ((TextView) v).getCompoundDrawables()[1];
+ Bitmap b = drawableToBitmap(icon);
ApplicationInfo app = (ApplicationInfo) v.getTag();
app = new ApplicationInfo(app);
- mDragController.startDrag(v, this, app, DragController.DRAG_ACTION_COPY);
- mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1);
+ mDragController.startDrag(v, b, this, app, DragController.DRAG_ACTION_COPY, null);
+ mLauncher.getWorkspace().onDragStartedWithItemSpans(1, 1, b);
return true;
}
+ }
return false;
}
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index d5f20c548..0cb0e138e 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -176,7 +176,8 @@ public final class Launcher extends Activity
private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
/** The different states that Launcher can be in. */
- private enum State { WORKSPACE, ALL_APPS, CUSTOMIZE, OVERVIEW };
+ private enum State { WORKSPACE, ALL_APPS, CUSTOMIZE, OVERVIEW,
+ CUSTOMIZE_SPRING_LOADED, ALL_APPS_SPRING_LOADED };
private State mState = State.WORKSPACE;
private AnimatorSet mStateAnimation;
@@ -1112,7 +1113,23 @@ public final class Launcher extends Activity
final int[] cellXY = mTmpAddItemCellCoordinates;
final CellLayout layout = (CellLayout) mWorkspace.getChildAt(screen);
- if (!layout.findCellForSpanThatIntersects(cellXY, 1, 1, intersectCellX, intersectCellY)) {
+ int[] touchXY = null;
+ if (mAddDropPosition != null && mAddDropPosition[0] > -1 && mAddDropPosition[1] > -1) {
+ touchXY = mAddDropPosition;
+ }
+ boolean foundCellSpan = false;
+ if (touchXY != null) {
+ // when dragging and dropping, just find the closest free spot
+ CellLayout screenLayout = (CellLayout) mWorkspace.getChildAt(screen);
+ int[] result = screenLayout.findNearestVacantArea(
+ touchXY[0], touchXY[1], 1, 1, cellXY);
+ foundCellSpan = (result != null);
+ } else {
+ foundCellSpan = layout.findCellForSpanThatIntersects(
+ cellXY, 1, 1, intersectCellX, intersectCellY);
+ }
+
+ if (!foundCellSpan) {
showOutOfSpaceMessage();
return;
}
@@ -1151,15 +1168,13 @@ public final class Launcher extends Activity
if (mAddDropPosition != null && mAddDropPosition[0] > -1 && mAddDropPosition[1] > -1) {
touchXY = mAddDropPosition;
}
- boolean findNearestVacantAreaFailed = false;
boolean foundCellSpan = false;
if (touchXY != null) {
// when dragging and dropping, just find the closest free spot
CellLayout screenLayout = (CellLayout) mWorkspace.getChildAt(screen);
int[] result = screenLayout.findNearestVacantArea(
touchXY[0], touchXY[1], spanXY[0], spanXY[1], cellXY);
- findNearestVacantAreaFailed = (result == null);
- foundCellSpan = !findNearestVacantAreaFailed;
+ foundCellSpan = (result != null);
} else {
// if we long pressed on an empty cell to bring up a menu,
// make sure we intersect the empty cell
@@ -1626,8 +1641,6 @@ public final class Launcher extends Activity
void addAppWidgetFromDrop(PendingAddWidgetInfo info, int screen, int[] position) {
resetAddInfo();
mAddScreen = screen;
-
- // only set mAddDropPosition if we dropped on home screen in "spring-loaded" manner
mAddDropPosition = position;
int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
@@ -2685,6 +2698,10 @@ public final class Launcher extends Activity
* @param animated If true, the transition will be animated.
*/
private void cameraZoomIn(State fromState, boolean animated) {
+ cameraZoomIn(fromState, animated, false);
+ }
+
+ private void cameraZoomIn(State fromState, boolean animated, boolean springLoaded) {
Resources res = getResources();
int duration = res.getInteger(R.integer.config_allAppsZoomOutTime);
float scaleFactor = (float) res.getInteger(R.integer.config_allAppsZoomScaleFactor);
@@ -2696,7 +2713,9 @@ public final class Launcher extends Activity
setPivotsForZoom(fromView, fromState, scaleFactor);
- mWorkspace.unshrink(animated);
+ if (!springLoaded) {
+ mWorkspace.unshrink(animated);
+ }
if (animated) {
if (mStateAnimation != null) mStateAnimation.cancel();
@@ -2719,7 +2738,9 @@ public final class Launcher extends Activity
AnimatorSet toolbarHideAnim = new AnimatorSet();
AnimatorSet toolbarShowAnim = new AnimatorSet();
- hideAndShowToolbarButtons(State.WORKSPACE, toolbarShowAnim, toolbarHideAnim);
+ if (!springLoaded) {
+ hideAndShowToolbarButtons(State.WORKSPACE, toolbarShowAnim, toolbarHideAnim);
+ }
mStateAnimation.playTogether(scaleAnim, toolbarHideAnim, alphaAnim);
@@ -2730,7 +2751,9 @@ public final class Launcher extends Activity
mStateAnimation.start();
} else {
fromView.setVisibility(View.GONE);
- hideAndShowToolbarButtons(State.WORKSPACE, null, null);
+ if (!springLoaded) {
+ hideAndShowToolbarButtons(State.WORKSPACE, null, null);
+ }
}
}
@@ -2859,6 +2882,33 @@ public final class Launcher extends Activity
mState = State.WORKSPACE;
}
+ void enterSpringLoadedDragMode(CellLayout layout) {
+ mWorkspace.enterSpringLoadedDragMode(layout);
+ if (mState == State.ALL_APPS) {
+ cameraZoomIn(State.ALL_APPS, true, true);
+ mState = State.ALL_APPS_SPRING_LOADED;
+ } else if (mState == State.CUSTOMIZE) {
+ cameraZoomIn(State.CUSTOMIZE, true, true);
+ mState = State.CUSTOMIZE_SPRING_LOADED;
+ }/* else {
+ // we're already in spring loaded mode; don't do anything
+ }*/
+ }
+
+ void exitSpringLoadedDragMode() {
+ if (mState == State.ALL_APPS_SPRING_LOADED) {
+ mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.BOTTOM_VISIBLE);
+ cameraZoomOut(State.ALL_APPS, true);
+ mState = State.ALL_APPS;
+ } else if (mState == State.CUSTOMIZE_SPRING_LOADED) {
+ mWorkspace.exitSpringLoadedDragMode(Workspace.ShrinkState.TOP);
+ cameraZoomOut(State.CUSTOMIZE, true);
+ mState = State.CUSTOMIZE;
+ }/* else {
+ // we're not in spring loaded mode; don't do anything
+ }*/
+ }
+
/**
* Things to test when changing this code.
* - Home from workspace
@@ -2899,7 +2949,7 @@ public final class Launcher extends Activity
* - From another workspace
*/
void closeAllApps(boolean animated) {
- if (mState == State.ALL_APPS) {
+ if (mState == State.ALL_APPS || mState == State.ALL_APPS_SPRING_LOADED) {
mWorkspace.setVisibility(View.VISIBLE);
if (LauncherApplication.isScreenXLarge()) {
cameraZoomIn(State.ALL_APPS, animated);
@@ -2932,7 +2982,7 @@ public final class Launcher extends Activity
// Hide the customization drawer (only exists in x-large configuration)
void hideCustomizationDrawer(boolean animated) {
- if (mState == State.CUSTOMIZE) {
+ if (mState == State.CUSTOMIZE || mState == State.CUSTOMIZE_SPRING_LOADED) {
cameraZoomIn(State.CUSTOMIZE, animated);
}
}
diff --git a/src/com/android/launcher2/PagedView.java b/src/com/android/launcher2/PagedView.java
index fed0884c3..856507d64 100644
--- a/src/com/android/launcher2/PagedView.java
+++ b/src/com/android/launcher2/PagedView.java
@@ -110,6 +110,9 @@ public abstract class PagedView extends ViewGroup {
protected boolean mAllowOverScroll = true;
protected int mUnboundedScrollX;
+ // parameter that adjusts the layout to be optimized for CellLayouts with that scale factor
+ protected float mLayoutScale = 1.0f;
+
protected static final int INVALID_POINTER = -1;
protected int mActivePointerId = INVALID_POINTER;
@@ -268,7 +271,9 @@ public abstract class PagedView extends ViewGroup {
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
- if (getChildCount() == 0 || currentPage == mCurrentPage) {
+ // don't introduce any checks like mCurrentPage == currentPage here-- if we change the
+ // the default
+ if (getChildCount() == 0) {
return;
}
@@ -445,6 +450,32 @@ public abstract class PagedView extends ViewGroup {
setCurrentPage(newCurrentPage);
}
+ // A layout scale of 1.0f assumes that the CellLayouts, in their unshrunken state, have a
+ // scale of 1.0f. A layout scale of 0.8f assumes the CellLayouts have a scale of 0.8f, and
+ // tightens the layout accordingly
+ public void setLayoutScale(float childrenScale) {
+ mLayoutScale = childrenScale;
+
+ // Now we need to do a re-layout, but preserving absolute X and Y coordinates
+ int childCount = getChildCount();
+ float childrenX[] = new float[childCount];
+ float childrenY[] = new float[childCount];
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ childrenX[i] = child.getX();
+ childrenY[i] = child.getY();
+ }
+ onLayout(false, mLeft, mTop, mRight, mBottom);
+ for (int i = 0; i < childCount; i++) {
+ final View child = getChildAt(i);
+ child.setX(childrenX[i]);
+ child.setY(childrenY[i]);
+ }
+ // Also, the page offset has changed (since the pages are now smaller);
+ // update the page offset, but again preserving absolute X and Y coordinates
+ moveToNewPageWithoutMovingCellLayouts(mCurrentPage);
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
@@ -466,17 +497,21 @@ public abstract class PagedView extends ViewGroup {
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
- final int childWidth = child.getMeasuredWidth();
+ final int childWidth = getScaledMeasuredWidth(child);
final int childHeight = child.getMeasuredHeight();
int childTop = mPaddingTop;
if (mCenterPagesVertically) {
childTop += ((getMeasuredHeight() - verticalPadding) - childHeight) / 2;
}
+
child.layout(childLeft, childTop,
- childLeft + childWidth, childTop + childHeight);
+ childLeft + child.getMeasuredWidth(), childTop + childHeight);
childLeft += childWidth + mPageSpacing;
}
}
+ if (mFirstLayout && mCurrentPage >= 0 && mCurrentPage < getChildCount()) {
+ mFirstLayout = false;
+ }
}
protected void updateAdjacentPagesAlpha() {
@@ -487,7 +522,7 @@ public abstract class PagedView extends ViewGroup {
final int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
View layout = (View) getChildAt(i);
- int childWidth = layout.getMeasuredWidth();
+ int childWidth = getScaledMeasuredWidth(layout);
int halfChildWidth = (childWidth / 2);
int childCenter = getChildOffset(i) + halfChildWidth;
@@ -503,11 +538,11 @@ public abstract class PagedView extends ViewGroup {
int distanceFromScreenCenter = childCenter - screenCenter;
if (distanceFromScreenCenter > 0) {
if (i > 0) {
- d += getChildAt(i - 1).getMeasuredWidth() / 2;
+ d += getScaledMeasuredWidth(getChildAt(i - 1)) / 2;
}
} else {
if (i < childCount - 1) {
- d += getChildAt(i + 1).getMeasuredWidth() / 2;
+ d += getScaledMeasuredWidth(getChildAt(i + 1)) / 2;
}
}
d += mPageSpacing;
@@ -553,7 +588,7 @@ public abstract class PagedView extends ViewGroup {
// page.
final int pageCount = getChildCount();
if (pageCount > 0) {
- final int pageWidth = getChildAt(0).getMeasuredWidth();
+ final int pageWidth = getScaledMeasuredWidth(getChildAt(0));
final int screenWidth = getMeasuredWidth();
int x = getRelativeChildOffset(0) + pageWidth;
int leftScreen = 0;
@@ -563,7 +598,7 @@ public abstract class PagedView extends ViewGroup {
x += pageWidth + mPageSpacing;
// replace above line with this if you don't assume all pages have same width as 0th
// page:
- // x += getChildAt(leftScreen).getMeasuredWidth();
+ // x += getScaledMeasuredWidth(getChildAt(leftScreen));
}
rightScreen = leftScreen;
while (x < mScrollX + screenWidth) {
@@ -572,7 +607,7 @@ public abstract class PagedView extends ViewGroup {
// replace above line with this if you don't assume all pages have same width as 0th
// page:
//if (rightScreen < pageCount) {
- // x += getChildAt(rightScreen).getMeasuredWidth();
+ // x += getScaledMeasuredWidth(getChildAt(rightScreen));
//}
}
rightScreen = Math.min(getChildCount() - 1, rightScreen);
@@ -1049,7 +1084,7 @@ public abstract class PagedView extends ViewGroup {
int right;
for (int i = 0; i < childCount; ++i) {
left = getRelativeChildOffset(i);
- right = (left + getChildAt(i).getMeasuredWidth());
+ right = (left + getScaledMeasuredWidth(getChildAt(i)));
if (left <= relativeOffset && relativeOffset <= right) {
return i;
}
@@ -1067,11 +1102,15 @@ public abstract class PagedView extends ViewGroup {
int offset = getRelativeChildOffset(0);
for (int i = 0; i < index; ++i) {
- offset += getChildAt(i).getMeasuredWidth() + mPageSpacing;
+ offset += getScaledMeasuredWidth(getChildAt(i)) + mPageSpacing;
}
return offset;
}
+ protected int getScaledMeasuredWidth(View child) {
+ return (int) (child.getMeasuredWidth() * mLayoutScale + 0.5f);
+ }
+
int getPageNearestToCenterOfScreen() {
int minDistanceFromScreenCenter = getMeasuredWidth();
int minDistanceFromScreenCenterIndex = -1;
@@ -1079,7 +1118,7 @@ public abstract class PagedView extends ViewGroup {
final int childCount = getChildCount();
for (int i = 0; i < childCount; ++i) {
View layout = (View) getChildAt(i);
- int childWidth = layout.getMeasuredWidth();
+ int childWidth = getScaledMeasuredWidth(layout);
int halfChildWidth = (childWidth / 2);
int childCenter = getChildOffset(i) + halfChildWidth;
int distanceFromScreenCenter = Math.abs(childCenter - screenCenter);
diff --git a/src/com/android/launcher2/SpringLoadedDragController.java b/src/com/android/launcher2/SpringLoadedDragController.java
new file mode 100644
index 000000000..a734258f9
--- /dev/null
+++ b/src/com/android/launcher2/SpringLoadedDragController.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 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;
+
+public class SpringLoadedDragController implements OnAlarmListener {
+ // how long the user must hover over a mini-screen before it unshrinks
+ final long ENTER_SPRING_LOAD_HOVER_TIME = 1000;
+ final long EXIT_SPRING_LOAD_HOVER_TIME = 200;
+
+ Alarm mAlarm;
+
+ // the screen the user is currently hovering over, if any
+ private CellLayout mScreen;
+ private Launcher mLauncher;
+
+ public SpringLoadedDragController(Launcher launcher) {
+ mLauncher = launcher;
+ mAlarm = new Alarm();
+ mAlarm.setOnAlarmListener(this);
+ }
+
+ public void onDragEnter(CellLayout cl) {
+ mScreen = cl;
+ mAlarm.setAlarm(ENTER_SPRING_LOAD_HOVER_TIME);
+ }
+
+ public void onDragExit() {
+ if (mScreen != null) {
+ mScreen.onDragExit();
+ }
+ mScreen = null;
+ mAlarm.setAlarm(EXIT_SPRING_LOAD_HOVER_TIME);
+ }
+
+ // this is called when our timer runs out
+ public void onAlarm(Alarm alarm) {
+ if (mScreen != null) {
+ // we're currently hovering over a screen
+ mLauncher.enterSpringLoadedDragMode(mScreen);
+ } else {
+ mLauncher.exitSpringLoadedDragMode();
+ }
+ }
+}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 239f6f626..b58faed94 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -81,6 +81,9 @@ public class Workspace extends SmoothPagedView
// customization mode
private static final float SHRINK_FACTOR = 0.16f;
+ // How much the screens shrink when we enter spring loaded drag mode
+ private static final float SPRING_LOADED_DRAG_SHRINK_FACTOR = 0.7f;
+
// Y rotation to apply to the workspace screens
private static final float WORKSPACE_ROTATION = 12.5f;
private static final float WORKSPACE_TRANSLATION = 50.0f;
@@ -118,6 +121,7 @@ public class Workspace extends SmoothPagedView
private int mDefaultPage;
private boolean mPageMoving = false;
+ private boolean mIsDragInProcess = false;
/**
* CellInfo for the cell that is currently being dragged
@@ -149,6 +153,8 @@ public class Workspace extends SmoothPagedView
private float[] mTempDragBottomRightCoordinates = new float[2];
private Matrix mTempInverseMatrix = new Matrix();
+ private SpringLoadedDragController mSpringLoadedDragControllger;
+
private static final int DEFAULT_CELL_COUNT_X = 4;
private static final int DEFAULT_CELL_COUNT_Y = 4;
@@ -159,9 +165,10 @@ public class Workspace extends SmoothPagedView
// in all apps or customize mode)
private boolean mIsSmall = false;
private boolean mIsInUnshrinkAnimation = false;
- private AnimatorListener mUnshrinkAnimationListener;
+ private AnimatorListener mShrinkAnimationListener, mUnshrinkAnimationListener;
enum ShrinkState { TOP, SPRING_LOADED, MIDDLE, BOTTOM_HIDDEN, BOTTOM_VISIBLE };
private ShrinkState mShrinkState;
+ private boolean mWasSpringLoadedOnDragExit = false;
private boolean mWaitingToShrink = false;
private ShrinkState mWaitingToShrinkState;
private AnimatorSet mAnimator;
@@ -677,7 +684,7 @@ public class Workspace extends SmoothPagedView
for (int i = 0; i < getChildCount(); i++) {
CellLayout cl = (CellLayout) getChildAt(i);
if (cl != null) {
- int totalDistance = cl.getMeasuredWidth() + mPageSpacing;
+ int totalDistance = getScaledMeasuredWidth(cl) + mPageSpacing;
int delta = screenCenter - (getChildOffset(i) -
getRelativeChildOffset(i) + halfScreenSize);
@@ -938,7 +945,9 @@ public class Workspace extends SmoothPagedView
// Stop any scrolling, move to the current page right away
setCurrentPage((mNextPage != INVALID_PAGE) ? mNextPage : mCurrentPage);
- updateWhichPagesAcceptDrops(mShrinkState);
+ if (!mIsDragInProcess) {
+ updateWhichPagesAcceptDrops(mShrinkState);
+ }
// we intercept and reject all touch events when we're small, so be sure to reset the state
mTouchState = TOUCH_STATE_REST;
@@ -1039,6 +1048,7 @@ public class Workspace extends SmoothPagedView
// increment newX for the next screen
newX += scaledPageWidth + extraScaledSpacing;
}
+ setLayoutScale(1.0f);
if (animated) {
mAnimator.start();
}
@@ -1159,18 +1169,24 @@ public class Workspace extends SmoothPagedView
* appearance).
*
*/
- public void onDragStartedWithItemSpans(int spanX, int spanY) {
- updateWhichPagesAcceptDropsDuringDrag(mShrinkState, spanX, spanY);
- }
+ public void onDragStartedWithItemSpans(int spanX, int spanY, Bitmap b) {
+ mIsDragInProcess = true;
+
+ final Canvas canvas = new Canvas();
- public void onDragStartedWithItemMinSize(int minWidth, int minHeight) {
- int[] spanXY = CellLayout.rectToCell(getResources(), minWidth, minHeight, null);
- onDragStartedWithItemSpans(spanXY[0], spanXY[1]);
+ // We need to add extra padding to the bitmap to make room for the glow effect
+ final int bitmapPadding = HolographicOutlineHelper.OUTER_BLUR_RADIUS;
+
+ // The outline is used to visualize where the item will land if dropped
+ mDragOutline = createDragOutline(b, canvas, bitmapPadding);
+
+ updateWhichPagesAcceptDropsDuringDrag(mShrinkState, spanX, spanY);
}
// we call this method whenever a drag and drop in Launcher finishes, even if Workspace was
// never dragged over
public void onDragStopped() {
+ mIsDragInProcess = false;
updateWhichPagesAcceptDrops(mShrinkState);
}
@@ -1181,16 +1197,48 @@ public class Workspace extends SmoothPagedView
// We call this when we trigger an unshrink by clicking on the CellLayout cl
public void unshrink(CellLayout clThatWasClicked) {
+ unshrink(clThatWasClicked, false);
+ }
+
+ public void unshrink(CellLayout clThatWasClicked, boolean springLoaded) {
int newCurrentPage = indexOfChild(clThatWasClicked);
if (mIsSmall) {
+ if (springLoaded) {
+ setLayoutScale(SPRING_LOADED_DRAG_SHRINK_FACTOR);
+ }
moveToNewPageWithoutMovingCellLayouts(newCurrentPage);
- unshrink(true);
+ unshrink(true, springLoaded);
+ }
+ }
+
+
+ public void enterSpringLoadedDragMode(CellLayout clThatWasClicked) {
+ mShrinkState = ShrinkState.SPRING_LOADED;
+ unshrink(clThatWasClicked, true);
+ mDragTargetLayout.onDragEnter();
+ }
+
+ public void exitSpringLoadedDragMode(ShrinkState shrinkState) {
+ shrink(shrinkState);
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragExit();
}
}
void unshrink(boolean animated) {
+ unshrink(animated, false);
+ }
+
+ void unshrink(boolean animated, boolean springLoaded) {
if (mIsSmall) {
- mIsSmall = false;
+ float finalScaleFactor = 1.0f;
+ float finalBackgroundAlpha = 0.0f;
+ if (springLoaded) {
+ finalScaleFactor = SPRING_LOADED_DRAG_SHRINK_FACTOR;
+ finalBackgroundAlpha = 1.0f;
+ } else {
+ mIsSmall = false;
+ }
if (mAnimator != null) {
mAnimator.cancel();
}
@@ -1216,9 +1264,9 @@ public class Workspace extends SmoothPagedView
ObjectAnimator animWithInterpolator = ObjectAnimator.ofPropertyValuesHolder(cl,
PropertyValuesHolder.ofFloat("translationX", translation),
PropertyValuesHolder.ofFloat("translationY", 0.0f),
- PropertyValuesHolder.ofFloat("scaleX", 1.0f),
- PropertyValuesHolder.ofFloat("scaleY", 1.0f),
- PropertyValuesHolder.ofFloat("backgroundAlpha", 0.0f),
+ PropertyValuesHolder.ofFloat("scaleX", finalScaleFactor),
+ PropertyValuesHolder.ofFloat("scaleY", finalScaleFactor),
+ PropertyValuesHolder.ofFloat("backgroundAlpha", finalBackgroundAlpha),
PropertyValuesHolder.ofFloat("alpha", finalAlphaValue),
PropertyValuesHolder.ofFloat("rotationY", rotation));
animWithInterpolator.setDuration(duration);
@@ -1227,8 +1275,8 @@ public class Workspace extends SmoothPagedView
} else {
cl.setTranslationX(translation);
cl.setTranslationY(0.0f);
- cl.setScaleX(1.0f);
- cl.setScaleY(1.0f);
+ cl.setScaleX(finalScaleFactor);
+ cl.setScaleY(finalScaleFactor);
cl.setBackgroundAlpha(0.0f);
cl.setAlpha(finalAlphaValue);
cl.setRotationY(rotation);
@@ -1295,6 +1343,22 @@ public class Workspace extends SmoothPagedView
}
/**
+ * Returns a new bitmap to be used as the object outline, e.g. to visualize the drop location.
+ * Responsibility for the bitmap is transferred to the caller.
+ */
+ private Bitmap createDragOutline(Bitmap orig, Canvas canvas, int padding) {
+ final int outlineColor = getResources().getColor(R.color.drag_outline_color);
+ final Bitmap b = Bitmap.createBitmap(
+ orig.getWidth() + padding, orig.getHeight() + padding, Bitmap.Config.ARGB_8888);
+
+ canvas.setBitmap(b);
+ canvas.drawBitmap(orig, 0, 0, new Paint());
+ mOutlineHelper.applyMediumExpensiveOutlineWithBlur(b, canvas, outlineColor, outlineColor);
+
+ return b;
+ }
+
+ /**
* Creates a drag outline to represent a drop (that we don't have the actual information for
* yet). May be changed in the future to alter the drop outline slightly depending on the
* clip description mime data.
@@ -1515,12 +1579,12 @@ public class Workspace extends SmoothPagedView
}
if (source != this) {
- if (mIsSmall) {
+ if (!mIsSmall || mWasSpringLoadedOnDragExit) {
+ onDropExternal(originX, originY, dragInfo, mDragTargetLayout, false);
+ } else {
// if we drag and drop to small screens, don't pass the touch x/y coords (when we
// enable spring-loaded adding, however, we do want to pass the touch x/y coords)
onDropExternal(-1, -1, dragInfo, mDragTargetLayout, false);
- } else {
- onDropExternal(originX, originY, dragInfo, mDragTargetLayout, false);
}
} else if (mDragInfo != null) {
final View cell = mDragInfo.cell;
@@ -1577,7 +1641,8 @@ public class Workspace extends SmoothPagedView
// Prepare it to be animated into its new position
// This must be called after the view has been re-parented
setPositionForDropAnimation(dragView, originX, originY, parent, cell);
- parent.onDropChild(cell);
+ boolean animateDrop = !mWasSpringLoadedOnDragExit;
+ parent.onDropChild(cell, animateDrop);
}
}
@@ -1919,21 +1984,34 @@ public class Workspace extends SmoothPagedView
CellLayout layout;
int originX = x - xOffset;
int originY = y - yOffset;
- if (mIsSmall || mIsInUnshrinkAnimation) {
+ boolean shrunken = mIsSmall || mIsInUnshrinkAnimation;
+ if (shrunken) {
layout = findMatchingPageForDragOver(
dragView, originX, originY, xOffset, yOffset);
if (layout != mDragTargetLayout) {
if (mDragTargetLayout != null) {
mDragTargetLayout.setHover(false);
+ mSpringLoadedDragControllger.onDragExit();
}
mDragTargetLayout = layout;
if (mDragTargetLayout != null && mDragTargetLayout.getAcceptsDrops()) {
mDragTargetLayout.setHover(true);
+ mSpringLoadedDragControllger.onDragEnter(mDragTargetLayout);
}
}
} else {
layout = getCurrentDropLayout();
+ if (layout != mDragTargetLayout) {
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragExit();
+ }
+ layout.onDragEnter();
+ mDragTargetLayout = layout;
+ }
+ }
+ if (!shrunken || mShrinkState == ShrinkState.SPRING_LOADED) {
+ layout = getCurrentDropLayout();
final ItemInfo item = (ItemInfo)dragInfo;
if (dragInfo instanceof LauncherAppWidgetInfo) {
@@ -1964,23 +2042,12 @@ public class Workspace extends SmoothPagedView
}
}
- if (layout != mDragTargetLayout) {
- if (mDragTargetLayout != null) {
- mDragTargetLayout.onDragExit();
- }
- layout.onDragEnter();
- mDragTargetLayout = layout;
- }
-
- // only visualize the drop locations for moving icons within the home screen on
- // tablet on phone, we also visualize icons dragged in from All Apps
- if ((!LauncherApplication.isScreenXLarge() || source == this)
- && mDragTargetLayout != null) {
+ if (mDragTargetLayout != null) {
final View child = (mDragInfo == null) ? null : mDragInfo.cell;
- int localOriginX = originX - (mDragTargetLayout.getLeft() - mScrollX);
- int localOriginY = originY - (mDragTargetLayout.getTop() - mScrollY);
+ float[] localOrigin = { originX, originY };
+ mapPointFromSelfToChild(mDragTargetLayout, localOrigin, null);
mDragTargetLayout.visualizeDropLocation(child, mDragOutline,
- localOriginX, localOriginY, item.spanX, item.spanY);
+ (int) localOrigin[0], (int) localOrigin[1], item.spanX, item.spanY);
}
}
}
@@ -1988,12 +2055,16 @@ public class Workspace extends SmoothPagedView
public void onDragExit(DragSource source, int x, int y, int xOffset,
int yOffset, DragView dragView, Object dragInfo) {
+ mWasSpringLoadedOnDragExit = mShrinkState == ShrinkState.SPRING_LOADED;
if (mDragTargetLayout != null) {
mDragTargetLayout.onDragExit();
}
if (!mIsPageMoving) {
hideOutlines();
}
+ if (mShrinkState == ShrinkState.SPRING_LOADED) {
+ mLauncher.exitSpringLoadedDragMode();
+ }
clearAllHovers();
}
@@ -2083,7 +2154,9 @@ public class Workspace extends SmoothPagedView
}
addInScreen(view, indexOfChild(cellLayout), mTargetCell[0],
mTargetCell[1], info.spanX, info.spanY, insertAtFirst);
- cellLayout.onDropChild(view);
+ boolean animateDrop = !mWasSpringLoadedOnDragExit;
+ cellLayout.onDropChild(view, animateDrop);
+ cellLayout.animateDrop();
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams();
LauncherModel.addOrMoveItemInDatabase(mLauncher, info,
@@ -2136,6 +2209,7 @@ public class Workspace extends SmoothPagedView
void setLauncher(Launcher launcher) {
mLauncher = launcher;
+ mSpringLoadedDragControllger = new SpringLoadedDragController(mLauncher);
}
public void setDragController(DragController dragController) {
@@ -2153,7 +2227,8 @@ public class Workspace extends SmoothPagedView
// final Object tag = mDragInfo.cell.getTag();
}
} else if (mDragInfo != null) {
- ((CellLayout) getChildAt(mDragInfo.screen)).onDropChild(mDragInfo.cell);
+ boolean animateDrop = !mWasSpringLoadedOnDragExit;
+ ((CellLayout) getChildAt(mDragInfo.screen)).onDropChild(mDragInfo.cell, animateDrop);
}
mDragOutline = null;
@@ -2214,6 +2289,7 @@ public class Workspace extends SmoothPagedView
for (int i = 0; i < childCount; i++) {
((CellLayout) getChildAt(i)).setHover(false);
}
+ mSpringLoadedDragControllger.onDragExit();
}
@Override