From aafa03cbb925c74be1c13f8bb99d928be429e62f Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Fri, 11 Jun 2010 17:34:16 -0700 Subject: Allow for NxM layout and in-place rotation of items on homescreen. Currently, rotation is disabled as designs are still in flux, but the NxM grid is enabled (8x4). Change-Id: I0026f88c674719e3d67de6d6d481d2d4cd606362 --- src/com/android/launcher2/AllApps2D.java | 13 +- src/com/android/launcher2/AllApps3D.java | 12 +- src/com/android/launcher2/AllAppsList.java | 9 +- src/com/android/launcher2/ApplicationInfo.java | 7 +- src/com/android/launcher2/CellLayout.java | 308 +++++++++------- src/com/android/launcher2/DeferredHandler.java | 5 +- src/com/android/launcher2/DragView.java | 5 - src/com/android/launcher2/Folder.java | 4 +- .../android/launcher2/InstallShortcutReceiver.java | 38 +- src/com/android/launcher2/ItemInfo.java | 5 + src/com/android/launcher2/Launcher.java | 96 +++-- src/com/android/launcher2/LauncherApplication.java | 12 + src/com/android/launcher2/LauncherModel.java | 200 +++++++++-- .../launcher2/LauncherModelOrientationHelper.java | 180 ++++++++++ src/com/android/launcher2/LiveFolderInfo.java | 1 - .../android/launcher2/ScriptField_VpConsts.java | 5 + src/com/android/launcher2/ShortcutInfo.java | 6 +- src/com/android/launcher2/ShortcutsAdapter.java | 5 +- .../android/launcher2/SymmetricalLinearTween.java | 2 - src/com/android/launcher2/UserFolder.java | 2 - src/com/android/launcher2/Utilities.java | 13 +- src/com/android/launcher2/Workspace.java | 392 ++++++++++++++------- 22 files changed, 903 insertions(+), 417 deletions(-) create mode 100644 src/com/android/launcher2/LauncherModelOrientationHelper.java (limited to 'src') diff --git a/src/com/android/launcher2/AllApps2D.java b/src/com/android/launcher2/AllApps2D.java index 7ad5e4915..b18fc1af7 100644 --- a/src/com/android/launcher2/AllApps2D.java +++ b/src/com/android/launcher2/AllApps2D.java @@ -16,6 +16,9 @@ package com.android.launcher2; +import java.util.ArrayList; +import java.util.Collections; + import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; @@ -25,20 +28,16 @@ import android.graphics.Color; import android.util.AttributeSet; import android.util.Log; import android.view.KeyEvent; -import android.view.ViewGroup; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; import android.view.animation.AnimationUtils; -import android.view.ViewConfiguration; import android.widget.AdapterView; -import android.widget.ImageButton; -import android.widget.TextView; import android.widget.ArrayAdapter; import android.widget.GridView; +import android.widget.ImageButton; import android.widget.RelativeLayout; - -import java.util.ArrayList; -import java.util.Collections; +import android.widget.TextView; import com.android.launcher.R; diff --git a/src/com/android/launcher2/AllApps3D.java b/src/com/android/launcher2/AllApps3D.java index 4a2dc49e4..9ef98fd32 100644 --- a/src/com/android/launcher2/AllApps3D.java +++ b/src/com/android/launcher2/AllApps3D.java @@ -16,6 +16,10 @@ package com.android.launcher2; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; + import android.content.ComponentName; import android.content.Context; import android.content.res.Resources; @@ -29,11 +33,9 @@ import android.renderscript.ProgramFragment; import android.renderscript.ProgramStore; import android.renderscript.ProgramVertex; import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; import android.renderscript.RenderScript; +import android.renderscript.RenderScriptGL; import android.renderscript.Sampler; -import android.renderscript.Script; -import android.renderscript.ScriptC; import android.renderscript.SimpleMesh; import android.renderscript.Type; import android.util.AttributeSet; @@ -48,10 +50,6 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; - import com.android.launcher.R; public class AllApps3D extends RSSurfaceView diff --git a/src/com/android/launcher2/AllAppsList.java b/src/com/android/launcher2/AllAppsList.java index 41aa6ca1c..3bacd87e0 100644 --- a/src/com/android/launcher2/AllAppsList.java +++ b/src/com/android/launcher2/AllAppsList.java @@ -16,17 +16,16 @@ package com.android.launcher2; +import java.util.ArrayList; +import java.util.List; + import android.content.ComponentName; -import android.content.Intent; import android.content.Context; +import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - /** * Stores the list of all applications for the all apps view. diff --git a/src/com/android/launcher2/ApplicationInfo.java b/src/com/android/launcher2/ApplicationInfo.java index 5bb503780..7b00f4fb1 100644 --- a/src/com/android/launcher2/ApplicationInfo.java +++ b/src/com/android/launcher2/ApplicationInfo.java @@ -16,17 +16,14 @@ package com.android.launcher2; +import java.util.ArrayList; + import android.content.ComponentName; -import android.content.ContentValues; -import android.content.Context; import android.content.Intent; import android.content.pm.ResolveInfo; import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; import android.util.Log; -import java.util.ArrayList; - /** * Represents an app in AllAppsView. */ diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java index 73481c248..d69c56f7d 100644 --- a/src/com/android/launcher2/CellLayout.java +++ b/src/com/android/launcher2/CellLayout.java @@ -16,36 +16,44 @@ package com.android.launcher2; +import java.util.ArrayList; + +import android.app.WallpaperManager; import android.content.Context; -import android.content.res.TypedArray; import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.Canvas; import android.util.AttributeSet; import android.view.ContextMenu; import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; import android.view.ViewGroup; -import android.app.WallpaperManager; - -import java.util.ArrayList; +import android.view.animation.Animation; +import android.view.animation.LayoutAnimationController; import com.android.launcher.R; public class CellLayout extends ViewGroup { + static final String TAG = "CellLayout"; + private boolean mPortrait; private int mCellWidth; private int mCellHeight; - + private int mLongAxisStartPadding; private int mLongAxisEndPadding; - private int mShortAxisStartPadding; private int mShortAxisEndPadding; + private int mLeftPadding; + private int mRightPadding; + private int mTopPadding; + private int mBottomPadding; + private int mShortAxisCells; private int mLongAxisCells; @@ -54,7 +62,7 @@ public class CellLayout extends ViewGroup { private final Rect mRect = new Rect(); private final CellInfo mCellInfo = new CellInfo(); - + int[] mCellXY = new int[2]; boolean[][] mOccupied; @@ -62,8 +70,8 @@ public class CellLayout extends ViewGroup { private boolean mDirtyTag; private boolean mLastDownOnOccupiedCell = false; - - private final WallpaperManager mWallpaperManager; + + private final WallpaperManager mWallpaperManager; public CellLayout(Context context) { this(context, null); @@ -79,16 +87,16 @@ public class CellLayout extends ViewGroup { mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10); mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10); - - mLongAxisStartPadding = + + mLongAxisStartPadding = a.getDimensionPixelSize(R.styleable.CellLayout_longAxisStartPadding, 10); - mLongAxisEndPadding = + mLongAxisEndPadding = a.getDimensionPixelSize(R.styleable.CellLayout_longAxisEndPadding, 10); mShortAxisStartPadding = a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisStartPadding, 10); - mShortAxisEndPadding = + mShortAxisEndPadding = a.getDimensionPixelSize(R.styleable.CellLayout_shortAxisEndPadding, 10); - + mShortAxisCells = a.getInt(R.styleable.CellLayout_shortAxisCells, 4); mLongAxisCells = a.getInt(R.styleable.CellLayout_longAxisCells, 4); @@ -96,14 +104,6 @@ public class CellLayout extends ViewGroup { setAlwaysDrawnWithCacheEnabled(false); - if (mOccupied == null) { - if (mPortrait) { - mOccupied = new boolean[mShortAxisCells][mLongAxisCells]; - } else { - mOccupied = new boolean[mLongAxisCells][mShortAxisCells]; - } - } - mWallpaperManager = WallpaperManager.getInstance(getContext()); } @@ -132,14 +132,24 @@ public class CellLayout extends ViewGroup { return mPortrait ? mLongAxisCells : mShortAxisCells; } - @Override - public void addView(View child, int index, ViewGroup.LayoutParams params) { + // Takes canonical layout parameters + public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params) { + final LayoutParams lp = params; + // Generate an id for each view, this assumes we have at most 256x256 cells // per workspace screen - final LayoutParams lp = (LayoutParams) params; - child.setId(((getId() & 0xFF) << 16) | (lp.cellX & 0xFF) << 8 | (lp.cellY & 0xFF)); + if (lp.cellX >= 0 && lp.cellX <= getCountX() - 1 && lp.cellY >= 0 && lp.cellY <= getCountY() - 1) { + // If the horizontal or vertical span is set to -1, it is taken to + // mean that it spans the extent of the CellLayout + if (lp.cellHSpan < 0) lp.cellHSpan = getCountX(); + if (lp.cellVSpan < 0) lp.cellVSpan = getCountY(); + + child.setId(childId); - super.addView(child, index, params); + addView(child, index, lp); + return true; + } + return false; } @Override @@ -185,7 +195,7 @@ public class CellLayout extends ViewGroup { } } } - + mLastDownOnOccupiedCell = found; if (!found) { @@ -217,6 +227,7 @@ public class CellLayout extends ViewGroup { setTag(cellInfo); } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getAction(); @@ -256,8 +267,8 @@ public class CellLayout extends ViewGroup { return info; } - private static void findIntersectingVacantCells(CellInfo cellInfo, int x, int y, - int xCount, int yCount, boolean[][] occupied) { + private static void findIntersectingVacantCells(CellInfo cellInfo, int x, + int y, int xCount, int yCount, boolean[][] occupied) { cellInfo.maxVacantSpanX = Integer.MIN_VALUE; cellInfo.maxVacantSpanXSpanY = Integer.MIN_VALUE; @@ -392,21 +403,21 @@ public class CellLayout extends ViewGroup { // Assume the caller will perform their own cell searching, otherwise we // risk causing an unnecessary rebuild after findCellForSpan() - + return cellInfo; } /** - * Given a point, return the cell that strictly encloses that point + * Given a point, return the cell that strictly encloses that point * @param x X coordinate of the point * @param y Y coordinate of the point * @param result Array of 2 ints to hold the x and y coordinate of the cell */ void pointToCellExact(int x, int y, int[] result) { final boolean portrait = mPortrait; - - final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; - final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; + + final int hStartPadding = getLeftPadding(); + final int vStartPadding = getTopPadding(); result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap); result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap); @@ -419,7 +430,7 @@ public class CellLayout extends ViewGroup { if (result[1] < 0) result[1] = 0; if (result[1] >= yAxis) result[1] = yAxis - 1; } - + /** * Given a point, return the cell that most closely encloses that point * @param x X coordinate of the point @@ -432,18 +443,15 @@ public class CellLayout extends ViewGroup { /** * Given a cell coordinate, return the point that represents the upper left corner of that cell - * - * @param cellX X coordinate of the cell + * + * @param cellX X coordinate of the cell * @param cellY Y coordinate of the cell - * + * * @param result Array of 2 ints to hold the x and y coordinate of the point */ void cellToPoint(int cellX, int cellY, int[] result) { - final boolean portrait = mPortrait; - - final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; - final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; - + final int hStartPadding = getLeftPadding(); + final int vStartPadding = getTopPadding(); result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap); result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap); @@ -458,92 +466,117 @@ public class CellLayout extends ViewGroup { } int getLeftPadding() { - return mPortrait ? mShortAxisStartPadding : mLongAxisStartPadding; + return mLeftPadding; } int getTopPadding() { - return mPortrait ? mLongAxisStartPadding : mShortAxisStartPadding; + return mTopPadding; } int getRightPadding() { - return mPortrait ? mShortAxisEndPadding : mLongAxisEndPadding; + return mRightPadding; } int getBottomPadding() { - return mPortrait ? mLongAxisEndPadding : mShortAxisEndPadding; + return mBottomPadding; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO: currently ignoring padding - + int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec); - int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); - + int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec); - + if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) { throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions"); } final int shortAxisCells = mShortAxisCells; final int longAxisCells = mLongAxisCells; - final int longAxisStartPadding = mLongAxisStartPadding; - final int longAxisEndPadding = mLongAxisEndPadding; - final int shortAxisStartPadding = mShortAxisStartPadding; - final int shortAxisEndPadding = mShortAxisEndPadding; final int cellWidth = mCellWidth; final int cellHeight = mCellHeight; - mPortrait = heightSpecSize > widthSpecSize; + boolean portrait = heightSpecSize > widthSpecSize; + if (portrait != mPortrait || mOccupied == null) { + if (portrait) { + mOccupied = new boolean[mShortAxisCells][mLongAxisCells]; + } else { + mOccupied = new boolean[mLongAxisCells][mShortAxisCells]; + } + } + mPortrait = portrait; int numShortGaps = shortAxisCells - 1; int numLongGaps = longAxisCells - 1; if (mPortrait) { - int vSpaceLeft = heightSpecSize - longAxisStartPadding - longAxisEndPadding - - (cellHeight * longAxisCells); + int vSpaceLeft = heightSpecSize - mLongAxisStartPadding + - mLongAxisEndPadding - (cellHeight * longAxisCells); mHeightGap = vSpaceLeft / numLongGaps; - int hSpaceLeft = widthSpecSize - shortAxisStartPadding - shortAxisEndPadding - - (cellWidth * shortAxisCells); + int hSpaceLeft = widthSpecSize - mShortAxisStartPadding + - mShortAxisEndPadding - (cellWidth * shortAxisCells); if (numShortGaps > 0) { mWidthGap = hSpaceLeft / numShortGaps; } else { mWidthGap = 0; } + + if (LauncherApplication.isInPlaceRotationEnabled()) { + mWidthGap = mHeightGap = Math.min(mHeightGap, mWidthGap); + mLeftPadding = mRightPadding = (widthSpecSize - cellWidth + * shortAxisCells - (shortAxisCells - 1) * mWidthGap) / 2; + mTopPadding = mBottomPadding = (heightSpecSize - cellHeight + * longAxisCells - (longAxisCells - 1) * mHeightGap) / 2; + } else { + mLeftPadding = mShortAxisStartPadding; + mRightPadding = mShortAxisEndPadding; + mTopPadding = mLongAxisStartPadding; + mBottomPadding = mLongAxisEndPadding; + } } else { - int hSpaceLeft = widthSpecSize - longAxisStartPadding - longAxisEndPadding - - (cellWidth * longAxisCells); + int hSpaceLeft = widthSpecSize - mLongAxisStartPadding + - mLongAxisEndPadding - (cellWidth * longAxisCells); mWidthGap = hSpaceLeft / numLongGaps; - int vSpaceLeft = heightSpecSize - shortAxisStartPadding - shortAxisEndPadding - - (cellHeight * shortAxisCells); + int vSpaceLeft = heightSpecSize - mShortAxisStartPadding + - mShortAxisEndPadding - (cellHeight * shortAxisCells); if (numShortGaps > 0) { mHeightGap = vSpaceLeft / numShortGaps; } else { mHeightGap = 0; } + + if (LauncherApplication.isScreenXLarge()) { + mWidthGap = mHeightGap = Math.min(mHeightGap, mWidthGap); + mLeftPadding = mRightPadding = (widthSpecSize - cellWidth + * longAxisCells - (longAxisCells - 1) * mWidthGap) / 2 ; + mTopPadding = mBottomPadding = (heightSpecSize - cellHeight + * shortAxisCells - (shortAxisCells - 1) * mHeightGap) / 2; + } else { + mLeftPadding = mLongAxisStartPadding; + mRightPadding = mLongAxisEndPadding; + mTopPadding = mShortAxisStartPadding; + mBottomPadding = mShortAxisEndPadding; + } } - int count = getChildCount(); for (int i = 0; i < count; i++) { View child = getChildAt(i); LayoutParams lp = (LayoutParams) child.getLayoutParams(); + lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, + mLeftPadding, mTopPadding); + + int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, + MeasureSpec.EXACTLY); + int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height, + MeasureSpec.EXACTLY); - if (mPortrait) { - lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, shortAxisStartPadding, - longAxisStartPadding); - } else { - lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap, longAxisStartPadding, - shortAxisStartPadding); - } - - int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY); - int childheightMeasureSpec = - MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); child.measure(childWidthMeasureSpec, childheightMeasureSpec); } @@ -596,7 +629,7 @@ public class CellLayout extends ViewGroup { /** * Find a vacant area that will fit the given bounds nearest the requested * cell location. Uses Euclidean distance to score multiple vacant areas. - * + * * @param pixelX The X location at which you want to search for a vacant area. * @param pixelY The Y location at which you want to search for a vacant area. * @param spanX Horizontal span of the object. @@ -608,12 +641,12 @@ public class CellLayout extends ViewGroup { */ int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, CellInfo vacantCells, int[] recycle) { - + // Keep track of best-scoring drop area final int[] bestXY = recycle != null ? recycle : new int[2]; final int[] cellXY = mCellXY; double bestDistance = Double.MAX_VALUE; - + // Bail early if vacant cells aren't valid if (!vacantCells.valid) { return null; @@ -623,17 +656,17 @@ public class CellLayout extends ViewGroup { final int size = vacantCells.vacantCells.size(); for (int i = 0; i < size; i++) { final CellInfo.VacantCell cell = vacantCells.vacantCells.get(i); - + // Reject if vacant cell isn't our exact size if (cell.spanX != spanX || cell.spanY != spanY) { continue; } - + // Score is center distance from requested pixel cellToPoint(cell.cellX, cell.cellY, cellXY); - - double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) + - Math.pow(cellXY[1] - pixelY, 2)); + + double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2) + + Math.pow(cellXY[1] - pixelY, 2)); if (distance <= bestDistance) { bestDistance = distance; bestXY[0] = cell.cellX; @@ -641,25 +674,22 @@ public class CellLayout extends ViewGroup { } } - // Return null if no suitable location found + // Return null if no suitable location found if (bestDistance < Double.MAX_VALUE) { return bestXY; } else { return null; } } - + /** - * Drop a child at the specified position + * Mark a child as having been dropped. * * @param child The child that is being dropped - * @param targetXY Destination area to move to */ - void onDropChild(View child, int[] targetXY) { + void onDropChild(View child) { if (child != null) { LayoutParams lp = (LayoutParams) child.getLayoutParams(); - lp.cellX = targetXY[0]; - lp.cellY = targetXY[1]; lp.isDragging = false; lp.dropped = true; mDragRect.setEmpty(); @@ -678,7 +708,7 @@ public class CellLayout extends ViewGroup { /** * Start dragging the specified child - * + * * @param child The child that is being dragged */ void onDragChild(View child) { @@ -686,13 +716,13 @@ public class CellLayout extends ViewGroup { lp.isDragging = true; mDragRect.setEmpty(); } - + /** * Drag a child over the specified position - * + * * @param child The child that is being dropped * @param cellX The child's new x cell location - * @param cellY The child's new y cell location + * @param cellY The child's new y cell location */ void onDragOverChild(View child, int cellX, int cellY) { int[] cellXY = mCellXY; @@ -701,39 +731,38 @@ public class CellLayout extends ViewGroup { cellToRect(cellXY[0], cellXY[1], lp.cellHSpan, lp.cellVSpan, mDragRect); invalidate(); } - + /** * Computes a bounding rectangle for a range of cells - * + * * @param cellX X coordinate of upper left corner expressed as a cell position * @param cellY Y coordinate of upper left corner expressed as a cell position - * @param cellHSpan Width in cells + * @param cellHSpan Width in cells * @param cellVSpan Height in cells * @param dragRect Rectnagle into which to put the results */ public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF dragRect) { - final boolean portrait = mPortrait; final int cellWidth = mCellWidth; final int cellHeight = mCellHeight; final int widthGap = mWidthGap; final int heightGap = mHeightGap; - - final int hStartPadding = portrait ? mShortAxisStartPadding : mLongAxisStartPadding; - final int vStartPadding = portrait ? mLongAxisStartPadding : mShortAxisStartPadding; - + + final int hStartPadding = getLeftPadding(); + final int vStartPadding = getTopPadding(); + int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap); int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap); int x = hStartPadding + cellX * (cellWidth + widthGap); int y = vStartPadding + cellY * (cellHeight + heightGap); - + dragRect.set(x, y, x + width, y + height); } - + /** - * Computes the required horizontal and vertical cell spans to always + * Computes the required horizontal and vertical cell spans to always * fit the given rectangle. - * + * * @param width Width in pixels * @param height Height in pixels */ @@ -758,7 +787,7 @@ public class CellLayout extends ViewGroup { * @param vacant Holds the x and y coordinate of the vacant cell * @param spanX Horizontal cell span. * @param spanY Vertical cell span. - * + * * @return True if a vacant cell was found */ public boolean getVacantCell(int[] vacant, int spanX, int spanY) { @@ -852,6 +881,17 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { return new CellLayout.LayoutParams(p); } + public static class CellLayoutAnimationController extends LayoutAnimationController { + public CellLayoutAnimationController(Animation animation, float delay) { + super(animation, delay); + } + + @Override + protected long getDelayForView(View view) { + return (int) (Math.random() * 150); + } + } + public static class LayoutParams extends ViewGroup.MarginLayoutParams { /** * Horizontal location of the item in the grid. @@ -876,7 +916,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { */ @ViewDebug.ExportedProperty public int cellVSpan; - + /** * Is this item currently being dragged */ @@ -902,7 +942,15 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { cellHSpan = 1; cellVSpan = 1; } - + + public LayoutParams(LayoutParams source) { + super(source); + this.cellX = source.cellX; + this.cellY = source.cellY; + this.cellHSpan = source.cellHSpan; + this.cellVSpan = source.cellVSpan; + } + public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) { super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); this.cellX = cellX; @@ -913,12 +961,12 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap, int hStartPadding, int vStartPadding) { - + final int myCellHSpan = cellHSpan; final int myCellVSpan = cellVSpan; final int myCellX = cellX; final int myCellY = cellY; - + width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) - leftMargin - rightMargin; height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) - @@ -927,14 +975,18 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin; y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin; } + + public String toString() { + return "(" + this.cellX + ", " + this.cellY + ")"; + } } static final class CellInfo implements ContextMenu.ContextMenuInfo { /** - * See View.AttachInfo.InvalidateInfo for futher explanations about - * the recycling mechanism. In this case, we recycle the vacant cells - * instances because up to several hundreds can be instanciated when - * the user long presses an empty cell. + * See View.AttachInfo.InvalidateInfo for futher explanations about the + * recycling mechanism. In this case, we recycle the vacant cells + * instances because up to several hundreds can be instanciated when the + * user long presses an empty cell. */ static final class VacantCell { int cellX; @@ -945,7 +997,7 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { // We can create up to 523 vacant cells on a 4x4 grid, 100 seems // like a reasonable compromise given the size of a VacantCell and // the fact that the user is not likely to touch an empty 4x4 grid - // very often + // very often private static final int POOL_LIMIT = 100; private static final Object sLock = new Object(); @@ -980,8 +1032,8 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { @Override public String toString() { - return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + spanX + - ", spanY=" + spanY + "]"; + return "VacantCell[x=" + cellX + ", y=" + cellY + ", spanX=" + + spanX + ", spanY=" + spanY + "]"; } } @@ -1004,7 +1056,9 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { final ArrayList list = vacantCells; final int count = list.size(); - for (int i = 0; i < count; i++) list.get(i).release(); + for (int i = 0; i < count; i++) { + list.get(i).release(); + } list.clear(); } @@ -1078,15 +1132,17 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { } } - if (clear) clearVacantCells(); + if (clear) { + clearVacantCells(); + } return found; } @Override public String toString() { - return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + ", x=" + cellX + - ", y=" + cellY + "]"; + return "Cell[view=" + (cell == null ? "null" : cell.getClass()) + + ", x=" + cellX + ", y=" + cellY + "]"; } } @@ -1094,5 +1150,3 @@ out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) { return mLastDownOnOccupiedCell; } } - - diff --git a/src/com/android/launcher2/DeferredHandler.java b/src/com/android/launcher2/DeferredHandler.java index 7801642d2..0323c7f4d 100644 --- a/src/com/android/launcher2/DeferredHandler.java +++ b/src/com/android/launcher2/DeferredHandler.java @@ -16,13 +16,12 @@ package com.android.launcher2; +import java.util.LinkedList; + import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; -import android.util.Log; - -import java.util.LinkedList; /** * Queue of things to run on a looper thread. Items posted with {@link #post} will not diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java index 248712ed3..bae592cb0 100644 --- a/src/com/android/launcher2/DragView.java +++ b/src/com/android/launcher2/DragView.java @@ -18,20 +18,15 @@ package com.android.launcher2; import android.content.Context; -import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; -import android.graphics.Point; import android.os.IBinder; -import android.util.AttributeSet; -import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; -import android.view.KeyEvent; import android.view.WindowManager; import android.view.WindowManagerImpl; diff --git a/src/com/android/launcher2/Folder.java b/src/com/android/launcher2/Folder.java index 7ff83284e..4d7c6668c 100644 --- a/src/com/android/launcher2/Folder.java +++ b/src/com/android/launcher2/Folder.java @@ -21,11 +21,11 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; +import android.widget.AbsListView; import android.widget.AdapterView; +import android.widget.BaseAdapter; import android.widget.Button; import android.widget.LinearLayout; -import android.widget.AbsListView; -import android.widget.BaseAdapter; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; diff --git a/src/com/android/launcher2/InstallShortcutReceiver.java b/src/com/android/launcher2/InstallShortcutReceiver.java index 3fc568b9f..36380540d 100644 --- a/src/com/android/launcher2/InstallShortcutReceiver.java +++ b/src/com/android/launcher2/InstallShortcutReceiver.java @@ -16,11 +16,11 @@ package com.android.launcher2; +import java.util.ArrayList; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import android.content.ContentResolver; -import android.database.Cursor; import android.widget.Toast; import com.android.launcher.R; @@ -86,38 +86,24 @@ public class InstallShortcutReceiver extends BroadcastReceiver { private static boolean findEmptyCell(Context context, int[] xy, int screen) { final int xCount = Launcher.NUMBER_CELLS_X; final int yCount = Launcher.NUMBER_CELLS_Y; - boolean[][] occupied = new boolean[xCount][yCount]; - final ContentResolver cr = context.getContentResolver(); - Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, - new String[] { LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY, - LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, - LauncherSettings.Favorites.SCREEN + "=?", - new String[] { String.valueOf(screen) }, null); - - final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX); - final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); - final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX); - final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY); - - try { - while (c.moveToNext()) { - int cellX = c.getInt(cellXIndex); - int cellY = c.getInt(cellYIndex); - int spanX = c.getInt(spanXIndex); - int spanY = c.getInt(spanYIndex); - + ArrayList items = LauncherModel.getItemsInLocalCoordinates(context); + ItemInfo item = null; + int cellX, cellY, spanX, spanY; + for (int i = 0; i < items.size(); ++i) { + item = items.get(i); + if (item.screen == screen) { + cellX = item.cellX; + cellY = item.cellY; + spanX = item.spanX; + spanY = item.spanY; for (int x = cellX; x < cellX + spanX && x < xCount; x++) { for (int y = cellY; y < cellY + spanY && y < yCount; y++) { occupied[x][y] = true; } } } - } catch (Exception e) { - return false; - } finally { - c.close(); } return CellLayout.findVacantCell(xy, 1, 1, xCount, yCount, occupied); diff --git a/src/com/android/launcher2/ItemInfo.java b/src/com/android/launcher2/ItemInfo.java index a96d9aeb2..dc4575062 100644 --- a/src/com/android/launcher2/ItemInfo.java +++ b/src/com/android/launcher2/ItemInfo.java @@ -112,6 +112,11 @@ class ItemInfo { } } + void updateValuesWithCoordinates(ContentValues values, int cellX, int cellY) { + values.put(LauncherSettings.Favorites.CELLX, cellX); + values.put(LauncherSettings.Favorites.CELLY, cellY); + } + static byte[] flattenBitmap(Bitmap bitmap) { // Try go guesstimate how much space the icon will take when serialized // to avoid unnecessary allocations/copies during the write. diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java index 07e8834c0..69911a788 100644 --- a/src/com/android/launcher2/Launcher.java +++ b/src/com/android/launcher2/Launcher.java @@ -16,8 +16,13 @@ package com.android.launcher2; -import com.android.common.Search; -import com.android.launcher.R; +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; import android.app.Activity; import android.app.AlertDialog; @@ -36,6 +41,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.Intent.ShortcutIconResource; +import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; @@ -67,6 +73,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import android.view.View.OnLongClickListener; import android.view.animation.AnimationUtils; import android.view.inputmethod.InputMethodManager; @@ -77,13 +84,8 @@ import android.widget.PopupWindow; import android.widget.TextView; import android.widget.Toast; -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; +import com.android.common.Search; +import com.android.launcher.R; /** * Default launcher application. @@ -211,10 +213,17 @@ public final class Launcher extends Activity private Drawable[] mHotseatIcons = null; private CharSequence[] mHotseatLabels = null; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + if (LauncherApplication.isInPlaceRotationEnabled()) { + // hide the status bar (temporary until we get the status bar design figured out) + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR); + } + LauncherApplication app = ((LauncherApplication)getApplication()); mModel = app.setLauncher(this); mIconCache = app.getIconCache(); @@ -232,8 +241,8 @@ public final class Launcher extends Activity loadHotseats(); checkForLocaleChange(); setWallpaperDimension(); - setContentView(R.layout.launcher); + setupViews(); registerContentObservers(); @@ -259,6 +268,19 @@ public final class Launcher extends Activity registerReceiver(mCloseSystemDialogsReceiver, filter); } + @Override + public void onConfigurationChanged(Configuration newConfig) { + // TODO Auto-generated method stub + super.onConfigurationChanged(newConfig); + + if (LauncherApplication.isInPlaceRotationEnabled()) { + mModel.updateOrientation(); + mWorkspace.refreshWorkspaceChildren(); + mWorkspace.rotateCurrentScreensChildren(); + } + } + + private void checkForLocaleChange() { final LocaleConfiguration localeConfiguration = new LocaleConfiguration(); readConfiguration(this, localeConfiguration); @@ -419,7 +441,7 @@ public final class Launcher extends Activity // note: if the user launches this without a default set, she // will always be taken to the default URL above; this is // unavoidable as we must specify a valid URL in order for the - // chooser to appear, and once the user selects something, that + // chooser to appear, and once the user selects something, that // URL is unavoidably sent to the chosen app. } else { try { @@ -429,7 +451,7 @@ public final class Launcher extends Activity // bogus; leave intent=null } } - + if (intent == null) { mHotseats[i] = null; mHotseatLabels[i] = getText(R.string.activity_not_found); @@ -437,15 +459,15 @@ public final class Launcher extends Activity } if (LOGD) { - Log.d(TAG, "loadHotseats: hotseat " + i - + " initial intent=[" + Log.d(TAG, "loadHotseats: hotseat " + i + + " initial intent=[" + intent.toUri(Intent.URI_INTENT_SCHEME) + "]"); } ResolveInfo bestMatch = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); List allMatches = pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); - if (LOGD) { + if (LOGD) { Log.d(TAG, "Best match for intent: " + bestMatch); Log.d(TAG, "All matches: "); for (ResolveInfo ri : allMatches) { @@ -454,8 +476,8 @@ public final class Launcher extends Activity } // did this resolve to a single app, or the resolver? if (allMatches.size() == 0 || bestMatch == null) { - // can't find any activity to handle this. let's leave the - // intent as-is and let Launcher show a toast when it fails + // can't find any activity to handle this. let's leave the + // intent as-is and let Launcher show a toast when it fails // to launch. mHotseats[i] = intent; @@ -471,7 +493,7 @@ public final class Launcher extends Activity break; } } - + if (!found) { if (LOGD) Log.d(TAG, "Multiple options, no default yet"); // the bestMatch is probably the ResolveActivity, meaning the @@ -496,8 +518,8 @@ public final class Launcher extends Activity } if (LOGD) { - Log.d(TAG, "loadHotseats: hotseat " + i - + " final intent=[" + Log.d(TAG, "loadHotseats: hotseat " + i + + " final intent=[" + ((mHotseats[i] == null) ? "null" : mHotseats[i].toUri(Intent.URI_INTENT_SCHEME)) @@ -712,7 +734,7 @@ public final class Launcher extends Activity mAllAppsGrid.setDragController(dragController); ((View) mAllAppsGrid).setWillNotDraw(false); // We don't want a hole punched in our window. // Manage focusability manually since this thing is always visible - ((View) mAllAppsGrid).setFocusable(false); + ((View) mAllAppsGrid).setFocusable(false); mWorkspace = (Workspace) dragLayer.findViewById(R.id.workspace); final Workspace workspace = mWorkspace; @@ -757,7 +779,7 @@ public final class Launcher extends Activity deleteZone.setLauncher(this); deleteZone.setDragController(dragController); - int deleteZoneHandleId = isScreenXLarge() ? R.id.add_button : R.id.all_apps_button_cluster; + int deleteZoneHandleId = LauncherApplication.isScreenXLarge() ? R.id.add_button : R.id.all_apps_button_cluster; deleteZone.setHandle(findViewById(deleteZoneHandleId)); dragController.setDragScoller(workspace); @@ -805,7 +827,7 @@ public final class Launcher extends Activity ); } } - + /** * Creates a view representing a shortcut. * @@ -1048,7 +1070,7 @@ public final class Launcher extends Activity unbindDesktopItems(); getContentResolver().unregisterContentObserver(mWidgetObserver); - + dismissPreview(mPreviousView); dismissPreview(mNextView); @@ -1179,11 +1201,6 @@ public final class Launcher extends Activity showAddDialog(mMenuAddInfo); } - boolean isScreenXLarge() { - int screenLayout = getResources().getConfiguration().screenLayout; - return (screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE; - } - void addAppWidgetFromDrop(ComponentName appWidgetProvider, CellLayout.CellInfo cellInfo) { mAddItemCellInfo = cellInfo; int appWidgetId = getAppWidgetHost().allocateAppWidgetId(); @@ -1518,7 +1535,7 @@ public final class Launcher extends Activity + "tag="+ tag + " intent=" + intent, e); } } - + void startActivityForResultSafely(Intent intent, int requestCode) { try { startActivityForResult(intent, requestCode); @@ -1563,7 +1580,7 @@ public final class Launcher extends Activity * * @param folderInfo The FolderInfo describing the folder to open. */ - private void openFolder(FolderInfo folderInfo) { + public void openFolder(FolderInfo folderInfo) { Folder openFolder; if (folderInfo instanceof UserFolderInfo) { @@ -1580,7 +1597,8 @@ public final class Launcher extends Activity openFolder.bind(folderInfo); folderInfo.opened = true; - mWorkspace.addInScreen(openFolder, folderInfo.screen, 0, 0, 4, 4); + mWorkspace.addInFullScreen(openFolder, folderInfo.screen); + openFolder.onOpen(); } @@ -1678,9 +1696,9 @@ public final class Launcher extends Activity final Workspace workspace = mWorkspace; CellLayout cell = ((CellLayout) workspace.getChildAt(start)); - + float max = workspace.getChildCount(); - + final Rect r = new Rect(); resources.getDrawable(R.drawable.preview_background).getPadding(r); int extraW = (int) ((r.left + r.right) * max); @@ -1731,7 +1749,7 @@ public final class Launcher extends Activity preview.addView(image, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); - bitmaps.add(bitmap); + bitmaps.add(bitmap); } final PopupWindow p = new PopupWindow(this); @@ -1752,7 +1770,7 @@ public final class Launcher extends Activity anchor.setTag(p); anchor.setTag(R.id.workspace, preview); - anchor.setTag(R.id.icon, bitmaps); + anchor.setTag(R.id.icon, bitmaps); } class PreviewTouchHandler implements View.OnClickListener, Runnable, View.OnFocusChangeListener { @@ -1768,7 +1786,7 @@ public final class Launcher extends Activity } public void run() { - dismissPreview(mAnchor); + dismissPreview(mAnchor); } public void onFocusChange(View v, boolean hasFocus) { @@ -1939,7 +1957,7 @@ public final class Launcher extends Activity ((View) mAllAppsGrid).setFocusable(true); ((View) mAllAppsGrid).requestFocus(); - + // TODO: fade these two too mDeleteZone.setVisibility(View.GONE); } @@ -2100,7 +2118,7 @@ public final class Launcher extends Activity } public void onShow(DialogInterface dialog) { - mWaitingForResult = true; + mWaitingForResult = true; } } diff --git a/src/com/android/launcher2/LauncherApplication.java b/src/com/android/launcher2/LauncherApplication.java index eda92d999..ca08378d8 100644 --- a/src/com/android/launcher2/LauncherApplication.java +++ b/src/com/android/launcher2/LauncherApplication.java @@ -20,6 +20,7 @@ import android.app.Application; import android.content.ContentResolver; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Configuration; import android.database.ContentObserver; import android.os.Handler; import dalvik.system.VMRuntime; @@ -27,6 +28,8 @@ import dalvik.system.VMRuntime; public class LauncherApplication extends Application { public LauncherModel mModel; public IconCache mIconCache; + private static boolean sIsScreenXLarge; + private static final boolean ENABLE_ROTATION = false; @Override public void onCreate() { @@ -36,6 +39,7 @@ public class LauncherApplication extends Application { mIconCache = new IconCache(this); mModel = new LauncherModel(this, mIconCache); + sIsScreenXLarge = (getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) == Configuration.SCREENLAYOUT_SIZE_XLARGE; // Register intent receivers IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); @@ -89,4 +93,12 @@ public class LauncherApplication extends Application { LauncherModel getModel() { return mModel; } + + public static boolean isInPlaceRotationEnabled() { + return sIsScreenXLarge && ENABLE_ROTATION; + } + + public static boolean isScreenXLarge() { + return sIsScreenXLarge; + } } diff --git a/src/com/android/launcher2/LauncherModel.java b/src/com/android/launcher2/LauncherModel.java index eb341f68a..238fbdfe7 100644 --- a/src/com/android/launcher2/LauncherModel.java +++ b/src/com/android/launcher2/LauncherModel.java @@ -16,6 +16,15 @@ package com.android.launcher2; +import java.lang.ref.WeakReference; +import java.net.URISyntaxException; +import java.text.Collator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; + import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; import android.content.BroadcastReceiver; @@ -23,9 +32,9 @@ import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.ContentValues; +import android.content.Context; import android.content.Intent; import android.content.Intent.ShortcutIconResource; -import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ProviderInfo; @@ -38,20 +47,10 @@ import android.net.Uri; import android.os.Handler; import android.os.HandlerThread; import android.os.Parcelable; -import android.os.RemoteException; -import android.util.Log; import android.os.Process; +import android.os.RemoteException; import android.os.SystemClock; - -import java.lang.ref.WeakReference; -import java.net.URISyntaxException; -import java.text.Collator; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Comparator; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; +import android.util.Log; import com.android.launcher.R; @@ -91,6 +90,8 @@ public class LauncherModel extends BroadcastReceiver { private Bitmap mDefaultIcon; + private static LauncherModelOrientationHelper mModelOrientationHelper; + public interface Callbacks { public int getCurrentWorkspaceScreen(); public void startBinding(); @@ -109,6 +110,7 @@ public class LauncherModel extends BroadcastReceiver { mApp = app; mAllAppsList = new AllAppsList(iconCache); mIconCache = iconCache; + mModelOrientationHelper = new LauncherModelOrientationHelper(mApp); mDefaultIcon = Utilities.createIconBitmap( app.getPackageManager().getDefaultActivityIcon(), app); @@ -141,11 +143,20 @@ public class LauncherModel extends BroadcastReceiver { } } + static int getCurrentOrientation() { + return mModelOrientationHelper.getCurrentOrientation(); + } + + static int getPreviousOrientationRelativeToCurrent() { + return mModelOrientationHelper.getPreviousOrientationRelativeToCurrent(); + } + /** * Move an item in the DB to a new */ static void moveItemInDatabase(Context context, ItemInfo item, long container, int screen, int cellX, int cellY) { + item.container = container; item.screen = screen; item.cellX = cellX; @@ -153,10 +164,11 @@ public class LauncherModel extends BroadcastReceiver { final ContentValues values = new ContentValues(); final ContentResolver cr = context.getContentResolver(); + final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item); values.put(LauncherSettings.Favorites.CONTAINER, item.container); - values.put(LauncherSettings.Favorites.CELLX, item.cellX); - values.put(LauncherSettings.Favorites.CELLY, item.cellY); + values.put(LauncherSettings.Favorites.CELLX, coord.x); + values.put(LauncherSettings.Favorites.CELLY, coord.y); values.put(LauncherSettings.Favorites.SCREEN, item.screen); cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null); @@ -180,6 +192,48 @@ public class LauncherModel extends BroadcastReceiver { return result; } + /** + * Returns an ItemInfo array containing all the items in the LauncherModel. + * The ItemInfo.id is not set through this function. + */ + static ArrayList getItemsInLocalCoordinates(Context context) { + ArrayList items = new ArrayList(); + final ContentResolver cr = context.getContentResolver(); + Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, new String[] { + LauncherSettings.Favorites.ITEM_TYPE, LauncherSettings.Favorites.CONTAINER, + LauncherSettings.Favorites.SCREEN, LauncherSettings.Favorites.CELLX, LauncherSettings.Favorites.CELLY, + LauncherSettings.Favorites.SPANX, LauncherSettings.Favorites.SPANY }, null, null, null); + + final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE); + final int containerIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CONTAINER); + final int screenIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SCREEN); + final int cellXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLX); + final int cellYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.CELLY); + final int spanXIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANX); + final int spanYIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.SPANY); + + try { + while (c.moveToNext()) { + ItemInfo item = new ItemInfo(); + item.cellX = c.getInt(cellXIndex); + item.cellY = c.getInt(cellYIndex); + item.spanX = c.getInt(spanXIndex); + item.spanY = c.getInt(spanYIndex); + item.container = c.getInt(containerIndex); + item.itemType = c.getInt(itemTypeIndex); + item.screen = c.getInt(screenIndex); + + items.add(item); + } + } catch (Exception e) { + items.clear(); + } finally { + c.close(); + } + + return items; + } + /** * Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList. */ @@ -210,12 +264,13 @@ public class LauncherModel extends BroadcastReceiver { break; } + final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getLocalCoordinates(c.getInt(cellXIndex), c.getInt(cellYIndex), 1, 1); folderInfo.title = c.getString(titleIndex); folderInfo.id = id; folderInfo.container = c.getInt(containerIndex); folderInfo.screen = c.getInt(screenIndex); - folderInfo.cellX = c.getInt(cellXIndex); - folderInfo.cellY = c.getInt(cellYIndex); + folderInfo.cellX = coord.x; + folderInfo.cellY = coord.y; return folderInfo; } @@ -239,9 +294,12 @@ public class LauncherModel extends BroadcastReceiver { final ContentValues values = new ContentValues(); final ContentResolver cr = context.getContentResolver(); - item.onAddToDatabase(values); + // update the values to be written with their canonical counterparts + final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item); + item.updateValuesWithCoordinates(values, coord.x, coord.y); + Uri result = cr.insert(notify ? LauncherSettings.Favorites.CONTENT_URI : LauncherSettings.Favorites.CONTENT_URI_NO_NOTIFICATION, values); @@ -250,6 +308,44 @@ public class LauncherModel extends BroadcastReceiver { } } + /** + * Creates a new unique child id, for a given cell span across all layouts. + */ + static int getCanonicalCellLayoutChildId(int cellId, int screen, int localCellX, int localCellY, int spanX, int spanY) { + if (LauncherApplication.isInPlaceRotationEnabled()) { + LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(localCellX, localCellY, spanX, spanY); + return ((screen & 0xFF) << 16) | (coord.x & 0xFF) << 8 | (coord.y & 0xFF); + } else { + return ((cellId & 0xFF) << 16) | (localCellX & 0xFF) << 8 | (localCellY & 0xFF); + } + } + + /* + * Convenience functions to help return the local device width and height. + */ + static int getLocalDeviceWidth() { + return mModelOrientationHelper.getLocalDeviceWidth(); + } + + static int getLocalDeviceHeight() { + return mModelOrientationHelper.getLocalDeviceHeight(); + } + + /** + * Return the new local coordinates given the local coordinates from the previous orientation. + */ + static LauncherModelOrientationHelper.Coordinates getLocalCoordinatesFromPreviousLocalCoordinates(CellLayout.LayoutParams lp) { + return mModelOrientationHelper.getLocalCoordinatesFromPreviousLocalCoordinates(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan); + } + + /** + * Updates the model orientation helper to take into account the current layout dimensions + * when performing local/canonical coordinate transformations. + */ + static void updateWorkspaceLayoutCells(int shortAxisCellCount, int longAxisCellCount) { + mModelOrientationHelper.updateDeviceDimensions(shortAxisCellCount, longAxisCellCount); + } + /** * Update an item to the database in a specified container. */ @@ -259,6 +355,10 @@ public class LauncherModel extends BroadcastReceiver { item.onAddToDatabase(values); + // update the values to be written with their canonical counterparts + final LauncherModelOrientationHelper.Coordinates coord = mModelOrientationHelper.getCanonicalCoordinates(item); + item.updateValuesWithCoordinates(values, coord.x, coord.y); + cr.update(LauncherSettings.Favorites.getContentUri(item.id, false), values, null, null); } @@ -293,13 +393,18 @@ public class LauncherModel extends BroadcastReceiver { } } + public void updateOrientation() { + // we update the LauncherModelOrientationHelper orientation whenever we re-initialize + mModelOrientationHelper.updateOrientation(mApp); + } + /** * Call from the handler for ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED and * ACTION_PACKAGE_CHANGED. */ public void onReceive(Context context, Intent intent) { if (DEBUG_LOADERS) Log.d(TAG, "onReceive intent=" + intent); - + final String action = intent.getAction(); if (Intent.ACTION_PACKAGE_CHANGED.equals(action) @@ -343,7 +448,6 @@ public class LauncherModel extends BroadcastReceiver { String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); enqueuePackageUpdated(new PackageUpdatedTask( PackageUpdatedTask.OP_UNAVAILABLE, packages)); - } } @@ -449,7 +553,7 @@ public class LauncherModel extends BroadcastReceiver { } if (DEBUG_LOADERS) { Log.d(TAG, "waited " - + (SystemClock.uptimeMillis()-workspaceWaitTime) + + (SystemClock.uptimeMillis()-workspaceWaitTime) + "ms for previous step to finish binding"); } } @@ -469,7 +573,6 @@ public class LauncherModel extends BroadcastReceiver { android.os.Process.setThreadPriority(mIsLaunching ? Process.THREAD_PRIORITY_DEFAULT : Process.THREAD_PRIORITY_BACKGROUND); } - if (loadWorkspaceFirst) { if (DEBUG_LOADERS) Log.d(TAG, "step 1: loading workspace"); loadAndBindWorkspace(); @@ -571,14 +674,13 @@ public class LauncherModel extends BroadcastReceiver { if (item.container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { return true; } - for (int x = item.cellX; x < (item.cellX+item.spanX); x++) { for (int y = item.cellY; y < (item.cellY+item.spanY); y++) { if (occupied[item.screen][x][y] != null) { Log.e(TAG, "Error loading shortcut " + item - + " into cell (" + item.screen + ":" + + " into cell (" + item.screen + ":" + x + "," + y - + ") occupied by " + + ") occupied by " + occupied[item.screen][x][y]); return false; } @@ -645,6 +747,11 @@ public class LauncherModel extends BroadcastReceiver { final int displayModeIndex = c.getColumnIndexOrThrow( LauncherSettings.Favorites.DISPLAY_MODE); + + LauncherModelOrientationHelper.Coordinates localCoords; + int cellX; + int cellY; + ShortcutInfo info; String intentDescription; LauncherAppWidgetInfo appWidgetInfo; @@ -678,13 +785,17 @@ public class LauncherModel extends BroadcastReceiver { if (info != null) { updateSavedIcon(context, info, c, iconIndex); + cellX = c.getInt(cellXIndex); + cellY = c.getInt(cellYIndex); + localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1); + info.intent = intent; info.id = c.getLong(idIndex); container = c.getInt(containerIndex); info.container = container; info.screen = c.getInt(screenIndex); - info.cellX = c.getInt(cellXIndex); - info.cellY = c.getInt(cellYIndex); + info.cellX = localCoords.x; + info.cellY = localCoords.y; // check & update map of what's occupied if (!checkItemPlacement(occupied, info)) { @@ -718,20 +829,22 @@ public class LauncherModel extends BroadcastReceiver { id = c.getLong(idIndex); UserFolderInfo folderInfo = findOrMakeUserFolder(mFolders, id); - folderInfo.title = c.getString(titleIndex); + cellX = c.getInt(cellXIndex); + cellY = c.getInt(cellYIndex); + localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1); + folderInfo.title = c.getString(titleIndex); folderInfo.id = id; container = c.getInt(containerIndex); folderInfo.container = container; folderInfo.screen = c.getInt(screenIndex); - folderInfo.cellX = c.getInt(cellXIndex); - folderInfo.cellY = c.getInt(cellYIndex); + folderInfo.cellX = localCoords.x; + folderInfo.cellY = localCoords.y; // check & update map of what's occupied if (!checkItemPlacement(occupied, folderInfo)) { break; } - switch (container) { case LauncherSettings.Favorites.CONTAINER_DESKTOP: mItems.add(folderInfo); @@ -754,7 +867,6 @@ public class LauncherModel extends BroadcastReceiver { itemsToRemove.add(id); } else { LiveFolderInfo liveFolderInfo = findOrMakeLiveFolder(mFolders, id); - intentDescription = c.getString(intentIndex); intent = null; if (intentDescription != null) { @@ -765,14 +877,18 @@ public class LauncherModel extends BroadcastReceiver { } } + cellX = c.getInt(cellXIndex); + cellY = c.getInt(cellYIndex); + localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, 1, 1); + liveFolderInfo.title = c.getString(titleIndex); liveFolderInfo.id = id; liveFolderInfo.uri = uri; container = c.getInt(containerIndex); liveFolderInfo.container = container; liveFolderInfo.screen = c.getInt(screenIndex); - liveFolderInfo.cellX = c.getInt(cellXIndex); - liveFolderInfo.cellY = c.getInt(cellYIndex); + liveFolderInfo.cellX = localCoords.x; + liveFolderInfo.cellY = localCoords.y; liveFolderInfo.baseIntent = intent; liveFolderInfo.displayMode = c.getInt(displayModeIndex); @@ -800,20 +916,26 @@ public class LauncherModel extends BroadcastReceiver { final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(appWidgetId); - + if (!isSafeMode && (provider == null || provider.provider == null || provider.provider.getPackageName() == null)) { Log.e(TAG, "Deleting widget that isn't installed anymore: id=" + id + " appWidgetId=" + appWidgetId); itemsToRemove.add(id); } else { + cellX = c.getInt(cellXIndex); + cellY = c.getInt(cellYIndex); + int spanX = c.getInt(spanXIndex); + int spanY = c.getInt(spanYIndex); + localCoords = mModelOrientationHelper.getLocalCoordinates(cellX, cellY, spanX, spanY); + appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId); appWidgetInfo.id = id; appWidgetInfo.screen = c.getInt(screenIndex); - appWidgetInfo.cellX = c.getInt(cellXIndex); - appWidgetInfo.cellY = c.getInt(cellYIndex); - appWidgetInfo.spanX = c.getInt(spanXIndex); - appWidgetInfo.spanY = c.getInt(spanYIndex); + appWidgetInfo.cellX = localCoords.x; + appWidgetInfo.cellY = localCoords.y; + appWidgetInfo.spanX = spanX; + appWidgetInfo.spanY = spanY; container = c.getInt(containerIndex); if (container != LauncherSettings.Favorites.CONTAINER_DESKTOP) { diff --git a/src/com/android/launcher2/LauncherModelOrientationHelper.java b/src/com/android/launcher2/LauncherModelOrientationHelper.java new file mode 100644 index 000000000..6a9473d86 --- /dev/null +++ b/src/com/android/launcher2/LauncherModelOrientationHelper.java @@ -0,0 +1,180 @@ +/* + * 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.content.Context; +import android.view.Display; +import android.view.Surface; +import android.view.WindowManager; + +public class LauncherModelOrientationHelper { + + static final String TAG = "LauncherModelOrientationHelper"; + + public class Coordinates { + public Coordinates(int newX, int newY) { + x = newX; + y = newY; + } + + public int x; + public int y; + } + + private int mOrientation; + private int mLocalDeviceWidth; + private int mLocalDeviceHeight; + private int mPreviousOrientation; + private int mPreviousLocalDeviceWidth; + private int mPreviousLocalDeviceHeight; + private int mCanonicalDeviceWidth; + private int mCanonicalDeviceHeight; + + protected LauncherModelOrientationHelper(Context ctx) { + updateOrientation(ctx); + } + + public int getCurrentOrientation() { + return mOrientation; + } + + public int getPreviousOrientationRelativeToCurrent() { + int orientationDifference = -(mOrientation - mPreviousOrientation); + + if (Math.abs(orientationDifference) > 180) { + orientationDifference = (int) -Math.signum(orientationDifference) + * (360 - Math.abs(orientationDifference)); + } + return orientationDifference; + } + + private void updateLocalDeviceDimensions() { + mPreviousLocalDeviceHeight = mLocalDeviceHeight; + mPreviousLocalDeviceWidth = mLocalDeviceWidth; + + if (mOrientation % 180 != 0) { + mLocalDeviceWidth = mCanonicalDeviceHeight; + mLocalDeviceHeight = mCanonicalDeviceWidth; + } else { + mLocalDeviceWidth = mCanonicalDeviceWidth; + mLocalDeviceHeight = mCanonicalDeviceHeight; + } + } + + public void updateOrientation(Context ctx) { + Display display = ((WindowManager) ctx + .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); + + mPreviousOrientation = mOrientation; + switch (display.getRotation()) { + case Surface.ROTATION_0: + mOrientation = 0; + break; + case Surface.ROTATION_90: + mOrientation = 90; + break; + case Surface.ROTATION_180: + mOrientation = 180; + break; + case Surface.ROTATION_270: + mOrientation = 270; + break; + } + updateLocalDeviceDimensions(); + } + + public void updateDeviceDimensions(int deviceWidth, int deviceHeight) { + mCanonicalDeviceWidth = deviceWidth; + mCanonicalDeviceHeight = deviceHeight; + + updateLocalDeviceDimensions(); + } + + public Coordinates getLocalCoordinatesFromPreviousLocalCoordinates( + int cellX, int cellY, int spanX, int spanY) { + return getTransformedLayoutParams(cellX, cellY, spanX, spanY, + getPreviousOrientationRelativeToCurrent(), + mPreviousLocalDeviceWidth, mPreviousLocalDeviceHeight); + } + + public Coordinates getCanonicalCoordinates(ItemInfo localItem) { + return getTransformedLayoutParams(localItem.cellX, localItem.cellY, + localItem.spanX, localItem.spanY, mOrientation, + mLocalDeviceWidth, mLocalDeviceHeight); + } + + public Coordinates getCanonicalCoordinates(int cellX, int cellY, + int spanX, int spanY) { + return getTransformedLayoutParams(cellX, cellY, spanX, spanY, + mOrientation, mLocalDeviceWidth, mLocalDeviceHeight); + } + + public Coordinates getLocalCoordinates(int cellX, int cellY, int spanX, + int spanY) { + return getTransformedLayoutParams(cellX, cellY, spanX, spanY, + -mOrientation, mCanonicalDeviceWidth, mCanonicalDeviceHeight); + } + + public int getLocalDeviceWidth() { + return mLocalDeviceWidth; + } + + public int getLocalDeviceHeight() { + return mLocalDeviceHeight; + } + + /** + * Transform the coordinates based on the current device rotation + */ + private Coordinates getTransformedLayoutParams(int cellX, int cellY, + int spanX, int spanY, int deviceRotationClockwise, + int initialDeviceWidth, int initialDeviceHeight) { + if (LauncherApplication.isScreenXLarge()) { + int x = cellX; + int y = cellY; + int width = spanX; + int height = spanY; + int finalDeviceWidth = initialDeviceWidth; + int finalDeviceHeight = initialDeviceHeight; + + // item rotation is opposite of device rotation to maintain an + // absolute + // spatial layout + double phi = Math.toRadians(-deviceRotationClockwise); + + double x1 = x + width / 2.0f - initialDeviceWidth / 2.0f; + double y1 = y + height / 2.0f - initialDeviceHeight / 2.0f; + + // multiply x and y by a clockwise rotation matrix + double x2 = x1 * Math.cos(phi) + y1 * Math.sin(phi); + double y2 = -x1 * Math.sin(phi) + y1 * Math.cos(phi); + + // Get the rotated device dimensions + if (deviceRotationClockwise % 180 != 0) { + finalDeviceWidth = initialDeviceHeight; + finalDeviceHeight = initialDeviceWidth; + } + + x2 = x2 + finalDeviceWidth / 2.0f - width / 2.0f; + y2 = y2 + finalDeviceHeight / 2.0f - height / 2.0f; + + return new Coordinates((int) Math.round(x2), (int) Math.round(y2)); + } else { + return new Coordinates(cellX, cellY); + } + } +} diff --git a/src/com/android/launcher2/LiveFolderInfo.java b/src/com/android/launcher2/LiveFolderInfo.java index 7d0a0f58f..74b021758 100644 --- a/src/com/android/launcher2/LiveFolderInfo.java +++ b/src/com/android/launcher2/LiveFolderInfo.java @@ -18,7 +18,6 @@ package com.android.launcher2; import android.content.ContentValues; import android.content.Intent; -import android.graphics.drawable.Drawable; import android.graphics.Bitmap; import android.net.Uri; diff --git a/src/com/android/launcher2/ScriptField_VpConsts.java b/src/com/android/launcher2/ScriptField_VpConsts.java index b5e41b780..ff183f4aa 100644 --- a/src/com/android/launcher2/ScriptField_VpConsts.java +++ b/src/com/android/launcher2/ScriptField_VpConsts.java @@ -19,6 +19,11 @@ package com.android.launcher2; import android.renderscript.*; import android.content.res.Resources; import android.util.Log; +import android.renderscript.Element; +import android.renderscript.FieldPacker; +import android.renderscript.Float2; +import android.renderscript.Float4; +import android.renderscript.RenderScript; public class ScriptField_VpConsts extends android.renderscript.Script.FieldBase { static public class Item { diff --git a/src/com/android/launcher2/ShortcutInfo.java b/src/com/android/launcher2/ShortcutInfo.java index 5c322baaa..b0da3a5b9 100644 --- a/src/com/android/launcher2/ShortcutInfo.java +++ b/src/com/android/launcher2/ShortcutInfo.java @@ -16,16 +16,14 @@ package com.android.launcher2; +import java.util.ArrayList; + import android.content.ComponentName; import android.content.ContentValues; -import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; -import android.graphics.drawable.Drawable; import android.util.Log; -import java.util.ArrayList; - /** * Represents a launchable icon on the workspaces and in folders. */ diff --git a/src/com/android/launcher2/ShortcutsAdapter.java b/src/com/android/launcher2/ShortcutsAdapter.java index 19c3af0a8..93c500a44 100644 --- a/src/com/android/launcher2/ShortcutsAdapter.java +++ b/src/com/android/launcher2/ShortcutsAdapter.java @@ -16,16 +16,15 @@ package com.android.launcher2; +import java.util.ArrayList; + import android.content.Context; -import android.content.pm.PackageManager; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; -import java.util.ArrayList; - import com.android.launcher.R; /** diff --git a/src/com/android/launcher2/SymmetricalLinearTween.java b/src/com/android/launcher2/SymmetricalLinearTween.java index 2e0ed8f03..da02242c8 100644 --- a/src/com/android/launcher2/SymmetricalLinearTween.java +++ b/src/com/android/launcher2/SymmetricalLinearTween.java @@ -17,9 +17,7 @@ package com.android.launcher2; import android.os.Handler; -import android.os.Message; import android.os.SystemClock; -import android.util.Log; /** * Provides an animation between 0.0f and 1.0f over a given duration. diff --git a/src/com/android/launcher2/UserFolder.java b/src/com/android/launcher2/UserFolder.java index d49c27aea..255099f3b 100644 --- a/src/com/android/launcher2/UserFolder.java +++ b/src/com/android/launcher2/UserFolder.java @@ -3,10 +3,8 @@ package com.android.launcher2; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; -import android.widget.ArrayAdapter; import com.android.launcher.R; diff --git a/src/com/android/launcher2/Utilities.java b/src/com/android/launcher2/Utilities.java index 757e48e30..c67ff99de 100644 --- a/src/com/android/launcher2/Utilities.java +++ b/src/com/android/launcher2/Utilities.java @@ -16,9 +16,8 @@ package com.android.launcher2; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.PaintDrawable; +import android.content.Context; +import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.Canvas; @@ -26,19 +25,19 @@ import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; -import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.TableMaskFilter; import android.graphics.Typeface; -import android.text.Layout.Alignment; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.PaintDrawable; import android.text.StaticLayout; import android.text.TextPaint; +import android.text.Layout.Alignment; import android.util.DisplayMetrics; import android.util.Log; -import android.content.res.Resources; -import android.content.Context; import com.android.launcher.R; diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java index c56a313e1..0f41cc9d9 100644 --- a/src/com/android/launcher2/Workspace.java +++ b/src/com/android/launcher2/Workspace.java @@ -42,7 +42,10 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewParent; +import android.view.animation.Animation; import android.view.animation.Interpolator; +import android.view.animation.RotateAnimation; +import android.view.animation.Animation.AnimationListener; import android.widget.Scroller; import android.widget.TextView; @@ -50,22 +53,23 @@ import java.util.ArrayList; import java.util.HashSet; /** - * The workspace is a wide area with a wallpaper and a finite number of screens. Each - * 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. + * The workspace is a wide area with a wallpaper and a finite number of screens. + * Each 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 { @SuppressWarnings({"UnusedDeclaration"}) private static final String TAG = "Launcher.Workspace"; private static final int INVALID_SCREEN = -1; - + /** - * The velocity at which a fling gesture will cause us to snap to the next screen + * The velocity at which a fling gesture will cause us to snap to the next + * screen */ private static final int SNAP_VELOCITY = 600; private final WallpaperManager mWallpaperManager; - + private int mDefaultScreen; private boolean mFirstLayout = true; @@ -79,7 +83,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag * CellInfo for the cell that is currently being dragged */ private CellLayout.CellInfo mDragInfo; - + /** * Target drop area calculated during last acceptDrop call. */ @@ -87,7 +91,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private float mLastMotionX; private float mLastMotionY; - + private final static int TOUCH_STATE_REST = 0; private final static int TOUCH_STATE_SCROLLING = 1; @@ -98,12 +102,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private Launcher mLauncher; private IconCache mIconCache; private DragController mDragController; - + /** * Cache of vacant cells, used during drag events and invalidated as needed. */ private CellLayout.CellInfo mVacantCache = null; - + private int[] mTempCell = new int[2]; private int[] mTempEstimate = new int[2]; @@ -111,14 +115,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private int mTouchSlop; private int mMaximumVelocity; - + private static final int INVALID_POINTER = -1; private int mActivePointerId = INVALID_POINTER; - + private Drawable mPreviousIndicator; private Drawable mNextIndicator; - + private static final float NANOTIME_DIV = 1000000000.0f; private static final float SMOOTHING_SPEED = 0.75f; private static final float SMOOTHING_CONSTANT = (float) (0.016 / Math.log(SMOOTHING_SPEED)); @@ -129,7 +133,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag private static final float BASELINE_FLING_VELOCITY = 2500.f; private static final float FLING_VELOCITY_INFLUENCE = 0.4f; - + private static class WorkspaceOvershootInterpolator implements Interpolator { private static final float DEFAULT_TENSION = 1.3f; private float mTension; @@ -137,7 +141,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag public WorkspaceOvershootInterpolator() { mTension = DEFAULT_TENSION; } - + public void setDistance(int distance) { mTension = distance > 0 ? DEFAULT_TENSION / distance : DEFAULT_TENSION; } @@ -153,7 +157,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag return t * t * ((mTension + 1) * t + mTension) + 1.0f; } } - + /** * Used to inflate the Workspace from XML. * @@ -175,11 +179,16 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag super(context, attrs, defStyle); mWallpaperManager = WallpaperManager.getInstance(context); - - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Workspace, defStyle, 0); + + TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.Workspace, defStyle, 0); + int canonicalDeviceWidth = a.getInt(R.styleable.Workspace_canonicalDeviceWidth, 4); + int canonicalDeviceHeight = a.getInt(R.styleable.Workspace_canonicalDeviceHeight, 4); mDefaultScreen = a.getInt(R.styleable.Workspace_defaultScreen, 1); a.recycle(); + LauncherModel.updateWorkspaceLayoutCells(canonicalDeviceWidth, + canonicalDeviceHeight); setHapticFeedbackEnabled(false); initWorkspace(); } @@ -249,9 +258,10 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag int count = currentScreen.getChildCount(); for (int i = 0; i < count; i++) { View child = currentScreen.getChildAt(i); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); - if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { - return (Folder) child; + if (child instanceof Folder) { + Folder folder = (Folder) child; + if (folder.getInfo().opened) + return folder; } } return null; @@ -266,9 +276,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag int count = currentScreen.getChildCount(); for (int i = 0; i < count; i++) { View child = currentScreen.getChildAt(i); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); - if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { - folders.add((Folder) child); + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child + .getLayoutParams(); + if (child instanceof Folder) { + Folder folder = (Folder) child; + if (folder.getInfo().opened) + folders.add(folder); break; } } @@ -296,11 +309,15 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag * @param currentScreen */ void setCurrentScreen(int currentScreen) { - if (!mScroller.isFinished()) mScroller.abortAnimation(); + if (!mScroller.isFinished()) + mScroller.abortAnimation(); clearVacantCache(); mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1)); - mPreviousIndicator.setLevel(mCurrentScreen); - mNextIndicator.setLevel(mCurrentScreen); + if (mPreviousIndicator != null) { + mPreviousIndicator.setLevel(mCurrentScreen); + mNextIndicator.setLevel(mCurrentScreen); + } + scrollTo(mCurrentScreen * getWidth(), 0); updateWallpaperOffset(); invalidate(); @@ -350,6 +367,85 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag addInScreen(child, screen, x, y, spanX, spanY, false); } + void addInFullScreen(View child, int screen) { + addInScreen(child, screen, 0, 0, -1, -1); + } + + public void rotateCurrentScreensChildren() { + + // close all the folders first + final ArrayList openFolders = getOpenFolders(); + + WorkspaceOvershootInterpolator wi = new WorkspaceOvershootInterpolator(); + RotateAnimation ra = new RotateAnimation((float) LauncherModel + .getPreviousOrientationRelativeToCurrent(), 0, + Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, + 0.5f); + ra.setInterpolator(wi); + CellLayout currentScreen = (CellLayout) getChildAt(mCurrentScreen); + ra.setStartOffset(150); + ra.setDuration(650 + (int) (Math.random() * 400) - 200); + + CellLayout.CellLayoutAnimationController animationController = new CellLayout.CellLayoutAnimationController( + ra, 0.0f); + currentScreen.setLayoutAnimation(animationController); + currentScreen.setLayoutAnimationListener(new AnimationListener() { + public void onAnimationStart(Animation animation) { + // do nothing + } + + public void onAnimationRepeat(Animation animation) { + // do nothing + } + + public void onAnimationEnd(Animation animation) { + for (int j = 0; j < openFolders.size(); ++j) { + Folder folder = openFolders.get(j); + if (!folder.getInfo().opened) { + mLauncher.openFolder(folder.getInfo()); + } + } + } + }); + animationController.start(); + + for (int j = 0; j < openFolders.size(); ++j) { + mLauncher.closeFolder(openFolders.get(j)); + } + } + + public void refreshWorkspaceChildren() { + final int count = getChildCount(); + View child; + + CellLayout.LayoutParams lp; + int widthMeasureSpec = MeasureSpec.makeMeasureSpec(LauncherModel + .getLocalDeviceWidth(), MeasureSpec.EXACTLY); + int heightMeasureSpec = MeasureSpec.makeMeasureSpec(LauncherModel + .getLocalDeviceHeight(), MeasureSpec.EXACTLY); + + clearVacantCache(); + + for (int i = 0; i < count; i++) { + final CellLayout layout = (CellLayout) getChildAt(i); + int numChildren = layout.getChildCount(); + + // save reference to all current children + for (int j = 0; j < numChildren; j++) { + child = layout.getChildAt(j); + + lp = (CellLayout.LayoutParams) child.getLayoutParams(); + LauncherModelOrientationHelper.Coordinates localCoord = LauncherModel + .getLocalCoordinatesFromPreviousLocalCoordinates(lp); + + lp.cellX = localCoord.x; + lp.cellY = localCoord.y; + } + + layout.measure(widthMeasureSpec, heightMeasureSpec); + } + } + /** * Adds the specified child in the specified screen. The position and dimension of * the child are defined by x, y, spanX and spanY. @@ -381,13 +477,23 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag lp.cellHSpan = spanX; lp.cellVSpan = spanY; } - group.addView(child, insert ? 0 : -1, lp); + + // get the canonical child id to uniquely represent this view in this + // screen + int childId = LauncherModel.getCanonicalCellLayoutChildId(child.getId(), screen, x, y, spanX, spanY); + if (!group.addViewToCellLayout(child, insert ? 0 : -1, childId, lp)) { + // TODO: This branch occurs when the workspace is adding views + // outside of the defined grid + // maybe we should be deleting these items from the LauncherMode? + Log.w(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout"); + } + if (!(child instanceof Folder)) { child.setHapticFeedbackEnabled(false); child.setOnLongClickListener(mLongClickListener); } if (child instanceof DropTarget) { - mDragController.addDropTarget((DropTarget)child); + mDragController.addDropTarget((DropTarget) child); } } @@ -432,14 +538,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag Math.max(0.f, Math.min(mScrollX/(float)scrollRange, 1.f)), 0); } } - + @Override public void scrollTo(int x, int y) { super.scrollTo(x, y); mTouchX = x; mSmoothingTime = System.nanoTime() / NANOTIME_DIV; } - + @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { @@ -531,7 +637,6 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } - if (mFirstLayout) { setHorizontalScrollBarEnabled(false); scrollTo(mCurrentScreen * width, 0); @@ -554,6 +659,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag childLeft += childWidth; } } + + if (LauncherApplication.isInPlaceRotationEnabled()) { + // When the device is rotated, the scroll position of the current screen + // needs to be refreshed + setCurrentScreen(getCurrentScreen()); + } } @Override @@ -613,7 +724,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (mCurrentScreen > 0) { getChildAt(mCurrentScreen - 1).addFocusables(views, direction); } - } else if (direction == View.FOCUS_RIGHT){ + } else if (direction == View.FOCUS_RIGHT) { if (mCurrentScreen < getChildCount() - 1) { getChildAt(mCurrentScreen + 1).addFocusables(views, direction); } @@ -662,7 +773,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); - + switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_MOVE: { /* @@ -683,9 +794,9 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag final int touchSlop = mTouchSlop; boolean xMoved = xDiff > touchSlop; boolean yMoved = yDiff > touchSlop; - + if (xMoved || yMoved) { - + if (xMoved) { // Scroll if the user moved far enough along the X axis mTouchState = TOUCH_STATE_SCROLLING; @@ -707,14 +818,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag break; } - case MotionEvent.ACTION_DOWN: { - final float x = ev.getX(); - final float y = ev.getY(); - // Remember location of down touch - mLastMotionX = x; - mLastMotionY = y; - mActivePointerId = ev.getPointerId(0); - mAllowLongPress = true; + case MotionEvent.ACTION_DOWN: { + final float x = ev.getX(); + final float y = ev.getY(); + // Remember location of down touch + mLastMotionX = x; + mLastMotionY = y; + mActivePointerId = ev.getPointerId(0); + mAllowLongPress = true; /* * If being flinged and user touches the screen, initiate drag; @@ -727,36 +838,36 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: - + if (mTouchState != TOUCH_STATE_SCROLLING) { final CellLayout currentScreen = (CellLayout)getChildAt(mCurrentScreen); if (!currentScreen.lastDownOnOccupiedCell()) { getLocationOnScreen(mTempCell); // Send a tap to the wallpaper if the last down was on empty space final int pointerIndex = ev.findPointerIndex(mActivePointerId); - mWallpaperManager.sendWallpaperCommand(getWindowToken(), + mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.wallpaper.tap", mTempCell[0] + (int) ev.getX(pointerIndex), mTempCell[1] + (int) ev.getY(pointerIndex), 0, null); } } - + // Release the drag clearChildrenCache(); mTouchState = TOUCH_STATE_REST; mActivePointerId = INVALID_POINTER; mAllowLongPress = false; - + if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } - break; - - case MotionEvent.ACTION_POINTER_UP: - onSecondaryPointerUp(ev); - break; + break; + + case MotionEvent.ACTION_POINTER_UP: + onSecondaryPointerUp(ev); + break; } /* @@ -765,7 +876,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag */ return mTouchState != TOUCH_STATE_REST; } - + private void onSecondaryPointerUp(MotionEvent ev) { final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; @@ -805,7 +916,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } ViewParent parent = v.getParent(); if (parent instanceof View) { - v = (View)v.getParent(); + v = (View) v.getParent(); } else { return; } @@ -818,7 +929,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag fromScreen = toScreen; toScreen = temp; } - + final int count = getChildCount(); fromScreen = Math.max(fromScreen, 0); @@ -841,7 +952,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag @Override public boolean onTouchEvent(MotionEvent ev) { - + if (mLauncher.isWorkspaceLocked()) { return false; // We don't want the events. Let them fall through to the all apps view. } @@ -910,11 +1021,11 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId); - + final int screenWidth = getWidth(); final int whichScreen = (mScrollX + (screenWidth / 2)) / screenWidth; final float scrolledPos = (float) mScrollX / screenWidth; - + if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) { // Fling hard enough to move left. // Don't fling across more than one screen at a time. @@ -950,24 +1061,24 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag return true; } - + void snapToScreen(int whichScreen) { snapToScreen(whichScreen, 0, false); } private void snapToScreen(int whichScreen, int velocity, boolean settle) { - //if (!mScroller.isFinished()) return; + // if (!mScroller.isFinished()) return; whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); - + clearVacantCache(); enableChildrenCache(mCurrentScreen, whichScreen); mNextScreen = whichScreen; if (mPreviousIndicator != null) { - mPreviousIndicator.setLevel(mNextScreen); - mNextIndicator.setLevel(mNextScreen); + mPreviousIndicator.setLevel(mNextScreen); + mNextIndicator.setLevel(mNextScreen); } View focusedChild = getFocusedChild(); @@ -975,7 +1086,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag focusedChild == getChildAt(mCurrentScreen)) { focusedChild.clearFocus(); } - + final int screenDelta = Math.max(1, Math.abs(whichScreen - mCurrentScreen)); final int newX = whichScreen * getWidth(); final int delta = newX - mScrollX; @@ -984,13 +1095,13 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (!mScroller.isFinished()) { mScroller.abortAnimation(); } - + if (settle) { mScrollInterpolator.setDistance(screenDelta); } else { mScrollInterpolator.disableSettle(); } - + velocity = Math.abs(velocity); if (velocity > 0) { duration += (duration / (velocity / BASELINE_FLING_VELOCITY)) @@ -1006,15 +1117,15 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag void startDrag(CellLayout.CellInfo cellInfo) { View child = cellInfo.cell; - + // Make sure the drag was started by a long press as opposed to a long click. if (!child.isInTouchMode()) { return; } - + mDragInfo = cellInfo; mDragInfo.screen = mCurrentScreen; - + CellLayout current = ((CellLayout) getChildAt(mCurrentScreen)); current.onDragChild(child); @@ -1061,44 +1172,53 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag // Move internally if (mDragInfo != null) { final View cell = mDragInfo.cell; - int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen; + int index = mScroller.isFinished() ? mCurrentScreen : mNextScreen; if (index != mDragInfo.screen) { final CellLayout originalCellLayout = (CellLayout) getChildAt(mDragInfo.screen); originalCellLayout.removeView(cell); - cellLayout.addView(cell); + addInScreen(cell, index, mDragInfo.cellX, mDragInfo.cellY, + mDragInfo.spanX, mDragInfo.spanY); } mTargetCell = estimateDropCell(x - xOffset, y - yOffset, - mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, mTargetCell); - cellLayout.onDropChild(cell, mTargetCell); + mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout, + mTargetCell); + cellLayout.onDropChild(cell); + // update the item's position after drop final ItemInfo info = (ItemInfo) cell.getTag(); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell.getLayoutParams(); + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) cell + .getLayoutParams(); + lp.cellX = mTargetCell[0]; + lp.cellY = mTargetCell[1]; + LauncherModel.moveItemInDatabase(mLauncher, info, - LauncherSettings.Favorites.CONTAINER_DESKTOP, index, lp.cellX, lp.cellY); + LauncherSettings.Favorites.CONTAINER_DESKTOP, index, + lp.cellX, lp.cellY); } } } - public void onDragEnter(DragSource source, int x, int y, int xOffset, int yOffset, - DragView dragView, Object dragInfo) { + public void onDragEnter(DragSource source, int x, int y, int xOffset, + int yOffset, DragView dragView, Object dragInfo) { clearVacantCache(); } - public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset, - DragView dragView, Object dragInfo) { + public void onDragOver(DragSource source, int x, int y, int xOffset, + int yOffset, DragView dragView, Object dragInfo) { } - public void onDragExit(DragSource source, int x, int y, int xOffset, int yOffset, - DragView dragView, Object dragInfo) { + public void onDragExit(DragSource source, int x, int y, int xOffset, + int yOffset, DragView dragView, Object dragInfo) { clearVacantCache(); } - private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout) { + private void onDropExternal(int x, int y, Object dragInfo, + CellLayout cellLayout) { onDropExternal(x, y, dragInfo, cellLayout, false); } - - private void onDropExternal(int x, int y, Object dragInfo, CellLayout cellLayout, - boolean insertAtFirst) { + + private void onDropExternal(int x, int y, Object dragInfo, + CellLayout cellLayout, boolean insertAtFirst) { // Drag from somewhere else ItemInfo info = (ItemInfo) dragInfo; @@ -1109,41 +1229,42 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT: if (info.container == NO_ID && info instanceof ApplicationInfo) { // Came from all apps -- make a copy - info = new ShortcutInfo((ApplicationInfo)info); + info = new ShortcutInfo((ApplicationInfo) info); } - view = mLauncher.createShortcut(R.layout.application, cellLayout, (ShortcutInfo)info); + view = mLauncher.createShortcut(R.layout.application, cellLayout, + (ShortcutInfo) info); break; case LauncherSettings.Favorites.ITEM_TYPE_USER_FOLDER: view = FolderIcon.fromXml(R.layout.folder_icon, mLauncher, - (ViewGroup) getChildAt(mCurrentScreen), ((UserFolderInfo) info)); + (ViewGroup) getChildAt(mCurrentScreen), + ((UserFolderInfo) info)); break; case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: cellLayout.setTagToCellInfoForPoint(x, y); mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName, cellLayout.getTag()); break; default: - throw new IllegalStateException("Unknown item type: " + info.itemType); + throw new IllegalStateException("Unknown item type: " + + info.itemType); } // addAppWidgetFromDrop already took care of attaching the widget view to the appropriate cell // TODO why aren't we calling addInScreen here? if (info.itemType != LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET) { - cellLayout.addView(view, insertAtFirst ? 0 : -1); - view.setHapticFeedbackEnabled(false); - view.setOnLongClickListener(mLongClickListener); - if (view instanceof DropTarget) { - mDragController.addDropTarget((DropTarget) view); - } - - mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, mTargetCell); - cellLayout.onDropChild(view, mTargetCell); - CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view.getLayoutParams(); + mTargetCell = estimateDropCell(x, y, 1, 1, view, cellLayout, + mTargetCell); + addInScreen(view, indexOfChild(cellLayout), mTargetCell[0], + mTargetCell[1], info.spanX, info.spanY, insertAtFirst); + cellLayout.onDropChild(view); + CellLayout.LayoutParams lp = (CellLayout.LayoutParams) view + .getLayoutParams(); LauncherModel.addOrMoveItemInDatabase(mLauncher, info, - LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, lp.cellX, lp.cellY); + LauncherSettings.Favorites.CONTAINER_DESKTOP, mCurrentScreen, + lp.cellX, lp.cellY); } } - + /** * Return the current {@link CellLayout}, correctly picking the destination * screen while a scroll is in progress. @@ -1170,37 +1291,37 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag return mVacantCache.findCellForSpan(mTempEstimate, spanX, spanY, false); } - + /** * {@inheritDoc} */ public Rect estimateDropLocation(DragSource source, int x, int y, int xOffset, int yOffset, DragView dragView, Object dragInfo, Rect recycle) { final CellLayout layout = getCurrentDropLayout(); - + final CellLayout.CellInfo cellInfo = mDragInfo; final int spanX = cellInfo == null ? 1 : cellInfo.spanX; final int spanY = cellInfo == null ? 1 : cellInfo.spanY; final View ignoreView = cellInfo == null ? null : cellInfo.cell; - + final Rect location = recycle != null ? recycle : new Rect(); - + // Find drop cell and convert into rectangle - int[] dropCell = estimateDropCell(x - xOffset, y - yOffset, - spanX, spanY, ignoreView, layout, mTempCell); - + int[] dropCell = estimateDropCell(x - xOffset, y - yOffset, spanX, + spanY, ignoreView, layout, mTempCell); + if (dropCell == null) { return null; } - + layout.cellToPoint(dropCell[0], dropCell[1], mTempEstimate); location.left = mTempEstimate[0]; location.top = mTempEstimate[1]; - + layout.cellToPoint(dropCell[0] + spanX, dropCell[1] + spanY, mTempEstimate); location.right = mTempEstimate[0]; location.bottom = mTempEstimate[1]; - + return location; } @@ -1218,7 +1339,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag return layout.findNearestVacantArea(pixelX, pixelY, spanX, spanY, mVacantCache, recycle); } - + void setLauncher(Launcher launcher) { mLauncher = launcher; } @@ -1230,14 +1351,14 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag public void onDropCompleted(View target, boolean success) { clearVacantCache(); - if (success){ + if (success) { if (target != this && mDragInfo != null) { final CellLayout cellLayout = (CellLayout) getChildAt(mDragInfo.screen); cellLayout.removeView(mDragInfo.cell); if (mDragInfo.cell instanceof DropTarget) { mDragController.removeDropTarget((DropTarget)mDragInfo.cell); } - //final Object tag = mDragInfo.cell.getTag(); + // final Object tag = mDragInfo.cell.getTag(); } } else { if (mDragInfo != null) { @@ -1252,18 +1373,22 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag public void scrollLeft() { clearVacantCache(); if (mScroller.isFinished()) { - if (mCurrentScreen > 0) snapToScreen(mCurrentScreen - 1); + if (mCurrentScreen > 0) + snapToScreen(mCurrentScreen - 1); } else { - if (mNextScreen > 0) snapToScreen(mNextScreen - 1); + if (mNextScreen > 0) + snapToScreen(mNextScreen - 1); } } public void scrollRight() { clearVacantCache(); if (mScroller.isFinished()) { - if (mCurrentScreen < getChildCount() -1) snapToScreen(mCurrentScreen + 1); + if (mCurrentScreen < getChildCount() - 1) + snapToScreen(mCurrentScreen + 1); } else { - if (mNextScreen < getChildCount() -1) snapToScreen(mNextScreen + 1); + if (mNextScreen < getChildCount() - 1) + snapToScreen(mNextScreen + 1); } } @@ -1291,7 +1416,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams(); if (lp.cellHSpan == 4 && lp.cellVSpan == 4 && child instanceof Folder) { Folder f = (Folder) child; - if (f.getInfo() == tag) { + if (f.getInfo() == tag && f.getInfo().opened) { return f; } } @@ -1321,7 +1446,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag public boolean allowLongPress() { return mAllowLongPress; } - + /** * Set true to allow long-press events to be triggered, usually checked by * {@link Launcher} to accept or block dpad-initiated long-presses. @@ -1349,17 +1474,17 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag public void run() { final ArrayList childrenToRemove = new ArrayList(); childrenToRemove.clear(); - + int childCount = layout.getChildCount(); for (int j = 0; j < childCount; j++) { final View view = layout.getChildAt(j); Object tag = view.getTag(); - + if (tag instanceof ShortcutInfo) { final ShortcutInfo info = (ShortcutInfo) tag; final Intent intent = info.intent; final ComponentName name = intent.getComponent(); - + if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { for (String packageName: packageNames) { if (packageName.equals(name.getPackageName())) { @@ -1375,12 +1500,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag final ArrayList toRemove = new ArrayList(1); final int contentsCount = contents.size(); boolean removedFromFolder = false; - + for (int k = 0; k < contentsCount; k++) { final ShortcutInfo appInfo = contents.get(k); final Intent intent = appInfo.intent; final ComponentName name = intent.getComponent(); - + if (Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { for (String packageName: packageNames) { if (packageName.equals(name.getPackageName())) { @@ -1393,11 +1518,12 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag } } } - + contents.removeAll(toRemove); if (removedFromFolder) { final Folder folder = getOpenFolder(); - if (folder != null) folder.notifyDataSetChanged(); + if (folder != null) + folder.notifyDataSetChanged(); } } else if (tag instanceof LiveFolderInfo) { final LiveFolderInfo info = (LiveFolderInfo) tag; @@ -1410,7 +1536,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (packageName.equals(providerInfo.packageName)) { // TODO: This should probably be done on a worker thread LauncherModel.deleteItemFromDatabase(mLauncher, info); - childrenToRemove.add(view); + childrenToRemove.add(view); } } } @@ -1423,13 +1549,13 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (packageName.equals(provider.provider.getPackageName())) { // TODO: This should probably be done on a worker thread LauncherModel.deleteItemFromDatabase(mLauncher, info); - childrenToRemove.add(view); + childrenToRemove.add(view); } } } } } - + childCount = childrenToRemove.size(); for (int j = 0; j < childCount; j++) { View child = childrenToRemove.get(j); @@ -1438,7 +1564,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag mDragController.removeDropTarget((DropTarget)child); } } - + if (childCount > 0) { layout.requestLayout(); layout.invalidate(); @@ -1468,7 +1594,7 @@ public class Workspace extends ViewGroup implements DropTarget, DragSource, Drag if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION && Intent.ACTION_MAIN.equals(intent.getAction()) && name != null) { final int appCount = apps.size(); - for (int k=0; k