added support for dragging widgets and app icons to mini screens
- gave mini screens a rounded rect background
- mini screens change color when dragged over
- added a way to specify the active region of dragged items, to allow for clipping of whitespace at borders
- fixed: feedback while dragging was often one cell off
- fixed: bug when adding to almost-full screen
- removed unused classes
Change-Id: I2fbd2aaaee6831b288cca8dec75e7b446068e8d1
diff --git a/src/com/android/launcher2/AllAppsPagedView.java b/src/com/android/launcher2/AllAppsPagedView.java
index 72eeb22..be3135c 100644
--- a/src/com/android/launcher2/AllAppsPagedView.java
+++ b/src/com/android/launcher2/AllAppsPagedView.java
@@ -181,7 +181,6 @@
app = new ApplicationInfo(app);
mDragController.startDrag(v, this, app, DragController.DRAG_ACTION_COPY);
- mLauncher.closeAllApps(true);
return true;
}
diff --git a/src/com/android/launcher2/CellLayout.java b/src/com/android/launcher2/CellLayout.java
index e86b305..4c08ca6 100644
--- a/src/com/android/launcher2/CellLayout.java
+++ b/src/com/android/launcher2/CellLayout.java
@@ -24,6 +24,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
@@ -81,10 +82,15 @@
private Bitmap mDimmedBitmap;
private Canvas mDimmedBitmapCanvas;
private float mDimmedBitmapAlpha;
- private boolean mDimmedBitmapDirty;
+ private boolean mDimmedBitmapDirty = false;
private final Paint mDimmedBitmapPaint = new Paint();
private final Rect mLayoutRect = new Rect();
private final Rect mDimmedBitmapRect = new Rect();
+ private Drawable mDimmedBitmapBackground;
+ private Drawable mDimmedBitmapBackgroundHover;
+ // If we're actively dragging something over this screen and it's small,
+ // mHover is true
+ private boolean mHover = false;
private final RectF mDragRect = new RectF();
@@ -122,6 +128,14 @@
mVacantDrawable = getResources().getDrawable(R.drawable.rounded_rect_green);
mOccupiedDrawable = getResources().getDrawable(R.drawable.rounded_rect_red);
+ if (LauncherApplication.isScreenXLarge()) {
+ mDimmedBitmapBackground = getResources().getDrawable(
+ R.drawable.mini_home_screen_bg);
+
+ mDimmedBitmapBackgroundHover = getResources().getDrawable(
+ R.drawable.mini_home_screen_bg_hover);
+ }
+
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
@@ -148,8 +162,20 @@
mDimmedBitmapPaint.setFilterBitmap(true);
}
+ public void setHover(boolean value) {
+ if (mHover != value) {
+ invalidate();
+ }
+ mHover = value;
+ }
+
@Override
public void dispatchDraw(Canvas canvas) {
+ if (mDimmedBitmapAlpha > 0.0f) {
+ final Drawable bg = mHover ? mDimmedBitmapBackgroundHover : mDimmedBitmapBackground;
+ bg.setAlpha((int) (mDimmedBitmapAlpha * 255));
+ bg.draw(canvas);
+ }
super.dispatchDraw(canvas);
}
@@ -567,6 +593,12 @@
super.onSizeChanged(w, h, oldw, oldh);
mLayoutRect.set(0, 0, w, h);
mDimmedBitmapRect.set(0, 0, (int) (DIMMED_BITMAP_SCALE * w), (int) (DIMMED_BITMAP_SCALE * h));
+ if (mDimmedBitmapBackground != null) {
+ mDimmedBitmapBackground.setBounds(mLayoutRect);
+ }
+ if (mDimmedBitmapBackgroundHover != null) {
+ mDimmedBitmapBackgroundHover.setBounds(mLayoutRect);
+ }
}
@Override
@@ -619,19 +651,12 @@
// draw the screen into the bitmap
// just for drawing to the bitmap, make all the items on the screen opaque
setChildrenAlpha(1.0f);
- dispatchDraw(mDimmedBitmapCanvas);
+ // call our superclass's dispatchdraw so we don't draw the background
+ super.dispatchDraw(mDimmedBitmapCanvas);
setChildrenAlpha(1.0f - mDimmedBitmapAlpha);
- // make the bitmap 'dimmed' ie colored regions are dark grey,
- // the rest is light grey
- // We draw grey to the whole bitmap, but filter where we draw based on
- // what regions are transparent or not (SRC_OUT), causing the intended effect
-
- // First, draw light grey everywhere in the background (currently transparent) regions
- // This will leave the regions with the widgets as mostly transparent
- mDimmedBitmapCanvas.drawColor(0xCCCCCCCC, PorterDuff.Mode.SRC_OUT);
- // Now, fill the the remaining transparent regions with dark grey
- mDimmedBitmapCanvas.drawColor(0xCC333333, PorterDuff.Mode.SRC_OUT);
+ // replace all colored areas with a dark (semi-transparent black)
+ mDimmedBitmapCanvas.drawColor(Color.argb(160, 0, 0, 0), PorterDuff.Mode.SRC_IN);
}
private boolean isVacant(int originX, int originY, int spanX, int spanY) {
@@ -683,9 +708,9 @@
final int countX = mCountX;
final int countY = mCountY;
- // originX and originY give the top left of the cell, but pointToCellRounded
- // compares center-to-center, so pass in the middle coordinates
- pointToCellRounded(originX + (mCellWidth / 2), originY + (mCellHeight / 2), result);
+ // pointToCellRounded takes the top left of a cell but will pad that with
+ // cellWidth/2 and cellHeight/2 when finding the matching cell
+ pointToCellRounded(originX, originY, result);
// If the item isn't fully on this screen, snap to the edges
int rightOverhang = result[0] + spanX - countX;
@@ -798,6 +823,7 @@
mDragCell[0] = -1;
mDragCell[1] = -1;
+ setHover(false);
mDragRect.setEmpty();
invalidate();
}
@@ -1104,12 +1130,12 @@
private int mCountX;
private int mCountY;
View cell;
- int cellX;
- int cellY;
+ int cellX = -1;
+ int cellY = -1;
// intersectX and intersectY constrain the results of findCellForSpan; any empty space
// it results must include this point (unless intersectX and intersectY are -1)
- int intersectX;
- int intersectY;
+ int intersectX = -1;
+ int intersectY = -1;
int spanX;
int spanY;
int screen;
@@ -1179,7 +1205,7 @@
endY = Math.min(endY, intersectY + (spanY - 1));
}
- for (int x = startX; x < endX + 1; x++) {
+ for (int x = startX; x < endX; x++) {
inner:
for (int y = startY; y < endY; y++) {
for (int i = 0; i < spanX; i++) {
diff --git a/src/com/android/launcher2/CustomizePagedView.java b/src/com/android/launcher2/CustomizePagedView.java
index 4a955b2..ef619be 100644
--- a/src/com/android/launcher2/CustomizePagedView.java
+++ b/src/com/android/launcher2/CustomizePagedView.java
@@ -166,12 +166,26 @@
final View animView = v;
switch (mCustomizationType) {
case WidgetCustomization:
+ // We assume that the view v is a TextView with a compound drawable on top, and that the
+ // whole text view is centered horizontally and top aligned. We get a more precise
+ // drag point using this information
+ final TextView textView = (TextView) animView;
+ final Drawable[] drawables = textView.getCompoundDrawables();
+ final Drawable icon = drawables[1];
+ int dragPointOffsetX = 0;
+ int dragPointOffsetY = 0;
+ Rect bounds = null;
+ if (icon != null) {
+ bounds = icon.getBounds();
+ bounds.left = (v.getWidth() - bounds.right) / 2;
+ bounds.right += bounds.left;
+ }
+
AppWidgetProviderInfo appWidgetInfo = (AppWidgetProviderInfo) v.getTag();
LauncherAppWidgetInfo dragInfo = new LauncherAppWidgetInfo(appWidgetInfo.provider);
dragInfo.minWidth = appWidgetInfo.minWidth;
dragInfo.minHeight = appWidgetInfo.minHeight;
- mDragController.startDrag(v, this, dragInfo, DragController.DRAG_ACTION_COPY);
- mLauncher.hideCustomizationDrawer();
+ mDragController.startDrag(v, this, dragInfo, DragController.DRAG_ACTION_COPY, bounds);
return true;
case FolderCustomization:
// animate some feedback to the long press
diff --git a/src/com/android/launcher2/DragController.java b/src/com/android/launcher2/DragController.java
index 651b6f0..e18470a 100644
--- a/src/com/android/launcher2/DragController.java
+++ b/src/com/android/launcher2/DragController.java
@@ -151,7 +151,7 @@
/**
* Starts a drag.
- *
+ *
* @param v The view that is being dragged
* @param source An object representing where the drag originated
* @param dragInfo The data associated with the object that is being dragged
@@ -159,6 +159,22 @@
* {@link #DRAG_ACTION_COPY}
*/
public void startDrag(View v, DragSource source, Object dragInfo, int dragAction) {
+ startDrag(v, source, dragInfo, dragAction, null);
+ }
+
+ /**
+ * Starts a drag.
+ *
+ * @param v The view that is being dragged
+ * @param source An object representing where the drag originated
+ * @param dragInfo The data associated with the object that is being dragged
+ * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
+ * {@link #DRAG_ACTION_COPY}
+ * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
+ * Makes dragging feel more precise, e.g. you can clip out a transparent border
+ */
+ public void startDrag(View v, DragSource source, Object dragInfo, int dragAction,
+ Rect dragRegion) {
mOriginator = v;
Bitmap b = getViewBitmap(v);
@@ -174,7 +190,7 @@
int screenY = loc[1];
startDrag(b, screenX, screenY, 0, 0, b.getWidth(), b.getHeight(),
- source, dragInfo, dragAction);
+ source, dragInfo, dragAction, dragRegion);
b.recycle();
@@ -185,7 +201,7 @@
/**
* Starts a drag.
- *
+ *
* @param b The bitmap to display as the drag image. It will be re-scaled to the
* enlarged size.
* @param screenX The x position on screen of the left-top of the bitmap.
@@ -202,6 +218,31 @@
public void startDrag(Bitmap b, int screenX, int screenY,
int textureLeft, int textureTop, int textureWidth, int textureHeight,
DragSource source, Object dragInfo, int dragAction) {
+ startDrag(b, screenX, screenY, textureLeft, textureTop, textureWidth, textureHeight,
+ source, dragInfo, dragAction, null);
+ }
+
+ /**
+ * Starts a drag.
+ *
+ * @param b The bitmap to display as the drag image. It will be re-scaled to the
+ * enlarged size.
+ * @param screenX The x position on screen of the left-top of the bitmap.
+ * @param screenY The y position on screen of the left-top of the bitmap.
+ * @param textureLeft The left edge of the region inside b to use.
+ * @param textureTop The top edge of the region inside b to use.
+ * @param textureWidth The width of the region inside b to use.
+ * @param textureHeight The height of the region inside b to use.
+ * @param source An object representing where the drag originated
+ * @param dragInfo The data associated with the object that is being dragged
+ * @param dragAction The drag action: either {@link #DRAG_ACTION_MOVE} or
+ * {@link #DRAG_ACTION_COPY}
+ * @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
+ * Makes dragging feel more precise, e.g. you can clip out a transparent border
+ */
+ public void startDrag(Bitmap b, int screenX, int screenY,
+ int textureLeft, int textureTop, int textureWidth, int textureHeight,
+ DragSource source, Object dragInfo, int dragAction, Rect dragRegion) {
if (PROFILE_DRAWING_DURING_DRAG) {
android.os.Debug.startMethodTracing("Launcher");
}
@@ -220,8 +261,10 @@
int registrationX = ((int)mMotionDownX) - screenX;
int registrationY = ((int)mMotionDownY) - screenY;
- mTouchOffsetX = mMotionDownX - screenX;
- mTouchOffsetY = mMotionDownY - screenY;
+ final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
+ final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
+ mTouchOffsetX = mMotionDownX - screenX - dragRegionLeft;
+ mTouchOffsetY = mMotionDownY - screenY - dragRegionTop;
mDragging = true;
mDragSource = source;
@@ -231,6 +274,12 @@
DragView dragView = mDragView = new DragView(mContext, b, registrationX, registrationY,
textureLeft, textureTop, textureWidth, textureHeight);
+
+ if (dragRegion != null) {
+ dragView.setDragRegion(dragRegionLeft, dragRegion.top,
+ dragRegion.right - dragRegionLeft, dragRegion.bottom - dragRegionTop);
+ }
+
dragView.show(mWindowToken, (int)mMotionDownX, (int)mMotionDownY);
}
diff --git a/src/com/android/launcher2/DragView.java b/src/com/android/launcher2/DragView.java
index bae592c..41e76f0 100644
--- a/src/com/android/launcher2/DragView.java
+++ b/src/com/android/launcher2/DragView.java
@@ -39,6 +39,11 @@
private int mRegistrationX;
private int mRegistrationY;
+ private int mDragRegionLeft = 0;
+ private int mDragRegionTop = 0;
+ private int mDragRegionWidth;
+ private int mDragRegionHeight;
+
SymmetricalLinearTween mTween;
private float mScale;
private float mAnimationScale = 1.0f;
@@ -71,12 +76,37 @@
scale.setScale(scaleFactor, scaleFactor);
mBitmap = Bitmap.createBitmap(bitmap, left, top, width, height, scale, true);
+ mDragRegionWidth = width;
+ mDragRegionHeight = height;
// The point in our scaled bitmap that the touch events are located
mRegistrationX = registrationX + (DRAG_SCALE / 2);
mRegistrationY = registrationY + (DRAG_SCALE / 2);
}
+ public void setDragRegion(int left, int top, int width, int height) {
+ mDragRegionLeft = left;
+ mDragRegionTop = top;
+ mDragRegionWidth = width;
+ mDragRegionHeight = height;
+ }
+
+ public int getDragRegionLeft() {
+ return mDragRegionLeft;
+ }
+
+ public int getDragRegionTop() {
+ return mDragRegionTop;
+ }
+
+ public int getDragRegionWidth() {
+ return mDragRegionWidth;
+ }
+
+ public int getDragRegionHeight() {
+ return mDragRegionHeight;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(mBitmap.getWidth(), mBitmap.getHeight());
diff --git a/src/com/android/launcher2/FolderListAdapter.java b/src/com/android/launcher2/FolderListAdapter.java
deleted file mode 100644
index ebb3332..0000000
--- a/src/com/android/launcher2/FolderListAdapter.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * 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 com.android.launcher.R;
-
-import android.content.Context;
-import android.content.pm.ResolveInfo;
-
-public class FolderListAdapter extends IntentListAdapter {
-
- public FolderListAdapter(Context context, String actionFilter) {
- super(context, actionFilter);
-
- // Manually create a separate entry for creating a folder in Launcher
- ResolveInfo folder = new ResolveInfo();
- folder.icon = R.drawable.ic_launcher_folder;
- folder.labelRes = R.string.group_folder;
- folder.resolvePackageName = context.getPackageName();
- mIntentList.add(0, folder);
- }
-}
diff --git a/src/com/android/launcher2/IntentListAdapter.java b/src/com/android/launcher2/IntentListAdapter.java
deleted file mode 100644
index f844738..0000000
--- a/src/com/android/launcher2/IntentListAdapter.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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 com.android.launcher.R;
-
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.graphics.drawable.Drawable;
-import android.provider.LiveFolders;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import java.util.List;
-
-public class IntentListAdapter extends BaseAdapter {
- private LayoutInflater mLayoutInflater;
- private PackageManager mPackageManager;
- protected List<ResolveInfo> mIntentList;
-
- public IntentListAdapter(Context context, String actionFilter) {
- mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mPackageManager = context.getPackageManager();
-
- Intent createLiveFolderIntent = new Intent(actionFilter);
- mIntentList = mPackageManager.queryIntentActivities(createLiveFolderIntent, 0);
- }
-
- public int getCount() {
- return mIntentList.size();
- }
-
- public Object getItem(int position) {
- return mIntentList.get(position);
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- TextView textView;
-
- if (convertView == null) {
- textView = (TextView) mLayoutInflater.inflate(
- R.layout.home_customization_drawer_item, parent, false);
- } else {
- textView = (TextView) convertView;
- }
-
- ResolveInfo info = mIntentList.get(position);
- Drawable image = info.loadIcon(mPackageManager);
- image.setBounds(0, 0, image.getIntrinsicWidth(), image.getIntrinsicHeight());
- textView.setCompoundDrawables(null, image, null, null);
-
- CharSequence label = info.loadLabel(mPackageManager);
- textView.setText(label);
-
- return textView;
- }
-}
diff --git a/src/com/android/launcher2/Launcher.java b/src/com/android/launcher2/Launcher.java
index c4bb69e..ee70b5e 100644
--- a/src/com/android/launcher2/Launcher.java
+++ b/src/com/android/launcher2/Launcher.java
@@ -205,6 +205,7 @@
private LauncherAppWidgetHost mAppWidgetHost;
private CellLayout.CellInfo mAddItemCellInfo;
+ private int[] mAddItemCoordinates;
private CellLayout.CellInfo mMenuAddInfo;
private final int[] mCellCoordinates = new int[2];
private FolderInfo mFolderInfo;
@@ -791,6 +792,7 @@
final int addScreen = savedState.getInt(RUNTIME_STATE_PENDING_ADD_SCREEN, -1);
if (addScreen > -1) {
+ mAddItemCoordinates = null;
mAddItemCellInfo = new CellLayout.CellInfo();
final CellLayout.CellInfo addItemCellInfo = mAddItemCellInfo;
addItemCellInfo.valid = true;
@@ -818,7 +820,7 @@
* Finds all the views we need and configure them properly.
*/
private void setupViews() {
- DragController dragController = mDragController;
+ final DragController dragController = mDragController;
DragLayer dragLayer = (DragLayer) findViewById(R.id.drag_layer);
dragLayer.setDragController(dragController);
@@ -1040,8 +1042,26 @@
int[] spans = layout.rectToCell(appWidgetInfo.minWidth, appWidgetInfo.minHeight, null);
// Try finding open space on Launcher screen
+ // We have saved the position to which the widget was dragged-- this really only matters
+ // if we are placing widgets on a "spring-loaded" screen
final int[] xy = mCellCoordinates;
- if (!findSlot(cellInfo, xy, spans[0], spans[1])) {
+
+ // For now, we don't save the coordinate where we dropped the icon because we're not
+ // supporting spring-loaded mini-screens; however, leaving the ability to directly place
+ // a widget on the home screen in case we want to add it in the future
+ final int[] xyTouch = null;
+ //final int[] xyTouch = mAddItemCoordinates;
+ boolean findNearestVacantAreaFailed = false;
+ if (xyTouch != null) {
+ CellLayout screen = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
+ int[] result = screen.findNearestVacantArea(
+ mAddItemCoordinates[0], mAddItemCoordinates[1],
+ spans[0], spans[1], cellInfo, xy);
+ findNearestVacantAreaFailed = (result == null);
+ }
+
+ if (findNearestVacantAreaFailed ||
+ (xyTouch == null && !findSlot(cellInfo, xy, spans[0], spans[1]))) {
if (appWidgetId != -1) mAppWidgetHost.deleteAppWidgetId(appWidgetId);
return;
}
@@ -1053,7 +1073,7 @@
LauncherModel.addItemToDatabase(this, launcherInfo,
LauncherSettings.Favorites.CONTAINER_DESKTOP,
- mWorkspace.getCurrentScreen(), xy[0], xy[1], false);
+ cellInfo.screen, xy[0], xy[1], false);
if (!mRestoring) {
mDesktopItems.add(launcherInfo);
@@ -1064,7 +1084,7 @@
launcherInfo.hostView.setAppWidget(appWidgetId, appWidgetInfo);
launcherInfo.hostView.setTag(launcherInfo);
- mWorkspace.addInCurrentScreen(launcherInfo.hostView, xy[0], xy[1],
+ mWorkspace.addInScreen(launcherInfo.hostView, cellInfo.screen, xy[0], xy[1],
launcherInfo.spanX, launcherInfo.spanY, isWorkspaceLocked());
}
}
@@ -1307,7 +1327,7 @@
// Disable add if the workspace is full.
if (visible) {
- mMenuAddInfo = mWorkspace.updateOccupiedCells(null);
+ mMenuAddInfo = mWorkspace.updateOccupiedCellsForCurrentScreen(null);
menu.setGroupEnabled(MENU_GROUP_ADD, mMenuAddInfo != null && mMenuAddInfo.valid);
}
@@ -1317,8 +1337,9 @@
// we need to initialize mAddItemCellInfo before adding something to the homescreen -- when
// using the settings menu to add an item, something similar happens in showAddDialog
public void prepareAddItemFromHomeCustomizationDrawer() {
- mMenuAddInfo = mWorkspace.updateOccupiedCells(null);
+ mMenuAddInfo = mWorkspace.updateOccupiedCellsForCurrentScreen(null);
mAddItemCellInfo = mMenuAddInfo;
+ mAddItemCellInfo = null;
}
@Override
@@ -1369,8 +1390,12 @@
}
}
- void addAppWidgetFromDrop(ComponentName appWidgetProvider, CellLayout.CellInfo cellInfo) {
+ void addAppWidgetFromDrop(ComponentName appWidgetProvider, CellLayout.CellInfo cellInfo,
+ int[] position) {
mAddItemCellInfo = cellInfo;
+
+ // only set mAddItemCoordinates if we dropped on home screen in "spring-loaded" manner
+ mAddItemCoordinates = position;
int appWidgetId = getAppWidgetHost().allocateAppWidgetId();
AppWidgetManager.getInstance(this).bindAppWidgetId(appWidgetId, appWidgetProvider);
addAppWidgetImpl(appWidgetId);
@@ -1523,9 +1548,8 @@
private boolean findSlot(CellLayout.CellInfo cellInfo, int[] xy, int spanX, int spanY) {
if (!cellInfo.findCellForSpan(xy, spanX, spanY)) {
- boolean[] occupied = mSavedState != null ?
- mSavedState.getBooleanArray(RUNTIME_STATE_PENDING_ADD_OCCUPIED_CELLS) : null;
- cellInfo = mWorkspace.updateOccupiedCells(occupied);
+ CellLayout targetLayout = (CellLayout) mWorkspace.getChildAt(cellInfo.screen);
+ cellInfo = targetLayout.updateOccupiedCells(null, null);
if (!cellInfo.findCellForSpan(xy, spanX, spanY)) {
Toast.makeText(this, getString(R.string.out_of_space), Toast.LENGTH_SHORT).show();
return false;
@@ -2034,6 +2058,7 @@
private void showAddDialog(CellLayout.CellInfo cellInfo) {
mAddItemCellInfo = cellInfo;
+ mAddItemCoordinates = null;
mWaitingForResult = true;
showDialog(DIALOG_CREATE_SHORTCUT);
}
diff --git a/src/com/android/launcher2/WidgetListAdapter.java b/src/com/android/launcher2/WidgetListAdapter.java
deleted file mode 100644
index 61e7c89..0000000
--- a/src/com/android/launcher2/WidgetListAdapter.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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 com.android.launcher.R;
-
-import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetProviderInfo;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.Region.Op;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.TextView;
-
-import java.util.List;
-
-public class WidgetListAdapter extends BaseAdapter {
- private final Launcher mLauncher;
- private List<AppWidgetProviderInfo> mWidgets;
- private final Canvas mCanvas = new Canvas();
-
- private final int[] mTempSize = new int[2];
- private final Rect mTempRect = new Rect();
-
- private static final String TAG = "Launcher.WidgetGalleryAdapter";
-
- WidgetListAdapter(Launcher launcher) {
- mLauncher = launcher;
- mWidgets = AppWidgetManager.getInstance(launcher).getInstalledProviders();
- }
-
- public int getCount() {
- return mWidgets.size();
- }
-
- public Object getItem(int position) {
- return mWidgets.get(position);
- }
-
- public long getItemId(int position) {
- return position;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- TextView textView;
-
- if (convertView == null) {
- LayoutInflater inflater =
- (LayoutInflater)mLauncher.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- textView = (TextView) inflater.inflate(
- R.layout.home_customization_drawer_widget, parent, false);
- } else {
- textView = (TextView) convertView;
- }
-
- AppWidgetProviderInfo info = mWidgets.get(position);
- PackageManager packageManager = mLauncher.getPackageManager();
- String packageName = info.provider.getPackageName();
- Drawable drawable = null;
- if (info.previewImage != 0) {
- drawable = packageManager.getDrawable(packageName, info.previewImage, null);
- if (drawable == null) {
- Log.w(TAG, "Can't load icon drawable 0x" + Integer.toHexString(info.icon)
- + " for provider: " + info.provider);
- }
- }
- // If we don't have a preview image, create a default one
- if (drawable == null) {
- Resources resources = mLauncher.getResources();
-
- // Determine the size the widget will take in the layout
- mLauncher.getWorkspace().estimateChildSize(info.minWidth, info.minHeight, mTempSize);
-
- // Create a new bitmap to hold the widget preview
- final int width = mTempSize[0];
- final int height = mTempSize[1];
- Bitmap bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
- mCanvas.setBitmap(bitmap);
- // For some reason, we must re-set the clip rect here, otherwise it will be wrong
- mCanvas.clipRect(0, 0, width, height, Op.REPLACE);
-
- Drawable background = resources.getDrawable(R.drawable.default_widget_preview);
- background.setBounds(0, 0, width, height);
- background.draw(mCanvas);
-
- // Draw the icon vertically centered, flush left
- try {
- Drawable icon = packageManager.getDrawable(packageName, info.icon, null);
- background.getPadding(mTempRect);
-
- final int left = mTempRect.left;
- final int top = (height - icon.getIntrinsicHeight()) / 2;
- icon.setBounds(
- left, top, left + icon.getIntrinsicWidth(), top + icon.getIntrinsicHeight());
- icon.draw(mCanvas);
- } catch (Resources.NotFoundException e) {
- // if we can't find the icon, then just don't draw it
- }
-
- drawable = new BitmapDrawable(resources, bitmap);
- }
- drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
- textView.setCompoundDrawables(null, drawable, null, null);
- textView.setText(info.label);
- // Store the widget info on the associated view so we can easily fetch it later
- textView.setTag(info);
-
- return textView;
- }
-}
diff --git a/src/com/android/launcher2/Workspace.java b/src/com/android/launcher2/Workspace.java
index 73eaeab..fc505c7 100644
--- a/src/com/android/launcher2/Workspace.java
+++ b/src/com/android/launcher2/Workspace.java
@@ -34,6 +34,7 @@
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
@@ -124,6 +125,8 @@
private int[] mTempCell = new int[2];
private int[] mTempEstimate = new int[2];
+ private float[] mTempDragCoordinates = new float[2];
+ private float[] mTempDragBottomRightCoordinates = new float[2];
private boolean mAllowLongPress = true;
@@ -459,7 +462,7 @@
}
}
- CellLayout.CellInfo updateOccupiedCells(boolean[] occupied) {
+ CellLayout.CellInfo updateOccupiedCellsForCurrentScreen(boolean[] occupied) {
CellLayout group = (CellLayout) getChildAt(mCurrentScreen);
if (group != null) {
return group.updateOccupiedCells(occupied, null);
@@ -1309,9 +1312,31 @@
public void onDrop(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
- final CellLayout cellLayout = getCurrentDropLayout();
+ CellLayout cellLayout = getCurrentDropLayout();
+ int originX = x - xOffset;
+ int originY = y - yOffset;
+ if (mIsSmall) {
+ // find out which target layout is over
+ final float[] localXY = mTempDragCoordinates;
+ localXY[0] = originX;
+ localXY[1] = originY;
+ final float[] localBottomRightXY = mTempDragBottomRightCoordinates;
+ // we need to subtract left/top here because DragController already adds
+ // dragRegionLeft/Top to xOffset and yOffset
+ localBottomRightXY[0] = originX + dragView.getDragRegionWidth();
+ localBottomRightXY[1] = originY + dragView.getDragRegionHeight();
+ cellLayout = findMatchingScreenForDragOver(localXY, localBottomRightXY);
+ if (cellLayout == null) {
+ // cancel the drag if we're not over a mini-screen at time of drop
+ // TODO: maybe add a nice fade here?
+ return;
+ }
+ // localXY will be transformed into the local screen's coordinate space; save that info
+ originX = (int)localXY[0];
+ originY = (int)localXY[1];
+ }
if (source != this) {
- onDropExternal(x - xOffset, y - yOffset, dragInfo, cellLayout);
+ onDropExternal(originX, originY, dragInfo, cellLayout);
} else {
// Move internally
if (mDragInfo != null) {
@@ -1323,7 +1348,8 @@
addInScreen(cell, index, mDragInfo.cellX, mDragInfo.cellY,
mDragInfo.spanX, mDragInfo.spanY);
}
- mTargetCell = estimateDropCell(x - xOffset, y - yOffset,
+
+ mTargetCell = estimateDropCell(originX, originY,
mDragInfo.spanX, mDragInfo.spanY, cell, cellLayout,
mTargetCell);
cellLayout.onDropChild(cell);
@@ -1381,11 +1407,87 @@
return null;
}
+ // xy = upper left corner of item being dragged
+ // bottomRightXy = lower right corner of item being dragged
+ // This method will see which mini-screen is most overlapped by the item being dragged, and
+ // return it. It will also transform the parameters xy and bottomRightXy into the local
+ // coordinate space of the returned screen
+ private CellLayout findMatchingScreenForDragOver(float[] xy, float[] bottomRightXy) {
+ float x = xy[0];
+ float y = xy[1];
+ float right = bottomRightXy[0];
+ float bottom = bottomRightXy[1];
+
+ float bestX = 0;
+ float bestY = 0;
+ float bestRight = 0;
+ float bestBottom = 0;
+
+ Matrix inverseMatrix = new Matrix();
+
+ // We loop through all the screens (ie CellLayouts) and see which one overlaps the most
+ // with the item being dragged.
+ final int screenCount = getChildCount();
+ CellLayout bestMatchingScreen = null;
+ float bestOverlapSoFar = 0;
+ for (int i = 0; i < screenCount; i++) {
+ CellLayout cl = (CellLayout)getChildAt(i);
+ // Transform the coordinates of the item being dragged to the CellLayout's coordinates
+ float left = cl.getLeft();
+ float top = cl.getTop();
+ xy[0] = x + mScrollX - left;
+ xy[1] = y + mScrollY - top;
+ cl.getMatrix().invert(inverseMatrix);
+
+ bottomRightXy[0] = right + mScrollX - left;
+ bottomRightXy[1] = bottom + mScrollY - top;
+
+ inverseMatrix.mapPoints(xy);
+ inverseMatrix.mapPoints(bottomRightXy);
+
+ float dragRegionX = xy[0];
+ float dragRegionY = xy[1];
+ float dragRegionRight = bottomRightXy[0];
+ float dragRegionBottom = bottomRightXy[1];
+
+ // Find the overlapping region
+ float overlapLeft = Math.max(0f, dragRegionX);
+ float overlapTop = Math.max(0f, dragRegionY);
+ float overlapBottom = Math.min(cl.getHeight(), dragRegionBottom);
+ float overlapRight = Math.min(cl.getWidth(), dragRegionRight);
+
+ if (overlapRight >= 0 && overlapLeft <= cl.getWidth() &&
+ overlapTop >= 0 && overlapBottom <= cl.getHeight()) {
+ // Calculate the size of the overlapping region
+ float overlap = (overlapRight - overlapLeft) * (overlapBottom - overlapTop);
+ if (overlap > bestOverlapSoFar) {
+ bestOverlapSoFar = overlap;
+ bestMatchingScreen = cl;
+ bestX = xy[0];
+ bestY = xy[1];
+ bestRight = bottomRightXy[0];
+ bestBottom = bottomRightXy[1];
+ }
+ }
+ }
+ if (bestMatchingScreen != null && bestMatchingScreen != mDragTargetLayout) {
+ if (mDragTargetLayout != null) {
+ mDragTargetLayout.onDragComplete();
+ }
+ mDragTargetLayout = bestMatchingScreen;
+ }
+ xy[0] = bestX;
+ xy[1] = bestY;
+ bottomRightXy[0] = bestRight;
+ bottomRightXy[1] = bestBottom;
+ return bestMatchingScreen;
+ }
+
public void onDragOver(DragSource source, int x, int y, int xOffset, int yOffset,
DragView dragView, Object dragInfo) {
final ItemInfo item = (ItemInfo)dragInfo;
- final CellLayout currentLayout = getCurrentDropLayout();
+ CellLayout currentLayout = getCurrentDropLayout();
if (dragInfo instanceof LauncherAppWidgetInfo) {
LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo)dragInfo;
@@ -1397,6 +1499,39 @@
item.spanY = spans[1];
}
}
+ int originX = x - xOffset;
+ int originY = y - yOffset;
+ if (mIsSmall) {
+ // find out which mini screen the dragged item is over
+ final float[] localXY = mTempDragCoordinates;
+ localXY[0] = originX;
+ localXY[1] = originY;
+ final float[] localBottomRightXY = mTempDragBottomRightCoordinates;
+
+ localBottomRightXY[0] = originX + dragView.getDragRegionWidth();
+ localBottomRightXY[1] = originY + dragView.getDragRegionHeight();
+ currentLayout = findMatchingScreenForDragOver(localXY, localBottomRightXY);
+ if (currentLayout != null) {
+ currentLayout.setHover(true);
+ }
+
+ originX = (int)localXY[0];
+ originY = (int)localXY[1];
+ }
+
+ if (source != this) {
+ // This is a hack to fix the point used to determine which cell an icon from the all
+ // apps screen is over
+ if (item != null && item.spanX == 1 && currentLayout != null) {
+ int dragRegionLeft = (dragView.getWidth() - currentLayout.getCellWidth()) / 2;
+
+ originX += dragRegionLeft - dragView.getDragRegionLeft();
+ if (dragView.getDragRegionWidth() != currentLayout.getCellWidth()) {
+ dragView.setDragRegion(dragView.getDragRegionLeft(), dragView.getDragRegionTop(),
+ currentLayout.getCellWidth(), dragView.getDragRegionHeight());
+ }
+ }
+ }
if (currentLayout != mDragTargetLayout) {
if (mDragTargetLayout != null) {
mDragTargetLayout.onDragComplete();
@@ -1404,23 +1539,14 @@
mDragTargetLayout = currentLayout;
}
- // Find the top left corner of the item
- int originX = x - xOffset;
- int originY = y - yOffset;
-
- // If not dragging from the Workspace, the size of dragView might not match the cell size
- if (!source.equals(this)) {
- // Break the drag view up into evenly sized chunks based on its spans
- int chunkWidth = dragView.getWidth() / item.spanX;
- int chunkHeight = dragView.getHeight() / item.spanY;
-
- // Adjust the origin for a cell centered at the top left chunk
- originX += (chunkWidth - currentLayout.getCellWidth()) / 2;
- originY += (chunkHeight - currentLayout.getCellHeight()) / 2;
+ // only visualize the drop locations for moving icons within the home screen on tablet
+ // on phone, we also visualize icons dragged in from All Apps
+ if ((!LauncherApplication.isScreenXLarge() || source == this)
+ && mDragTargetLayout != null) {
+ final View child = (mDragInfo == null) ? null : mDragInfo.cell;
+ mDragTargetLayout.visualizeDropLocation(
+ child, originX, originY, item.spanX, item.spanY);
}
-
- final View child = (mDragInfo == null) ? null : mDragInfo.cell;
- currentLayout.visualizeDropLocation(child, originX, originY, item.spanX, item.spanY);
}
public void onDragExit(DragSource source, int x, int y, int xOffset,
@@ -1460,7 +1586,11 @@
break;
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
cellLayout.setTagToCellInfoForPoint(x, y);
- mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName, cellLayout.getTag());
+ int[] position = new int[2];
+ position[0] = x;
+ position[1] = y;
+ mLauncher.addAppWidgetFromDrop(((LauncherAppWidgetInfo)dragInfo).providerName,
+ cellLayout.getTag(), position);
break;
default:
throw new IllegalStateException("Unknown item type: "