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
This commit is contained in:
Winson Chung 2010-06-11 17:34:16 -07:00 committed by Adam Cohen
parent 6404116682
commit aafa03cbb9
28 changed files with 992 additions and 419 deletions

View File

@ -75,6 +75,7 @@
android:stateNotNeeded="true"
android:theme="@style/Theme"
android:screenOrientation="nosensor"
android:configChanges="orientation"
android:windowSoftInputMode="stateUnspecified|adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -29,14 +29,14 @@
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
launcher:defaultScreen="2">
launcher:canonicalDeviceWidth="8"
launcher:canonicalDeviceHeight="4">
<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
<include android:id="@+id/cell2" layout="@layout/workspace_screen" />
<include android:id="@+id/cell3" layout="@layout/workspace_screen" />
<include android:id="@+id/cell4" layout="@layout/workspace_screen" />
<include android:id="@+id/cell5" layout="@layout/workspace_screen" />
</com.android.launcher2.Workspace>
<com.android.launcher2.DeleteZone

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.android.launcher2.CellLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:hapticFeedbackEnabled="false"
launcher:cellWidth="@dimen/workspace_cell_width"
launcher:cellHeight="@dimen/workspace_cell_height"
launcher:longAxisStartPadding="8dip"
launcher:longAxisEndPadding="8dip"
launcher:shortAxisStartPadding="8dip"
launcher:shortAxisEndPadding="8dip"
launcher:shortAxisCells="4"
launcher:longAxisCells="8" />

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2009 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.
-->
<resources>
<dimen name="workspace_cell_width">76dip</dimen>
<dimen name="workspace_cell_height">76dip</dimen>
</resources>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<resources>
<style name="WorkspaceIcon.Portrait">
<item name="android:drawablePadding">4dip</item>
<item name="android:paddingTop">1dip</item>
</style>
<style name="WorkspaceIcon.Landscape">
<item name="android:drawablePadding">4dip</item>
<item name="android:paddingTop">1dip</item>
</style>
</resources>

View File

@ -32,6 +32,10 @@
<declare-styleable name="Workspace">
<!-- The first screen the workspace should display. -->
<attr name="defaultScreen" format="integer" />
<!-- The number of horizontal cells for the device in its natural orientation -->
<attr name="canonicalDeviceWidth" format="integer" />
<!-- The number of vertical cells for the device in its natural orientation -->
<attr name="canonicalDeviceHeight" format="integer" />
</declare-styleable>
<!-- CellLayout specific attributes. These attributes are used to customize

View File

@ -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;

View File

@ -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

View File

@ -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.

View File

@ -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.
*/

View File

@ -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();
super.addView(child, index, params);
child.setId(childId);
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<VacantCell> 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;
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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<ItemInfo> 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);

View File

@ -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.

View File

@ -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<ResolveInfo> 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;
}
}

View File

@ -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;
}
}

View File

@ -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 <container, screen, cellX, cellY>
*/
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<ItemInfo> getItemsInLocalCoordinates(Context context) {
ArrayList<ItemInfo> items = new ArrayList<ItemInfo>();
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) {

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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 {

View File

@ -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.
*/

View File

@ -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;
/**

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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<Folder> 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<View> childrenToRemove = new ArrayList<View>();
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<ShortcutInfo> toRemove = new ArrayList<ShortcutInfo>(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<appCount; k++) {
for (int k = 0; k < appCount; k++) {
ApplicationInfo app = apps.get(k);
if (app.componentName.equals(name)) {
info.setIcon(mIconCache.getIcon(info.intent));