Merge "Require valid arrays when adding and binding new Apps. (Bug 11627095)" into jb-ub-now-jolly-elf
diff --git a/src/com/android/launcher3/AppsCustomizePagedView.java b/src/com/android/launcher3/AppsCustomizePagedView.java
index d9ca157..688ff82 100644
--- a/src/com/android/launcher3/AppsCustomizePagedView.java
+++ b/src/com/android/launcher3/AppsCustomizePagedView.java
@@ -916,6 +916,13 @@
}
@Override
+ public float getIntrinsicIconScaleFactor() {
+ LauncherAppState app = LauncherAppState.getInstance();
+ DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
+ return (float) grid.allAppsIconSizePx / grid.iconSizePx;
+ }
+
+ @Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
cancelAllTasks();
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index ab48233..1bfaa23 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -198,7 +198,7 @@
* @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 dragLayerX, int dragLayerY,
+ public DragView startDrag(Bitmap b, int dragLayerX, int dragLayerY,
DragSource source, Object dragInfo, int dragAction, Point dragOffset, Rect dragRegion,
float initialDragViewScale) {
if (PROFILE_DRAWING_DURING_DRAG) {
@@ -245,6 +245,7 @@
mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
dragView.show(mMotionDownX, mMotionDownY);
handleMoveEvent(mMotionDownX, mMotionDownY);
+ return dragView;
}
/**
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index 159d7d9..dc0ba90 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -522,14 +522,18 @@
scale *= childScale;
int toX = coord[0];
int toY = coord[1];
+ float toScale = scale;
if (child instanceof TextView) {
TextView tv = (TextView) child;
+ // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
+ // the workspace may have smaller icon bounds).
+ toScale = scale / dragView.getIntrinsicIconScaleFactor();
// The child may be scaled (always about the center of the view) so to account for it,
// we have to offset the position by the scaled size. Once we do that, we can center
// the drag view about the scaled child view.
- toY += Math.round(scale * tv.getPaddingTop());
- toY -= dragView.getMeasuredHeight() * (1 - scale) / 2;
+ toY += Math.round(toScale * tv.getPaddingTop());
+ toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
} else if (child instanceof FolderIcon) {
// Account for holographic blur padding on the drag view
@@ -555,7 +559,7 @@
}
}
};
- animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, scale, scale,
+ animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
onCompleteRunnable, ANIMATION_END_DISAPPEAR, duration, anchorView);
}
diff --git a/src/com/android/launcher3/DragSource.java b/src/com/android/launcher3/DragSource.java
index 2ef99ae..cca9ab1 100644
--- a/src/com/android/launcher3/DragSource.java
+++ b/src/com/android/launcher3/DragSource.java
@@ -30,6 +30,11 @@
*/
boolean supportsFlingToDelete();
+ /*
+ * @return the scale of the icons over the workspace icon size
+ */
+ float getIntrinsicIconScaleFactor();
+
/**
* A callback specifically made back to the source after an item from this source has been flung
* to be deleted on a DropTarget. In such a situation, this method will be called after
diff --git a/src/com/android/launcher3/DragView.java b/src/com/android/launcher3/DragView.java
index 686cf62..b66b55c 100644
--- a/src/com/android/launcher3/DragView.java
+++ b/src/com/android/launcher3/DragView.java
@@ -51,6 +51,9 @@
private float mOffsetX = 0.0f;
private float mOffsetY = 0.0f;
private float mInitialScale = 1f;
+ // The intrinsic icon scale factor is the scale factor for a drag icon over the workspace
+ // size. This is ignored for non-icons.
+ private float mIntrinsicIconScale = 1f;
/**
* Construct the drag view.
@@ -120,6 +123,15 @@
mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
}
+ /** Sets the scale of the view over the normal workspace icon size. */
+ public void setIntrinsicIconScaleFactor(float scale) {
+ mIntrinsicIconScale = scale;
+ }
+
+ public float getIntrinsicIconScaleFactor() {
+ return mIntrinsicIconScale;
+ }
+
public float getOffsetY() {
return mOffsetY;
}
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index bce6707..83be143 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -27,19 +27,11 @@
class FastBitmapDrawable extends Drawable {
private Bitmap mBitmap;
private int mAlpha;
- private int mWidth;
- private int mHeight;
private final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG);
FastBitmapDrawable(Bitmap b) {
- mAlpha = 255;
+ mAlpha = 255;
mBitmap = b;
- if (b != null) {
- mWidth = mBitmap.getWidth();
- mHeight = mBitmap.getHeight();
- } else {
- mWidth = mHeight = 0;
- }
}
@Override
@@ -76,32 +68,22 @@
@Override
public int getIntrinsicWidth() {
- return mWidth;
+ return getBounds().width();
}
@Override
public int getIntrinsicHeight() {
- return mHeight;
+ return getBounds().height();
}
@Override
public int getMinimumWidth() {
- return mWidth;
+ return getBounds().width();
}
@Override
public int getMinimumHeight() {
- return mHeight;
- }
-
- public void setBitmap(Bitmap b) {
- mBitmap = b;
- if (b != null) {
- mWidth = mBitmap.getWidth();
- mHeight = mBitmap.getHeight();
- } else {
- mWidth = mHeight = 0;
- }
+ return getBounds().height();
}
public Bitmap getBitmap() {
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index f26d01f..1d234ff 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -119,6 +119,11 @@
private int DRAG_MODE_REORDER = 1;
private int mDragMode = DRAG_MODE_NONE;
+ // We avoid measuring the scroll view with a 0 width or height, as this
+ // results in CellLayout being measured as UNSPECIFIED, which it does
+ // not support.
+ private static final int MIN_CONTENT_DIMEN = 5;
+
private boolean mDestroyed;
private AutoScrollHelper mAutoScrollHelper;
@@ -787,6 +792,11 @@
}
@Override
+ public float getIntrinsicIconScaleFactor() {
+ return 1f;
+ }
+
+ @Override
public boolean supportsFlingToDelete() {
return true;
}
@@ -961,8 +971,13 @@
int maxContentAreaHeight = grid.availableHeightPx -
workspacePadding.top - workspacePadding.bottom -
mFolderNameHeight;
- return Math.min(maxContentAreaHeight,
+ int height = Math.min(maxContentAreaHeight,
mContent.getDesiredHeight());
+ return Math.max(height, MIN_CONTENT_DIMEN);
+ }
+
+ private int getContentAreaWidth() {
+ return Math.max(mContent.getDesiredWidth(), MIN_CONTENT_DIMEN);
}
private int getFolderHeight() {
@@ -974,11 +989,12 @@
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getPaddingLeft() + getPaddingRight() + mContent.getDesiredWidth();
int height = getFolderHeight();
- int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(mContent.getDesiredWidth(),
+ int contentAreaWidthSpec = MeasureSpec.makeMeasureSpec(getContentAreaWidth(),
MeasureSpec.EXACTLY);
int contentAreaHeightSpec = MeasureSpec.makeMeasureSpec(getContentAreaHeight(),
MeasureSpec.EXACTLY);
- mContent.setFixedSize(mContent.getDesiredWidth(), mContent.getDesiredHeight());
+
+ mContent.setFixedSize(getContentAreaWidth(), getContentAreaHeight());
mScrollView.measure(contentAreaWidthSpec, contentAreaHeightSpec);
mFolderName.measure(contentAreaWidthSpec,
MeasureSpec.makeMeasureSpec(mFolderNameHeight, MeasureSpec.EXACTLY));
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0c14ed9..cfc5c48 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -45,7 +45,6 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
@@ -113,6 +112,7 @@
import java.util.Date;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Default launcher application.
@@ -181,8 +181,10 @@
private static final String RUNTIME_STATE_PENDING_ADD_SPAN_Y = "launcher.add_span_y";
// Type: parcelable
private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_INFO = "launcher.add_widget_info";
- // Type: parcelable
+ // Type: parcelable
private static final String RUNTIME_STATE_PENDING_ADD_WIDGET_ID = "launcher.add_widget_id";
+ // Type: int[]
+ private static final String RUNTIME_STATE_VIEW_IDS = "launcher.view_ids";
private static final String TOOLBAR_ICON_METADATA_NAME = "com.android.launcher.toolbar_icon";
private static final String TOOLBAR_SEARCH_ICON_METADATA_NAME =
@@ -207,6 +209,9 @@
private static final Object sLock = new Object();
private static int sScreen = DEFAULT_SCREEN;
+ private HashMap<Integer, Integer> mItemIdToViewId = new HashMap<Integer, Integer>();
+ private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
+
// How long to wait before the new-shortcut animation automatically pans the workspace
private static int NEW_APPS_PAGE_MOVE_DELAY = 500;
private static int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5;
@@ -671,6 +676,34 @@
}
/**
+ * Copied from View -- the View version of the method isn't called
+ * anywhere else in our process and only exists for API level 17+,
+ * so it's ok to keep our own version with no API requirement.
+ */
+ public static int generateViewId() {
+ for (;;) {
+ final int result = sNextGeneratedId.get();
+ // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
+ int newValue = result + 1;
+ if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
+ if (sNextGeneratedId.compareAndSet(result, newValue)) {
+ return result;
+ }
+ }
+ }
+
+ public int getViewIdForItem(ItemInfo info) {
+ // This cast is safe given the > 2B range for int.
+ int itemId = (int) info.id;
+ if (mItemIdToViewId.containsKey(itemId)) {
+ return mItemIdToViewId.get(itemId);
+ }
+ int viewId = generateViewId();
+ mItemIdToViewId.put(itemId, viewId);
+ return viewId;
+ }
+
+ /**
* Returns whether we should delay spring loaded mode -- for shortcuts and widgets that have
* a configuration step, this allows the proper animations to run after other transitions.
*/
@@ -1108,6 +1141,7 @@
*
* @param savedState The previous state.
*/
+ @SuppressWarnings("unchecked")
private void restoreState(Bundle savedState) {
if (savedState == null) {
return;
@@ -1160,6 +1194,8 @@
int currentIndex = savedState.getInt("apps_customize_currentIndex");
mAppsCustomizeContent.restorePageForIndex(currentIndex);
}
+ mItemIdToViewId = (HashMap<Integer, Integer>)
+ savedState.getSerializable(RUNTIME_STATE_VIEW_IDS);
}
/**
@@ -1704,7 +1740,7 @@
// In all these cases, only animate if we're already on home
mWorkspace.exitWidgetResizeMode();
if (alreadyOnHome && mState == State.WORKSPACE && !mWorkspace.isTouchActive() &&
- openFolder == null) {
+ openFolder == null && shouldMoveToDefaultScreenOnHomeIntent()) {
mWorkspace.moveToDefaultScreen(true);
}
@@ -1730,6 +1766,8 @@
if (mAppsCustomizeTabHost != null) {
mAppsCustomizeTabHost.reset();
}
+
+ onHomeIntent();
}
if (DEBUG_RESUME_TIME) {
@@ -1737,6 +1775,21 @@
}
}
+ /**
+ * Override point for subclasses to prevent movement to the default screen when the home
+ * button is pressed. Used (for example) in GEL, to prevent movement during a search.
+ */
+ protected boolean shouldMoveToDefaultScreenOnHomeIntent() {
+ return true;
+ }
+
+ /**
+ * Override point for subclasses to provide custom behaviour for when a home intent is fired.
+ */
+ protected void onHomeIntent() {
+ // Do nothing
+ }
+
@Override
public void onRestoreInstanceState(Bundle state) {
super.onRestoreInstanceState(state);
@@ -1784,6 +1837,7 @@
int currentIndex = mAppsCustomizeContent.getSaveInstanceStateIndex();
outState.putInt("apps_customize_currentIndex", currentIndex);
}
+ outState.putSerializable(RUNTIME_STATE_VIEW_IDS, mItemIdToViewId);
}
@Override
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index f36c815..8ef0ff2 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -949,7 +949,9 @@
}
// Get the canonical child id to uniquely represent this view in this screen
- int childId = LauncherModel.getCellLayoutChildId(container, screenId, x, y, spanX, spanY);
+ ItemInfo info = (ItemInfo) child.getTag();
+ int childId = mLauncher.getViewIdForItem(info);
+
boolean markCellsAsOccupied = !(child instanceof Folder);
if (!layout.addViewToCellLayout(child, insert ? 0 : -1, childId, lp, markCellsAsOccupied)) {
// TODO: This branch occurs when the workspace is adding views
@@ -2108,7 +2110,8 @@
if (stateIsSmall) {
finalAlpha = 0f;
} else if (stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
- finalAlpha = i == getNextPage() ? 1f : 0f;
+
+ finalAlpha = (i == getNextPage() || i < numCustomPages()) ? 1f : 0f;
} else {
finalAlpha = 1f;
}
@@ -2349,6 +2352,11 @@
final CellLayout cl = (CellLayout) getChildAt(i);
cl.setShortcutAndWidgetAlpha(1f);
}
+ } else {
+ for (int i = 0; i < numCustomPages(); i++) {
+ final CellLayout cl = (CellLayout) getChildAt(i);
+ cl.setShortcutAndWidgetAlpha(1f);
+ }
}
showCustomContentIfNecessary();
}
@@ -2536,8 +2544,16 @@
icon.clearPressedOrFocusedBackground();
}
- mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
+ if (child.getTag() == null || !(child.getTag() instanceof ItemInfo)) {
+ String msg = "Drag started with a view that has no tag set. This "
+ + "will cause a crash (issue 11627249) down the line. "
+ + "View: " + child + " tag: " + child.getTag();
+ throw new IllegalStateException(msg);
+ }
+
+ DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source, child.getTag(),
DragController.DRAG_ACTION_MOVE, dragVisualizeOffset, dragRect, scale);
+ dv.setIntrinsicIconScaleFactor(source.getIntrinsicIconScaleFactor());
if (child.getParent() instanceof ShortcutAndWidgetContainer) {
mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent();
@@ -2883,8 +2899,6 @@
lp.cellHSpan = item.spanX;
lp.cellVSpan = item.spanY;
lp.isLockedToGrid = true;
- cell.setId(LauncherModel.getCellLayoutChildId(container, mDragInfo.screenId,
- mTargetCell[0], mTargetCell[1], mDragInfo.spanX, mDragInfo.spanY));
if (container != LauncherSettings.Favorites.CONTAINER_HOTSEAT &&
cell instanceof LauncherAppWidgetHostView) {
@@ -4141,6 +4155,11 @@
}
@Override
+ public float getIntrinsicIconScaleFactor() {
+ return 1f;
+ }
+
+ @Override
public boolean supportsFlingToDelete() {
return true;
}
@@ -4561,6 +4580,7 @@
child.requestFocus();
}
}
+ exitWidgetResizeMode();
}
@Override