From bebf042666cffe52039b875a549a582abd78a431 Mon Sep 17 00:00:00 2001 From: Adam Cohen Date: Wed, 11 Apr 2012 18:06:28 -0700 Subject: Widget resizing can now displace items Change-Id: I005c9aebf64b2d01debe59f86a208075d19476ea --- .../android/launcher2/AppWidgetResizeFrame.java | 114 ++++++++++++++------- src/com/android/launcher2/CellLayout.java | 84 ++++++--------- src/com/android/launcher2/DragLayer.java | 4 +- src/com/android/launcher2/LauncherModel.java | 34 ++++-- src/com/android/launcher2/Workspace.java | 4 +- 5 files changed, 136 insertions(+), 104 deletions(-) diff --git a/src/com/android/launcher2/AppWidgetResizeFrame.java b/src/com/android/launcher2/AppWidgetResizeFrame.java index c01a882cb..2cc12400d 100644 --- a/src/com/android/launcher2/AppWidgetResizeFrame.java +++ b/src/com/android/launcher2/AppWidgetResizeFrame.java @@ -49,11 +49,13 @@ public class AppWidgetResizeFrame extends FrameLayout { private int mMinVSpan; private int mDeltaX; private int mDeltaY; + private int mDeltaXAddOn; + private int mDeltaYAddOn; private int mBackgroundPadding; private int mTouchTargetWidth; - private int mExpandability[] = new int[4]; + int[] mDirectionVector = new int[2]; final int SNAP_DURATION = 150; final int BACKGROUND_PADDING = 24; @@ -130,6 +132,11 @@ public class AppWidgetResizeFrame extends FrameLayout { final float density = mLauncher.getResources().getDisplayMetrics().density; mBackgroundPadding = (int) Math.ceil(density * BACKGROUND_PADDING); mTouchTargetWidth = 2 * mBackgroundPadding; + + // When we create the resize frame, we first mark all cells as unoccupied. The appropriate + // cells (same if not resized, or different) will be marked as occupied when the resize + // frame is dismissed. + mCellLayout.markCellsAsUnoccupiedForView(mWidgetView); } public boolean beginResizeIfPointInRegion(int x, int y) { @@ -147,8 +154,6 @@ public class AppWidgetResizeFrame extends FrameLayout { mBaselineHeight = getMeasuredHeight(); mBaselineX = getLeft(); mBaselineY = getTop(); - mRunningHInc = 0; - mRunningVInc = 0; if (anyBordersActive) { mLeftHandle.setAlpha(mLeftBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA); @@ -156,8 +161,6 @@ public class AppWidgetResizeFrame extends FrameLayout { mTopHandle.setAlpha(mTopBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA); mBottomHandle.setAlpha(mBottomBorderActive ? 1.0f : DIMMED_HANDLE_ALPHA); } - mCellLayout.getExpandabilityArrayForView(mWidgetView, mExpandability); - return anyBordersActive; } @@ -183,10 +186,14 @@ public class AppWidgetResizeFrame extends FrameLayout { } } + public void visualizeResizeForDelta(int deltaX, int deltaY) { + visualizeResizeForDelta(deltaX, deltaY, false); + } + /** * Based on the deltas, we resize the frame, and, if needed, we resize the widget. */ - public void visualizeResizeForDelta(int deltaX, int deltaY) { + private void visualizeResizeForDelta(int deltaX, int deltaY, boolean onDismiss) { updateDeltas(deltaX, deltaY); DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); @@ -204,25 +211,31 @@ public class AppWidgetResizeFrame extends FrameLayout { lp.height = mBaselineHeight + mDeltaY; } - resizeWidgetIfNeeded(); + resizeWidgetIfNeeded(onDismiss); requestLayout(); } /** * Based on the current deltas, we determine if and how to resize the widget. */ - private void resizeWidgetIfNeeded() { + private void resizeWidgetIfNeeded(boolean onDismiss) { int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap(); int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap(); - float hSpanIncF = 1.0f * mDeltaX / xThreshold - mRunningHInc; - float vSpanIncF = 1.0f * mDeltaY / yThreshold - mRunningVInc; + int deltaX = mDeltaX + mDeltaXAddOn; + int deltaY = mDeltaY + mDeltaYAddOn; + + float hSpanIncF = 1.0f * deltaX / xThreshold - mRunningHInc; + float vSpanIncF = 1.0f * deltaY / yThreshold - mRunningVInc; int hSpanInc = 0; int vSpanInc = 0; int cellXInc = 0; int cellYInc = 0; + int countX = mCellLayout.getCountX(); + int countY = mCellLayout.getCountY(); + if (Math.abs(hSpanIncF) > RESIZE_THRESHOLD) { hSpanInc = Math.round(hSpanIncF); } @@ -230,58 +243,75 @@ public class AppWidgetResizeFrame extends FrameLayout { vSpanInc = Math.round(vSpanIncF); } - if (hSpanInc == 0 && vSpanInc == 0) return; + if (!onDismiss && (hSpanInc == 0 && vSpanInc == 0)) return; - // Before we change the widget, we clear the occupied cells associated with it. - // The new set of occupied cells is marked below, once the layout params are updated. - mCellLayout.markCellsAsUnoccupiedForView(mWidgetView); CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams(); + int spanX = lp.cellHSpan; + int spanY = lp.cellVSpan; + int cellX = lp.useTmpCoords ? lp.tmpCellX : lp.cellX; + int cellY = lp.useTmpCoords ? lp.tmpCellY : lp.cellY; + + int hSpanDelta = 0; + int vSpanDelta = 0; + // For each border, we bound the resizing based on the minimum width, and the maximum // expandability. if (mLeftBorderActive) { - cellXInc = Math.max(-mExpandability[LEFT], hSpanInc); + cellXInc = Math.max(-cellX, hSpanInc); cellXInc = Math.min(lp.cellHSpan - mMinHSpan, cellXInc); hSpanInc *= -1; - hSpanInc = Math.min(mExpandability[LEFT], hSpanInc); + hSpanInc = Math.min(cellX, hSpanInc); hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc); - mRunningHInc -= hSpanInc; + hSpanDelta = -hSpanInc; + } else if (mRightBorderActive) { - hSpanInc = Math.min(mExpandability[RIGHT], hSpanInc); + hSpanInc = Math.min(countX - (cellX + spanX), hSpanInc); hSpanInc = Math.max(-(lp.cellHSpan - mMinHSpan), hSpanInc); - mRunningHInc += hSpanInc; + hSpanDelta = hSpanInc; } if (mTopBorderActive) { - cellYInc = Math.max(-mExpandability[TOP], vSpanInc); + cellYInc = Math.max(-cellY, vSpanInc); cellYInc = Math.min(lp.cellVSpan - mMinVSpan, cellYInc); vSpanInc *= -1; - vSpanInc = Math.min(mExpandability[TOP], vSpanInc); + vSpanInc = Math.min(cellY, vSpanInc); vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc); - mRunningVInc -= vSpanInc; + vSpanDelta = -vSpanInc; } else if (mBottomBorderActive) { - vSpanInc = Math.min(mExpandability[BOTTOM], vSpanInc); + vSpanInc = Math.min(countY - (cellY + spanY), vSpanInc); vSpanInc = Math.max(-(lp.cellVSpan - mMinVSpan), vSpanInc); - mRunningVInc += vSpanInc; + vSpanDelta = vSpanInc; } + mDirectionVector[0] = 0; + mDirectionVector[1] = 0; // Update the widget's dimensions and position according to the deltas computed above if (mLeftBorderActive || mRightBorderActive) { - lp.cellHSpan += hSpanInc; - lp.cellX += cellXInc; + spanX += hSpanInc; + cellX += cellXInc; + mDirectionVector[0] = mLeftBorderActive ? -1 : 1; } if (mTopBorderActive || mBottomBorderActive) { - lp.cellVSpan += vSpanInc; - lp.cellY += cellYInc; + spanY += vSpanInc; + cellY += cellYInc; + mDirectionVector[1] = mTopBorderActive ? -1 : 1; } - // Update the expandability array, as we have changed the widget's size. - mCellLayout.getExpandabilityArrayForView(mWidgetView, mExpandability); + if (!onDismiss && vSpanDelta == 0 && hSpanDelta == 0) return; + + if (mCellLayout.createAreaForResize(cellX, cellY, spanX, spanY, mWidgetView, + mDirectionVector, onDismiss)) { + lp.tmpCellX = cellX; + lp.tmpCellY = cellY; + lp.cellHSpan = spanX; + lp.cellVSpan = spanY; + mRunningVInc += vSpanDelta; + mRunningHInc += hSpanDelta; + } - // Update the cells occupied by this widget - mCellLayout.markCellsAsOccupiedForView(mWidgetView); mWidgetView.requestLayout(); } @@ -289,16 +319,22 @@ public class AppWidgetResizeFrame extends FrameLayout { * This is the final step of the resize. Here we save the new widget size and position * to LauncherModel and animate the resize frame. */ - public void commitResizeForDelta(int deltaX, int deltaY) { - visualizeResizeForDelta(deltaX, deltaY); + public void commitResize() { + resizeWidgetIfNeeded(true); + requestLayout(); + } - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) mWidgetView.getLayoutParams(); - LauncherModel.resizeItemInDatabase(getContext(), mItemInfo, lp.cellX, lp.cellY, - lp.cellHSpan, lp.cellVSpan); - mWidgetView.requestLayout(); + public void onTouchUp() { + int xThreshold = mCellLayout.getCellWidth() + mCellLayout.getWidthGap(); + int yThreshold = mCellLayout.getCellHeight() + mCellLayout.getHeightGap(); + + mDeltaXAddOn = mRunningHInc * xThreshold; + mDeltaYAddOn = mRunningVInc * yThreshold; + mDeltaX = 0; + mDeltaY = 0; - // Once our widget resizes (hence the post), we want to snap the resize frame to it post(new Runnable() { + @Override public void run() { snapToWidget(true); } diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index da7c2b0ec..26a3ecf34 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -2083,6 +2083,8 @@ public class CellLayout extends ViewGroup { if (info != null) { info.cellX = lp.cellX = lp.tmpCellX; info.cellY = lp.cellY = lp.tmpCellY; + info.spanX = lp.cellHSpan; + info.spanY = lp.cellVSpan; } } mLauncher.getWorkspace().updateItemLocationsInDatabase(this); @@ -2214,6 +2216,37 @@ public class CellLayout extends ViewGroup { setItemPlacementDirty(false); } + boolean createAreaForResize(int cellX, int cellY, int spanX, int spanY, + View dragView, int[] direction, boolean commit) { + int[] pixelXY = new int[2]; + regionToCenterPoint(cellX, cellY, spanX, spanY, pixelXY); + + // First we determine if things have moved enough to cause a different layout + ItemConfiguration swapSolution = simpleSwap(pixelXY[0], pixelXY[1], spanX, spanY, + spanX, spanY, direction, dragView, true, new ItemConfiguration()); + + setUseTempCoords(true); + if (swapSolution != null && swapSolution.isSolution) { + // If we're just testing for a possible location (MODE_ACCEPT_DROP), we don't bother + // committing anything or animating anything as we just want to determine if a solution + // exists + copySolutionToTempState(swapSolution, dragView); + setItemPlacementDirty(true); + animateItemsToSolution(swapSolution, dragView, commit); + + if (commit) { + commitTempPlacement(); + completeAndClearReorderHintAnimations(); + setItemPlacementDirty(false); + } else { + beginOrAdjustHintAnimations(swapSolution, dragView, + REORDER_ANIMATION_DURATION); + } + mShortcutsAndWidgets.requestLayout(); + } + return swapSolution.isSolution; + } + int[] createArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY, View dragView, int[] result, int resultSpan[], int mode) { // First we determine if things have moved enough to cause a different layout @@ -2235,7 +2268,6 @@ public class CellLayout extends ViewGroup { mPreviousReorderDirection[0] = INVALID_DIRECTION; mPreviousReorderDirection[1] = INVALID_DIRECTION; } - } else { getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView, mDirectionVector); mPreviousReorderDirection[0] = mDirectionVector[0]; @@ -2694,56 +2726,6 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { } } - /** - * Given a view, determines how much that view can be expanded in all directions, in terms of - * whether or not there are other items occupying adjacent cells. Used by the - * AppWidgetResizeFrame to determine how the widget can be resized. - */ - public void getExpandabilityArrayForView(View view, int[] expandability) { - final LayoutParams lp = (LayoutParams) view.getLayoutParams(); - boolean flag; - - expandability[AppWidgetResizeFrame.LEFT] = 0; - for (int x = lp.cellX - 1; x >= 0; x--) { - flag = false; - for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) { - if (mOccupied[x][y]) flag = true; - } - if (flag) break; - expandability[AppWidgetResizeFrame.LEFT]++; - } - - expandability[AppWidgetResizeFrame.TOP] = 0; - for (int y = lp.cellY - 1; y >= 0; y--) { - flag = false; - for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) { - if (mOccupied[x][y]) flag = true; - } - if (flag) break; - expandability[AppWidgetResizeFrame.TOP]++; - } - - expandability[AppWidgetResizeFrame.RIGHT] = 0; - for (int x = lp.cellX + lp.cellHSpan; x < mCountX; x++) { - flag = false; - for (int y = lp.cellY; y < lp.cellY + lp.cellVSpan; y++) { - if (mOccupied[x][y]) flag = true; - } - if (flag) break; - expandability[AppWidgetResizeFrame.RIGHT]++; - } - - expandability[AppWidgetResizeFrame.BOTTOM] = 0; - for (int y = lp.cellY + lp.cellVSpan; y < mCountY; y++) { - flag = false; - for (int x = lp.cellX; x < lp.cellX + lp.cellHSpan; x++) { - if (mOccupied[x][y]) flag = true; - } - if (flag) break; - expandability[AppWidgetResizeFrame.BOTTOM]++; - } - } - public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) { markCellsAsUnoccupiedForView(view); markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true); diff --git a/src/com/android/launcher2/DragLayer.java b/src/com/android/launcher2/DragLayer.java index 94528574d..e4e48d0cf 100644 --- a/src/com/android/launcher2/DragLayer.java +++ b/src/com/android/launcher2/DragLayer.java @@ -242,7 +242,8 @@ public class DragLayer extends FrameLayout { break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: - mCurrentResizeFrame.commitResizeForDelta(x - mXDown, y - mYDown); + mCurrentResizeFrame.visualizeResizeForDelta(x - mXDown, y - mYDown); + mCurrentResizeFrame.onTouchUp(); mCurrentResizeFrame = null; } } @@ -383,6 +384,7 @@ public class DragLayer extends FrameLayout { public void clearAllResizeFrames() { if (mResizeFrames.size() > 0) { for (AppWidgetResizeFrame frame: mResizeFrames) { + frame.commitResize(); removeView(frame); } mResizeFrames.clear(); diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index a9c4970e3..d29e2e68a 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -248,6 +248,7 @@ public class LauncherModel extends BroadcastReceiver { sWorker.post(r); } } + /** * Move an item in the DB to a new */ @@ -276,24 +277,35 @@ public class LauncherModel extends BroadcastReceiver { } /** - * Resize an item in the DB to a new + * Move and/or resize item in the DB to a new */ - static void resizeItemInDatabase(Context context, final ItemInfo item, final int cellX, - final int cellY, final int spanX, final int spanY) { - item.spanX = spanX; - item.spanY = spanY; + static void modifyItemInDatabase(Context context, final ItemInfo item, final long container, + final int screen, final int cellX, final int cellY, final int spanX, final int spanY) { + item.container = container; item.cellX = cellX; item.cellY = cellY; + item.spanX = spanX; + item.spanY = spanY; + + // We store hotseat items in canonical form which is this orientation invariant position + // in the hotseat + if (context instanceof Launcher && screen < 0 && + container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) { + item.screen = ((Launcher) context).getHotseat().getOrderInHotseat(cellX, cellY); + } else { + item.screen = screen; + } final ContentValues values = new ContentValues(); values.put(LauncherSettings.Favorites.CONTAINER, item.container); - values.put(LauncherSettings.Favorites.SPANX, spanX); - values.put(LauncherSettings.Favorites.SPANY, spanY); - values.put(LauncherSettings.Favorites.CELLX, cellX); - values.put(LauncherSettings.Favorites.CELLY, cellY); - updateItemInDatabaseHelper(context, values, item, "resizeItemInDatabase"); - } + values.put(LauncherSettings.Favorites.CELLX, item.cellX); + values.put(LauncherSettings.Favorites.CELLY, item.cellY); + values.put(LauncherSettings.Favorites.SPANX, item.spanX); + values.put(LauncherSettings.Favorites.SPANY, item.spanY); + values.put(LauncherSettings.Favorites.SCREEN, item.screen); + updateItemInDatabaseHelper(context, values, item, "moveItemInDatabase"); + } /** * Update an item to the database in a specified container. diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index 8c3b46517..aa343b00d 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -3403,8 +3403,8 @@ public class Workspace extends SmoothPagedView ItemInfo info = (ItemInfo) v.getTag(); // Null check required as the AllApps button doesn't have an item info if (info != null) { - LauncherModel.moveItemInDatabase(mLauncher, info, container, screen, info.cellX, - info.cellY); + LauncherModel.modifyItemInDatabase(mLauncher, info, container, screen, info.cellX, + info.cellY, info.spanX, info.spanY); } } } -- cgit v1.2.3