summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/search_drop_target_bar.xml20
-rw-r--r--res/layout/widget_cell.xml4
-rw-r--r--res/values/strings.xml8
-rw-r--r--src/com/android/launcher3/AppWidgetResizeFrame.java2
-rw-r--r--src/com/android/launcher3/AppsContainerRecyclerView.java4
-rw-r--r--src/com/android/launcher3/ButtonDropTarget.java19
-rw-r--r--src/com/android/launcher3/CellLayout.java360
-rw-r--r--src/com/android/launcher3/DeferredHandler.java47
-rw-r--r--src/com/android/launcher3/DeleteDropTarget.java14
-rw-r--r--src/com/android/launcher3/DeviceProfile.java3
-rw-r--r--src/com/android/launcher3/DragController.java8
-rw-r--r--src/com/android/launcher3/DragLayer.java3
-rw-r--r--src/com/android/launcher3/Folder.java27
-rw-r--r--src/com/android/launcher3/FolderInfo.java1
-rw-r--r--src/com/android/launcher3/FolderPagedView.java215
-rw-r--r--src/com/android/launcher3/InfoDropTarget.java11
-rw-r--r--src/com/android/launcher3/Launcher.java17
-rw-r--r--src/com/android/launcher3/LauncherAccessibilityDelegate.java53
-rw-r--r--src/com/android/launcher3/LauncherModel.java125
-rw-r--r--src/com/android/launcher3/LauncherStateTransitionAnimation.java4
-rw-r--r--src/com/android/launcher3/SearchDropTargetBar.java15
-rw-r--r--src/com/android/launcher3/ShortcutAndWidgetContainer.java8
-rw-r--r--src/com/android/launcher3/UninstallDropTarget.java17
-rw-r--r--src/com/android/launcher3/Utilities.java33
-rw-r--r--src/com/android/launcher3/Workspace.java20
-rw-r--r--src/com/android/launcher3/util/LongArrayMap.java65
-rw-r--r--src/com/android/launcher3/widget/WidgetCell.java212
-rw-r--r--src/com/android/launcher3/widget/WidgetHostViewLoader.java197
-rw-r--r--src/com/android/launcher3/widget/WidgetsContainerView.java67
-rw-r--r--src/com/android/launcher3/widget/WidgetsListAdapter.java5
30 files changed, 654 insertions, 930 deletions
diff --git a/res/layout/search_drop_target_bar.xml b/res/layout/search_drop_target_bar.xml
index e383d74c0..69f42bb4c 100644
--- a/res/layout/search_drop_target_bar.xml
+++ b/res/layout/search_drop_target_bar.xml
@@ -44,26 +44,26 @@
style="@style/DropTargetButtonContainer"
android:layout_weight="1" >
- <!-- Uninstall target -->
+ <!-- Info target -->
- <com.android.launcher3.UninstallDropTarget
- android:id="@+id/uninstall_target_text"
+ <com.android.launcher3.InfoDropTarget
+ android:id="@+id/info_target_text"
style="@style/DropTargetButton"
- android:drawableStart="@drawable/uninstall_target_selector"
- android:text="@string/delete_target_uninstall_label" />
+ android:drawableStart="@drawable/info_target_selector"
+ android:text="@string/info_target_label" />
</FrameLayout>
<FrameLayout
style="@style/DropTargetButtonContainer"
android:layout_weight="1" >
- <!-- Info target -->
+ <!-- Uninstall target -->
- <com.android.launcher3.InfoDropTarget
- android:id="@+id/info_target_text"
+ <com.android.launcher3.UninstallDropTarget
+ android:id="@+id/uninstall_target_text"
style="@style/DropTargetButton"
- android:drawableStart="@drawable/info_target_selector"
- android:text="@string/info_target_label" />
+ android:drawableStart="@drawable/uninstall_target_selector"
+ android:text="@string/delete_target_uninstall_label" />
</FrameLayout>
</LinearLayout>
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 50294c035..64ddea1ae 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -47,7 +47,7 @@
android:fadingEdge="horizontal"
android:textColor="#FFFFFFFF"
- android:textSize="12sp"
+ android:textSize="16sp"
android:textAlignment="viewStart"
android:fontFamily="sans-serif-condensed"
android:shadowRadius="2.0"
@@ -64,7 +64,7 @@
android:layout_weight="0"
android:gravity="start"
android:textColor="#FFFFFFFF"
- android:textSize="12sp"
+ android:textSize="16sp"
android:textAlignment="viewStart"
android:fontFamily="sans-serif-condensed"
android:shadowRadius="2.0"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 52306e30e..a68f53a91 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -77,7 +77,7 @@
<!-- Search bar text in the apps view. [CHAR_LIMIT=50] -->
<string name="apps_view_search_bar_hint">Search Apps</string>
<!-- Loading apps text. [CHAR_LIMIT=50] -->
- <string name="loading_apps_message">Loading Apps...</string>
+ <string name="loading_apps_message">Loading Apps&#8230;</string>
<!-- No-search-results text. [CHAR_LIMIT=50] -->
<string name="apps_view_no_search_results">No Apps found matching \"<xliff:g id="query" example="Android">%1$s</xliff:g>\"</string>
@@ -91,8 +91,6 @@
<string name="rename_action">OK</string>
<!-- Buttons in Rename folder dialog box -->
<string name="cancel_action">Cancel</string>
- <!-- Label for button to sort folder contents. [CHAR_LIMIT=10] -->
- <string name="sort_alphabetical">A-Z</string>
<!-- Shortcuts -->
<skip />
@@ -309,13 +307,13 @@ s -->
<!-- Strings for accessibility actions -->
<!-- Accessibility action to add an app to workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
- <string name="action_add_to_workspace">Add To Workspace</string>
+ <string name="action_add_to_workspace">Add to workspace</string>
<!-- Accessibility confirmation for item added to workspace [DO NOT TRANSLATE] -->
<string name="item_added_to_workspace">Item added to workspace</string>
<!-- Accessibility confirmation for item removed [DO NOT TRANSLATE] -->
- <string name="item_removed_from_workspace">Item removed from workspace</string>
+ <string name="item_removed">Item removed</string>
<!-- Accessibility action to move an item on the workspace. [CHAR_LIMIT=30] [DO NOT TRANSLATE] -->
<string name="action_move">Move Item</string>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 240250750..3c698c014 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -349,7 +349,7 @@ public class AppWidgetResizeFrame extends FrameLayout {
mTmpRect.right, mTmpRect.bottom);
}
- static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
+ public static Rect getWidgetSizeRanges(Launcher launcher, int spanX, int spanY, Rect rect) {
if (rect == null) {
rect = new Rect();
}
diff --git a/src/com/android/launcher3/AppsContainerRecyclerView.java b/src/com/android/launcher3/AppsContainerRecyclerView.java
index 16244ee35..f8897128e 100644
--- a/src/com/android/launcher3/AppsContainerRecyclerView.java
+++ b/src/com/android/launcher3/AppsContainerRecyclerView.java
@@ -156,6 +156,10 @@ public class AppsContainerRecyclerView extends RecyclerView
handleTouchEvent(ev);
}
+ public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
+ // Do nothing
+ }
+
/**
* Handles the touch event and determines whether to show the fast scroller (or updates it if
* it is already showing).
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 5b399087a..fb49df5df 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -26,18 +26,19 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
import android.util.AttributeSet;
import android.view.View;
+import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import android.widget.TextView;
-import com.android.launcher3.R;
import com.android.launcher3.util.Thunk;
/**
* Implements a DropTarget.
*/
-public abstract class ButtonDropTarget extends TextView implements DropTarget, DragController.DragListener {
+public abstract class ButtonDropTarget extends TextView
+ implements DropTarget, DragController.DragListener, OnClickListener {
private static int DRAG_VIEW_DROP_DURATION = 285;
@@ -256,4 +257,18 @@ public abstract class ButtonDropTarget extends TextView implements DropTarget, D
public void getLocationInDragLayer(int[] loc) {
mLauncher.getDragLayer().getLocationInDragLayer(this, loc);
}
+
+ public void enableAccessibleDrag(boolean enable) {
+ setOnClickListener(enable ? this : null);
+ }
+
+ protected String getAccessibilityDropConfirmation() {
+ return null;
+ }
+
+ @Override
+ public void onClick(View v) {
+ LauncherAppState.getInstance().getAccessibilityDelegate()
+ .handleAccessibleDrop(this, null, getAccessibilityDropConfirmation());
+ }
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index f4afb954d..85653bef7 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -48,9 +48,7 @@ import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.Animation;
import android.view.animation.DecelerateInterpolator;
-import android.view.animation.LayoutAnimationController;
import com.android.launcher3.FolderIcon.FolderRingAnimator;
import com.android.launcher3.LauncherAccessibilityDelegate.DragType;
@@ -121,7 +119,6 @@ public class CellLayout extends ViewGroup {
// If we're actively dragging something over this screen, mIsDragOverlapping is true
private boolean mIsDragOverlapping = false;
- boolean mUseActiveGlowBackground = false;
// These arrays are used to implement the drag visualization on x-large screens.
// They are used as circular arrays, indexed by mDragOutlineCurrent.
@@ -557,7 +554,7 @@ public class CellLayout extends ViewGroup {
Resources res = getContext().getResources();
View child = getChildAt(x, y);
if (child == null || child == dragInfo.item) {
- return res.getString(R.string.move_to_empty_cell, x, y);
+ return res.getString(R.string.move_to_empty_cell, x + 1, y + 1);
} else {
ItemInfo info = (ItemInfo) child.getTag();
if (info instanceof AppInfo || info instanceof ShortcutInfo) {
@@ -684,10 +681,6 @@ public class CellLayout extends ViewGroup {
}
}
- void setUseActiveGlowBackground(boolean use) {
- mUseActiveGlowBackground = use;
- }
-
void disableBackground() {
mDrawBackground = false;
}
@@ -703,7 +696,6 @@ public class CellLayout extends ViewGroup {
void setIsDragOverlapping(boolean isDragOverlapping) {
if (mIsDragOverlapping != isDragOverlapping) {
mIsDragOverlapping = isDragOverlapping;
- setUseActiveGlowBackground(mIsDragOverlapping);
invalidate();
}
}
@@ -722,7 +714,7 @@ public class CellLayout extends ViewGroup {
if (mDrawBackground && mBackgroundAlpha > 0.0f) {
Drawable bg;
- if (mUseActiveGlowBackground) {
+ if (mIsDragOverlapping) {
// In the mini case, we draw the active_glow bg *over* the active background
bg = mActiveGlowBackground;
} else {
@@ -906,7 +898,7 @@ public class CellLayout extends ViewGroup {
}
public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
- boolean markCells, boolean inLayout) {
+ boolean markCells) {
final LayoutParams lp = params;
// Hotseat icons - remove text
@@ -927,7 +919,7 @@ public class CellLayout extends ViewGroup {
if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
child.setId(childId);
- mShortcutsAndWidgets.addView(child, index, lp, inLayout);
+ mShortcutsAndWidgets.addView(child, index, lp);
if (markCells) markCellsAsOccupiedForView(child);
@@ -936,11 +928,6 @@ public class CellLayout extends ViewGroup {
return false;
}
- public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params,
- boolean markCells) {
- return addViewToCellLayout(child, index, childId, params, markCells, false);
- }
-
@Override
public void removeAllViews() {
clearOccupiedCells();
@@ -955,10 +942,6 @@ public class CellLayout extends ViewGroup {
}
}
- public void removeViewWithoutMarkingCells(View view) {
- mShortcutsAndWidgets.removeView(view);
- }
-
@Override
public void removeView(View view) {
markCellsAsUnoccupiedForView(view);
@@ -1088,9 +1071,7 @@ public class CellLayout extends ViewGroup {
public float getDistanceFromCell(float x, float y, int[] cell) {
cellToCenterPoint(cell[0], cell[1], mTmpPoint);
- float distance = (float) Math.sqrt( Math.pow(x - mTmpPoint[0], 2) +
- Math.pow(y - mTmpPoint[1], 2));
- return distance;
+ return (float) Math.hypot(x - mTmpPoint[0], y - mTmpPoint[1]);
}
int getCellWidth() {
@@ -1109,28 +1090,6 @@ public class CellLayout extends ViewGroup {
return mHeightGap;
}
- Rect getContentRect(Rect r) {
- if (r == null) {
- r = new Rect();
- }
- int left = getPaddingLeft();
- int top = getPaddingTop();
- int right = left + getWidth() - getPaddingLeft() - getPaddingRight();
- int bottom = top + getHeight() - getPaddingTop() - getPaddingBottom();
- r.set(left, top, right, bottom);
- return r;
- }
-
- /** Return a rect that has the cellWidth/cellHeight (left, top), and
- * widthGap/heightGap (right, bottom) */
- static void getMetrics(Rect metrics, int paddedMeasureWidth,
- int paddedMeasureHeight, int countX, int countY) {
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- metrics.set(grid.calculateCellWidth(paddedMeasureWidth, countX),
- grid.calculateCellHeight(paddedMeasureHeight, countY), 0, 0);
- }
-
public void setFixedSize(int width, int height) {
mFixedWidth = width;
mFixedHeight = height;
@@ -1246,7 +1205,6 @@ public class CellLayout extends ViewGroup {
}
public void setBackgroundAlphaMultiplier(float multiplier) {
-
if (mBackgroundAlphaMultiplier != multiplier) {
mBackgroundAlphaMultiplier = multiplier;
invalidate();
@@ -1360,36 +1318,6 @@ public class CellLayout extends ViewGroup {
return false;
}
- /**
- * Estimate where the top left cell of the dragged item will land if it is dropped.
- *
- * @param originX The X value of the top left corner of the item
- * @param originY The Y value of the top left corner of the item
- * @param spanX The number of horizontal cells that the item spans
- * @param spanY The number of vertical cells that the item spans
- * @param result The estimated drop cell X and Y.
- */
- void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
- final int countX = mCountX;
- final int countY = mCountY;
-
- // 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;
- if (rightOverhang > 0) {
- result[0] -= rightOverhang; // Snap to right
- }
- result[0] = Math.max(0, result[0]); // Snap to left
- int bottomOverhang = result[1] + spanY - countY;
- if (bottomOverhang > 0) {
- result[1] -= bottomOverhang; // Snap to bottom
- }
- result[1] = Math.max(0, result[1]); // Snap to top
- }
-
void visualizeDropLocation(View v, Bitmap dragOutline, int originX, int originY, int cellX,
int cellY, int spanX, int spanY, boolean resize, Point dragOffset, Rect dragRegion) {
final int oldDragCellX = mDragCell[0];
@@ -1473,9 +1401,8 @@ public class CellLayout extends ViewGroup {
* @return The X, Y cell of a vacant area that can contain this object,
* nearest the requested location.
*/
- int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY,
- int[] result) {
- return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
+ int[] findNearestVacantArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+ return findNearestVacantArea(pixelX, pixelY, spanX, spanY, spanX, spanY, result, null);
}
/**
@@ -1495,30 +1422,10 @@ public class CellLayout extends ViewGroup {
*/
int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
int spanY, int[] result, int[] resultSpan) {
- return findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null,
+ return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, true,
result, resultSpan);
}
- /**
- * 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.
- * @param spanY Vertical span of the object.
- * @param ignoreOccupied If true, the result can be an occupied cell
- * @param result Array in which to place the result, or null (in which case a new array will
- * be allocated)
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, View ignoreView,
- boolean ignoreOccupied, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY,
- spanX, spanY, ignoreView, ignoreOccupied, result, null, mOccupied);
- }
-
private final Stack<Rect> mTempRectStack = new Stack<Rect>();
private void lazyInitTempRectStack() {
if (mTempRectStack.isEmpty()) {
@@ -1550,12 +1457,9 @@ public class CellLayout extends ViewGroup {
* @return The X, Y cell of a vacant area that can contain this object,
* nearest the requested location.
*/
- int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
- View ignoreView, boolean ignoreOccupied, int[] result, int[] resultSpan,
- boolean[][] occupied) {
+ private int[] findNearestArea(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX,
+ int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
lazyInitTempRectStack();
- // mark space take by ignoreView as available (method checks if ignoreView is null)
- markCellsAsUnoccupiedForView(ignoreView, occupied);
// For items with a spanX / spanY > 1, the passed in point (pixelX, pixelY) corresponds
// to the center of the item, but we are searching based on the top-left cell, so
@@ -1586,7 +1490,7 @@ public class CellLayout extends ViewGroup {
// First, let's see if this thing fits anywhere
for (int i = 0; i < minSpanX; i++) {
for (int j = 0; j < minSpanY; j++) {
- if (occupied[x + i][y + j]) {
+ if (mOccupied[x + i][y + j]) {
continue inner;
}
}
@@ -1603,7 +1507,7 @@ public class CellLayout extends ViewGroup {
while (!(hitMaxX && hitMaxY)) {
if (incX && !hitMaxX) {
for (int j = 0; j < ySize; j++) {
- if (x + xSize > countX -1 || occupied[x + xSize][y + j]) {
+ if (x + xSize > countX -1 || mOccupied[x + xSize][y + j]) {
// We can't move out horizontally
hitMaxX = true;
}
@@ -1613,7 +1517,7 @@ public class CellLayout extends ViewGroup {
}
} else if (!hitMaxY) {
for (int i = 0; i < xSize; i++) {
- if (y + ySize > countY - 1 || occupied[x + i][y + ySize]) {
+ if (y + ySize > countY - 1 || mOccupied[x + i][y + ySize]) {
// We can't move out vertically
hitMaxY = true;
}
@@ -1646,8 +1550,7 @@ public class CellLayout extends ViewGroup {
}
}
validRegions.push(currentRect);
- double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
- + Math.pow(cellXY[1] - pixelY, 2));
+ double distance = Math.hypot(cellXY[0] - pixelX, cellXY[1] - pixelY);
if ((distance <= bestDistance && !contained) ||
currentRect.contains(bestRect)) {
@@ -1662,8 +1565,6 @@ public class CellLayout extends ViewGroup {
}
}
}
- // re-mark space taken by ignoreView as occupied
- markCellsAsOccupiedForView(ignoreView, occupied);
// Return -1, -1 if no suitable location found
if (bestDistance == Double.MAX_VALUE) {
@@ -1717,8 +1618,7 @@ public class CellLayout extends ViewGroup {
}
}
- float distance = (float)
- Math.sqrt((x - cellX) * (x - cellX) + (y - cellY) * (y - cellY));
+ float distance = (float) Math.hypot(x - cellX, y - cellY);
int[] curDirection = mTmpPoint;
computeDirectionVector(x - cellX, y - cellY, curDirection);
// The direction score is just the dot product of the two candidate direction
@@ -2334,7 +2234,7 @@ public class CellLayout extends ViewGroup {
}
}
- ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
+ private ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX, int minSpanY,
int spanX, int spanY, int[] direction, View dragView, boolean decX,
ItemConfiguration solution) {
// Copy the current state into the solution. This solution will be manipulated as necessary.
@@ -2623,7 +2523,7 @@ public class CellLayout extends ViewGroup {
mLauncher.getWorkspace().updateItemLocationsInDatabase(this);
}
- public void setUseTempCoords(boolean useTempCoords) {
+ private void setUseTempCoords(boolean useTempCoords) {
int childCount = mShortcutsAndWidgets.getChildCount();
for (int i = 0; i < childCount; i++) {
LayoutParams lp = (LayoutParams) mShortcutsAndWidgets.getChildAt(i).getLayoutParams();
@@ -2631,11 +2531,11 @@ public class CellLayout extends ViewGroup {
}
}
- ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
+ private ItemConfiguration findConfigurationNoShuffle(int pixelX, int pixelY, int minSpanX, int minSpanY,
int spanX, int spanY, View dragView, ItemConfiguration solution) {
int[] result = new int[2];
int[] resultSpan = new int[2];
- findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, null, result,
+ findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result,
resultSpan);
if (result[0] >= 0 && result[1] >= 0) {
copyCurrentStateToSolution(solution, false);
@@ -2952,45 +2852,6 @@ 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.
- * @param spanY Vertical span of the object.
- * @param ignoreView Considers space occupied by this view as unoccupied
- * @param result Previously returned value to possibly recycle.
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestVacantArea(
- int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY, ignoreView, true, result);
- }
-
- /**
- * 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 minSpanX The minimum horizontal span required
- * @param minSpanY The minimum vertical span required
- * @param spanX Horizontal span of the object.
- * @param spanY Vertical span of the object.
- * @param ignoreView Considers space occupied by this view as unoccupied
- * @param result Previously returned value to possibly recycle.
- * @return The X, Y cell of a vacant area that can contain this object,
- * nearest the requested location.
- */
- int[] findNearestVacantArea(int pixelX, int pixelY, int minSpanX, int minSpanY,
- int spanX, int spanY, View ignoreView, int[] result, int[] resultSpan) {
- return findNearestArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, ignoreView, true,
- result, resultSpan, mOccupied);
- }
-
- /**
* Find a starting cell position that will fit the given bounds nearest the requested
* cell location. Uses Euclidean distance to score multiple vacant areas.
*
@@ -3003,9 +2864,8 @@ public class CellLayout extends ViewGroup {
* @return The X, Y cell of a vacant area that can contain this object,
* nearest the requested location.
*/
- int[] findNearestArea(
- int pixelX, int pixelY, int spanX, int spanY, int[] result) {
- return findNearestArea(pixelX, pixelY, spanX, spanY, null, false, result);
+ int[] findNearestArea(int pixelX, int pixelY, int spanX, int spanY, int[] result) {
+ return findNearestArea(pixelX, pixelY, spanX, spanY, spanX, spanY, false, result, null);
}
boolean existsEmptyCell() {
@@ -3026,103 +2886,32 @@ public class CellLayout extends ViewGroup {
* @return True if a vacant cell of the specified dimension was found, false otherwise.
*/
public boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
- return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null, mOccupied);
- }
-
- /**
- * Like above, but ignores any cells occupied by the item "ignoreView"
- *
- * @param cellXY The array that will contain the position of a vacant cell if such a cell
- * can be found.
- * @param spanX The horizontal span of the cell we want to find.
- * @param spanY The vertical span of the cell we want to find.
- * @param ignoreView The home screen item we should treat as not occupying any space
- * @return
- */
- boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
- return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1,
- ignoreView, mOccupied);
- }
-
- /**
- * Like above, but if intersectX and intersectY are not -1, then this method will try to
- * return coordinates for rectangles that contain the cell [intersectX, intersectY]
- *
- * @param spanX The horizontal span of the cell we want to find.
- * @param spanY The vertical span of the cell we want to find.
- * @param ignoreView The home screen item we should treat as not occupying any space
- * @param intersectX The X coordinate of the cell that we should try to overlap
- * @param intersectX The Y coordinate of the cell that we should try to overlap
- *
- * @return True if a vacant cell of the specified dimension was found, false otherwise.
- */
- boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
- int intersectX, int intersectY) {
- return findCellForSpanThatIntersectsIgnoring(
- cellXY, spanX, spanY, intersectX, intersectY, null, mOccupied);
- }
-
- /**
- * The superset of the above two methods
- */
- boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
- int intersectX, int intersectY, View ignoreView, boolean occupied[][]) {
- // mark space take by ignoreView as available (method checks if ignoreView is null)
- markCellsAsUnoccupiedForView(ignoreView, occupied);
-
boolean foundCell = false;
- while (true) {
- int startX = 0;
- if (intersectX >= 0) {
- startX = Math.max(startX, intersectX - (spanX - 1));
- }
- int endX = mCountX - (spanX - 1);
- if (intersectX >= 0) {
- endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
- }
- int startY = 0;
- if (intersectY >= 0) {
- startY = Math.max(startY, intersectY - (spanY - 1));
- }
- int endY = mCountY - (spanY - 1);
- if (intersectY >= 0) {
- endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
- }
-
- for (int y = startY; y < endY && !foundCell; y++) {
- inner:
- for (int x = startX; x < endX; x++) {
- for (int i = 0; i < spanX; i++) {
- for (int j = 0; j < spanY; j++) {
- if (occupied[x + i][y + j]) {
- // small optimization: we can skip to after the column we just found
- // an occupied cell
- x += i;
- continue inner;
- }
+ final int endX = mCountX - (spanX - 1);
+ final int endY = mCountY - (spanY - 1);
+
+ for (int y = 0; y < endY && !foundCell; y++) {
+ inner:
+ for (int x = 0; x < endX; x++) {
+ for (int i = 0; i < spanX; i++) {
+ for (int j = 0; j < spanY; j++) {
+ if (mOccupied[x + i][y + j]) {
+ // small optimization: we can skip to after the column we just found
+ // an occupied cell
+ x += i;
+ continue inner;
}
}
- if (cellXY != null) {
- cellXY[0] = x;
- cellXY[1] = y;
- }
- foundCell = true;
- break;
}
- }
- if (intersectX == -1 && intersectY == -1) {
+ if (cellXY != null) {
+ cellXY[0] = x;
+ cellXY[1] = y;
+ }
+ foundCell = true;
break;
- } else {
- // if we failed to find anything, try again but without any requirements of
- // intersecting
- intersectX = -1;
- intersectY = -1;
- continue;
}
}
- // re-mark space taken by ignoreView as occupied
- markCellsAsOccupiedForView(ignoreView, occupied);
return foundCell;
}
@@ -3232,13 +3021,6 @@ public class CellLayout extends ViewGroup {
return result;
}
- public int[] cellSpansToSize(int hSpans, int vSpans) {
- int[] size = new int[2];
- size[0] = hSpans * mCellWidth + (hSpans - 1) * mWidthGap;
- size[1] = vSpans * mCellHeight + (vSpans - 1) * mHeightGap;
- return size;
- }
-
/**
* Calculate the grid spans needed to fit given item
*/
@@ -3262,44 +3044,6 @@ public class CellLayout extends ViewGroup {
info.spanY = spans[1];
}
- /**
- * Find the first vacant cell, if there is one.
- *
- * @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) {
-
- return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
- }
-
- static boolean findVacantCell(int[] vacant, int spanX, int spanY,
- int xCount, int yCount, boolean[][] occupied) {
-
- for (int y = 0; (y + spanY) <= yCount; y++) {
- for (int x = 0; (x + spanX) <= xCount; x++) {
- boolean available = !occupied[x][y];
-out: for (int i = x; i < x + spanX; i++) {
- for (int j = y; j < y + spanY; j++) {
- available = available && !occupied[i][j];
- if (!available) break out;
- }
- }
-
- if (available) {
- vacant[0] = x;
- vacant[1] = y;
- return true;
- }
- }
- }
-
- return false;
- }
-
private void clearOccupiedCells() {
for (int x = 0; x < mCountX; x++) {
for (int y = 0; y < mCountY; y++) {
@@ -3308,27 +3052,16 @@ out: for (int i = x; i < x + spanX; i++) {
}
}
- public void onMove(View view, int newCellX, int newCellY, int newSpanX, int newSpanY) {
- markCellsAsUnoccupiedForView(view);
- markCellsForView(newCellX, newCellY, newSpanX, newSpanY, mOccupied, true);
- }
-
public void markCellsAsOccupiedForView(View view) {
- markCellsAsOccupiedForView(view, mOccupied);
- }
- public void markCellsAsOccupiedForView(View view, boolean[][] occupied) {
if (view == null || view.getParent() != mShortcutsAndWidgets) return;
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, true);
+ markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, true);
}
public void markCellsAsUnoccupiedForView(View view) {
- markCellsAsUnoccupiedForView(view, mOccupied);
- }
- public void markCellsAsUnoccupiedForView(View view, boolean occupied[][]) {
if (view == null || view.getParent() != mShortcutsAndWidgets) return;
LayoutParams lp = (LayoutParams) view.getLayoutParams();
- markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, occupied, false);
+ markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, mOccupied, false);
}
private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean[][] occupied,
@@ -3374,17 +3107,6 @@ out: for (int i = x; i < x + spanX; 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.
diff --git a/src/com/android/launcher3/DeferredHandler.java b/src/com/android/launcher3/DeferredHandler.java
index eb7c26a28..a43ab6723 100644
--- a/src/com/android/launcher3/DeferredHandler.java
+++ b/src/com/android/launcher3/DeferredHandler.java
@@ -20,12 +20,10 @@ import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
-import android.util.Pair;
import com.android.launcher3.util.Thunk;
import java.util.LinkedList;
-import java.util.ListIterator;
/**
* Queue of things to run on a looper thread. Items posted with {@link #post} will not
@@ -35,20 +33,18 @@ import java.util.ListIterator;
* This class is fifo.
*/
public class DeferredHandler {
- @Thunk LinkedList<Pair<Runnable, Integer>> mQueue = new LinkedList<Pair<Runnable, Integer>>();
+ @Thunk LinkedList<Runnable> mQueue = new LinkedList<>();
private MessageQueue mMessageQueue = Looper.myQueue();
private Impl mHandler = new Impl();
@Thunk class Impl extends Handler implements MessageQueue.IdleHandler {
public void handleMessage(Message msg) {
- Pair<Runnable, Integer> p;
Runnable r;
synchronized (mQueue) {
if (mQueue.size() == 0) {
return;
}
- p = mQueue.removeFirst();
- r = p.first;
+ r = mQueue.removeFirst();
}
r.run();
synchronized (mQueue) {
@@ -79,11 +75,8 @@ public class DeferredHandler {
/** Schedule runnable to run after everything that's on the queue right now. */
public void post(Runnable runnable) {
- post(runnable, 0);
- }
- public void post(Runnable runnable, int type) {
synchronized (mQueue) {
- mQueue.add(new Pair<Runnable, Integer>(runnable, type));
+ mQueue.add(runnable);
if (mQueue.size() == 1) {
scheduleNextLocked();
}
@@ -92,31 +85,10 @@ public class DeferredHandler {
/** Schedule runnable to run when the queue goes idle. */
public void postIdle(final Runnable runnable) {
- postIdle(runnable, 0);
- }
- public void postIdle(final Runnable runnable, int type) {
- post(new IdleRunnable(runnable), type);
- }
-
- public void cancelRunnable(Runnable runnable) {
- synchronized (mQueue) {
- while (mQueue.remove(runnable)) { }
- }
- }
- public void cancelAllRunnablesOfType(int type) {
- synchronized (mQueue) {
- ListIterator<Pair<Runnable, Integer>> iter = mQueue.listIterator();
- Pair<Runnable, Integer> p;
- while (iter.hasNext()) {
- p = iter.next();
- if (p.second == type) {
- iter.remove();
- }
- }
- }
+ post(new IdleRunnable(runnable));
}
- public void cancel() {
+ public void cancelAll() {
synchronized (mQueue) {
mQueue.clear();
}
@@ -124,20 +96,19 @@ public class DeferredHandler {
/** Runs all queued Runnables from the calling thread. */
public void flush() {
- LinkedList<Pair<Runnable, Integer>> queue = new LinkedList<Pair<Runnable, Integer>>();
+ LinkedList<Runnable> queue = new LinkedList<>();
synchronized (mQueue) {
queue.addAll(mQueue);
mQueue.clear();
}
- for (Pair<Runnable, Integer> p : queue) {
- p.first.run();
+ for (Runnable r : queue) {
+ r.run();
}
}
void scheduleNextLocked() {
if (mQueue.size() > 0) {
- Pair<Runnable, Integer> p = mQueue.getFirst();
- Runnable peek = p.first;
+ Runnable peek = mQueue.getFirst();
if (peek instanceof IdleRunnable) {
mMessageQueue.addIdleHandler(mHandler);
} else {
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index aa3e66c09..e741b9787 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -29,7 +29,6 @@ import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
-import com.android.launcher3.R;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.WidgetsContainerView;
@@ -59,13 +58,15 @@ public class DeleteDropTarget extends ButtonDropTarget {
setDrawable(R.drawable.remove_target_selector);
}
- public static boolean willAcceptDrop(DragSource source, Object info) {
- return (info instanceof ItemInfo) && source.supportsDeleteDropTarget();
+ public static boolean supportsDrop(Object info) {
+ return (info instanceof ShortcutInfo)
+ || (info instanceof LauncherAppWidgetInfo)
+ || (info instanceof FolderInfo);
}
@Override
protected boolean supportsDrop(DragSource source, Object info) {
- return willAcceptDrop(source, info);
+ return source.supportsDeleteDropTarget() && supportsDrop(info);
}
@Override
@@ -304,4 +305,9 @@ public class DeleteDropTarget extends ButtonDropTarget {
dragLayer.animateView(d.dragView, updateCb, duration, tInterpolator, onAnimationEndRunnable,
DragLayer.ANIMATION_END_DISAPPEAR, null);
}
+
+ @Override
+ protected String getAccessibilityDropConfirmation() {
+ return getResources().getString(R.string.item_removed);
+ }
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 40998a52a..deb807501 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -460,8 +460,7 @@ public class DeviceProfile {
}
@Thunk float dist(PointF p0, PointF p1) {
- return (float) Math.sqrt((p1.x - p0.x)*(p1.x-p0.x) +
- (p1.y-p0.y)*(p1.y-p0.y));
+ return (float) Math.hypot(p1.x - p0.x, p1.y - p0.y);
}
private float weight(PointF a, PointF b,
diff --git a/src/com/android/launcher3/DragController.java b/src/com/android/launcher3/DragController.java
index b24608cb1..3b21c2b55 100644
--- a/src/com/android/launcher3/DragController.java
+++ b/src/com/android/launcher3/DragController.java
@@ -462,8 +462,7 @@ public class DragController {
mLastTouchUpTime = System.currentTimeMillis();
if (mDragging) {
PointF vec = isFlingingToDelete(mDragObject.dragSource);
- if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource,
- mDragObject.dragInfo)) {
+ if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
vec = null;
}
if (vec != null) {
@@ -514,8 +513,7 @@ public class DragController {
checkTouchMove(dropTarget);
// Check if we are hovering over the scroll areas
- mDistanceSinceScroll +=
- Math.sqrt(Math.pow(mLastTouch[0] - x, 2) + Math.pow(mLastTouch[1] - y, 2));
+ mDistanceSinceScroll += Math.hypot(mLastTouch[0] - x, mLastTouch[1] - y);
mLastTouch[0] = x;
mLastTouch[1] = y;
checkScrollState(x, y);
@@ -617,7 +615,7 @@ public class DragController {
if (mDragging) {
PointF vec = isFlingingToDelete(mDragObject.dragSource);
- if (!DeleteDropTarget.willAcceptDrop(mDragObject.dragSource, mDragObject.dragInfo)) {
+ if (!DeleteDropTarget.supportsDrop(mDragObject.dragInfo)) {
vec = null;
}
if (vec != null) {
diff --git a/src/com/android/launcher3/DragLayer.java b/src/com/android/launcher3/DragLayer.java
index ab2e094cb..91f97fa4a 100644
--- a/src/com/android/launcher3/DragLayer.java
+++ b/src/com/android/launcher3/DragLayer.java
@@ -657,8 +657,7 @@ public class DragLayer extends InsettableFrameLayout {
final Runnable onCompleteRunnable, final int animationEndStyle, View anchorView) {
// Calculate the duration of the animation based on the object's distance
- final float dist = (float) Math.sqrt(Math.pow(to.left - from.left, 2) +
- Math.pow(to.top - from.top, 2));
+ final float dist = (float) Math.hypot(to.left - from.left, to.top - from.top);
final Resources res = getResources();
final float maxDist = (float) res.getInteger(R.integer.config_dropAnimMaxDist);
diff --git a/src/com/android/launcher3/Folder.java b/src/com/android/launcher3/Folder.java
index c35ce944f..03a9019e8 100644
--- a/src/com/android/launcher3/Folder.java
+++ b/src/com/android/launcher3/Folder.java
@@ -83,12 +83,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
public static final int SCROLL_HINT_DURATION = DragController.SCROLL_DELAY;
/**
- * Time in milliseconds for which an icon sticks to the target position
- * in case of a sorted folder.
- */
- private static final int SORTED_STICKY_REORDER_DELAY = 1500;
-
- /**
* Fraction of icon width which behave as scroll region.
*/
private static final float ICON_OVERSCROLL_WIDTH_FACTOR = 0.45f;
@@ -417,7 +411,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
if (!(getParent() instanceof DragLayer)) return;
mContent.completePendingPageChanges();
- if (!(mDragInProgress && mContent.mIsSorted)) {
+ if (!mDragInProgress) {
// Open on the first page.
mContent.snapToPageImmediately(0);
}
@@ -459,7 +453,7 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
int rx = (int) Math.max(Math.max(width - getPivotX(), 0), getPivotX());
int ry = (int) Math.max(Math.max(height - getPivotY(), 0), getPivotY());
- float radius = (float) Math.sqrt(rx * rx + ry * ry);
+ float radius = (float) Math.hypot(rx, ry);
AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
Animator reveal = LauncherAnimUtils.createCircularReveal(this, (int) getPivotX(),
(int) getPivotY(), 0, radius);
@@ -533,12 +527,6 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
mIsExternalDrag = true;
mDragInProgress = true;
- if (mContent.mIsSorted) {
- mScrollPauseAlarm.setOnAlarmListener(null);
- mScrollPauseAlarm.cancelAlarm();
- mScrollPauseAlarm.setAlarm(SORTED_STICKY_REORDER_DELAY);
- }
-
// Since this folder opened by another controller, it might not get onDrop or
// onDropComplete. Perform cleanup once drag-n-drop ends.
mDragController.addDragListener(this);
@@ -745,9 +733,18 @@ public class Folder extends LinearLayout implements DragSource, View.OnClickList
replaceFolderWithFinalItem();
}
} else {
- rearrangeChildren();
// The drag failed, we need to return the item to the folder
+ ShortcutInfo info = (ShortcutInfo) d.dragInfo;
+ View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info)
+ ? mCurrentDragView : mContent.createNewView(info);
+ ArrayList<View> views = getItemsInReadingOrder();
+ views.add(info.rank, icon);
+ mContent.arrangeChildren(views, views.size());
+ mItemsInvalidated = true;
+
+ mSuppressOnAdd = true;
mFolderIcon.onDrop(d);
+ mSuppressOnAdd = false;
}
if (target != this) {
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 80b156413..69b2ae78c 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -33,6 +33,7 @@ public class FolderInfo extends ItemInfo {
/**
* The folder is locked in sorted mode
+ * @deprecated
*/
public static final int FLAG_ITEMS_SORTED = 0x00000001;
diff --git a/src/com/android/launcher3/FolderPagedView.java b/src/com/android/launcher3/FolderPagedView.java
index 617489271..c68ef72b3 100644
--- a/src/com/android/launcher3/FolderPagedView.java
+++ b/src/com/android/launcher3/FolderPagedView.java
@@ -20,23 +20,16 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
-import android.view.animation.Interpolator;
-import android.view.animation.OvershootInterpolator;
-import android.widget.Switch;
import com.android.launcher3.FocusHelper.PagedFolderKeyEventListener;
import com.android.launcher3.PageIndicator.PageMarkerResources;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.util.Thunk;
-import java.text.Collator;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
@@ -47,17 +40,10 @@ public class FolderPagedView extends PagedView {
private static final boolean ALLOW_FOLDER_SCROLL = true;
- // To enable this flag, user_folder.xml needs to be modified to add sort button.
- private static final boolean ALLOW_ITEM_SORTING = false;
-
private static final int REORDER_ANIMATION_DURATION = 230;
private static final int START_VIEW_REORDER_DELAY = 30;
private static final float VIEW_REORDER_DELAY_FACTOR = 0.9f;
- private static final int SPAN_TO_PAGE_DURATION = 350;
- private static final int SORT_ANIM_HIDE_DURATION = 130;
- private static final int SORT_ANIM_SHOW_DURATION = 160;
-
/**
* Fraction of the width to scroll when showing the next page hint.
*/
@@ -87,13 +73,8 @@ public class FolderPagedView extends PagedView {
private FocusIndicatorView mFocusIndicatorView;
private PagedFolderKeyEventListener mKeyListener;
- private View mSortButton;
- private Switch mSortSwitch;
private View mPageIndicator;
- private boolean mSortOperationPending;
- boolean mIsSorted;
-
public FolderPagedView(Context context, AttributeSet attrs) {
super(context, attrs);
LauncherAppState app = LauncherAppState.getInstance();
@@ -121,132 +102,6 @@ public class FolderPagedView extends PagedView {
mFocusIndicatorView = (FocusIndicatorView) folder.findViewById(R.id.focus_indicator);
mKeyListener = new PagedFolderKeyEventListener(folder);
mPageIndicator = folder.findViewById(R.id.folder_page_indicator);
-
- if (ALLOW_ITEM_SORTING) {
- // Initialize {@link #mSortSwitch} and {@link #mSortButton}.
- }
- }
-
- /**
- * Called when sort button is clicked.
- */
- private void onSortClicked() {
- if (mSortOperationPending) {
- return;
- }
- if (mIsSorted) {
- setIsSorted(false, true);
- } else {
- mSortOperationPending = true;
- doSort();
- }
- }
-
- private void setIsSorted(boolean isSorted, boolean saveChanges) {
- mIsSorted = isSorted;
- if (ALLOW_ITEM_SORTING) {
- mSortSwitch.setChecked(isSorted);
- mFolder.mInfo.setOption(FolderInfo.FLAG_ITEMS_SORTED, isSorted,
- saveChanges ? mFolder.mLauncher : null);
- }
- }
-
- /**
- * Sorts the contents of the folder and animates the icons on the first page to reflect
- * the changes.
- * Steps:
- * 1. Scroll to first page
- * 2. Sort all icons in one go
- * 3. Re-apply the old IconInfos on the first page (so that there is no instant change)
- * 4. Animate each view individually to reflect the new icon.
- */
- private void doSort() {
- if (!mSortOperationPending) {
- return;
- }
- if (getNextPage() != 0) {
- snapToPage(0, SPAN_TO_PAGE_DURATION, new DecelerateInterpolator());
- return;
- }
-
- mSortOperationPending = false;
- ShortcutInfo[][] oldItems = new ShortcutInfo[mGridCountX][mGridCountY];
- CellLayout currentPage = getCurrentCellLayout();
- for (int x = 0; x < mGridCountX; x++) {
- for (int y = 0; y < mGridCountY; y++) {
- View v = currentPage.getChildAt(x, y);
- if (v != null) {
- oldItems[x][y] = (ShortcutInfo) v.getTag();
- }
- }
- }
-
- ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
- Collections.sort(views, new ViewComparator());
- arrangeChildren(views, views.size());
-
- int delay = 0;
- float delayAmount = START_VIEW_REORDER_DELAY;
- final Interpolator hideInterpolator = new DecelerateInterpolator(2);
- final Interpolator showInterpolator = new OvershootInterpolator(0.8f);
-
- currentPage = getCurrentCellLayout();
- for (int x = 0; x < mGridCountX; x++) {
- for (int y = 0; y < mGridCountY; y++) {
- final BubbleTextView v = (BubbleTextView) currentPage.getChildAt(x, y);
- if (v != null) {
- final ShortcutInfo info = (ShortcutInfo) v.getTag();
- final Runnable clearPending = new Runnable() {
-
- @Override
- public void run() {
- mPendingAnimations.remove(v);
- v.setScaleX(1);
- v.setScaleY(1);
- }
- };
- if (oldItems[x][y] == null) {
- v.setScaleX(0);
- v.setScaleY(0);
- v.animate().setDuration(SORT_ANIM_SHOW_DURATION)
- .setStartDelay(SORT_ANIM_HIDE_DURATION + delay)
- .scaleX(1).scaleY(1).setInterpolator(showInterpolator)
- .withEndAction(clearPending);
- mPendingAnimations.put(v, clearPending);
- } else {
- // Apply the old iconInfo so that there is no sudden change.
- v.applyFromShortcutInfo(oldItems[x][y], mIconCache, false);
- v.animate().setStartDelay(delay).setDuration(SORT_ANIM_HIDE_DURATION)
- .scaleX(0).scaleY(0)
- .setInterpolator(hideInterpolator)
- .withEndAction(new Runnable() {
-
- @Override
- public void run() {
- // Apply the new iconInfo as part of the animation.
- v.applyFromShortcutInfo(info, mIconCache, false);
- v.animate().scaleX(1).scaleY(1)
- .setDuration(SORT_ANIM_SHOW_DURATION).setStartDelay(0)
- .setInterpolator(showInterpolator)
- .withEndAction(clearPending);
- }
- });
- mPendingAnimations.put(v, new Runnable() {
-
- @Override
- public void run() {
- clearPending.run();
- v.applyFromShortcutInfo(info, mIconCache, false);
- }
- });
- }
- delay += delayAmount;
- delayAmount *= VIEW_REORDER_DELAY_FACTOR;
- }
- }
- }
-
- setIsSorted(true, true);
}
/**
@@ -295,7 +150,6 @@ public class FolderPagedView extends PagedView {
* @return list of items that could not be bound, probably because we hit the max size limit.
*/
public ArrayList<ShortcutInfo> bindItems(ArrayList<ShortcutInfo> items) {
- mIsSorted = ALLOW_ITEM_SORTING && mFolder.mInfo.hasOption(FolderInfo.FLAG_ITEMS_SORTED);
ArrayList<View> icons = new ArrayList<View>();
ArrayList<ShortcutInfo> extra = new ArrayList<ShortcutInfo>();
@@ -317,20 +171,6 @@ public class FolderPagedView extends PagedView {
public int allocateRankForNewItem(ShortcutInfo info) {
int rank = getItemCount();
ArrayList<View> views = new ArrayList<View>(mFolder.getItemsInReadingOrder());
- if (ALLOW_ITEM_SORTING && mIsSorted) {
- View tmp = new View(getContext());
- tmp.setTag(info);
- int index = Collections.binarySearch(views, tmp, new ViewComparator());
- if (index < 0) {
- rank = -index - 1;
- } else {
- // Item with same name already exists.
- // We will just insert it before that item.
- rank = index;
- }
-
- }
-
views.add(rank, null);
arrangeChildren(views, views.size(), false);
setCurrentPage(rank / mMaxItemsPerPage);
@@ -363,7 +203,7 @@ public class FolderPagedView extends PagedView {
}
@SuppressLint("InflateParams")
- private View createNewView(ShortcutInfo item) {
+ public View createNewView(ShortcutInfo item) {
final BubbleTextView textView = (BubbleTextView) mInflater.inflate(
R.layout.folder_application, null, false);
textView.applyFromShortcutInfo(item, mIconCache, false);
@@ -447,10 +287,6 @@ public class FolderPagedView extends PagedView {
int position = 0;
int newX, newY, rank;
- boolean isSorted = mIsSorted;
-
- ViewComparator comparator = new ViewComparator();
- View lastView = null;
rank = 0;
for (int i = 0; i < itemCount; i++) {
View v = list.size() > i ? list.get(i) : null;
@@ -465,10 +301,6 @@ public class FolderPagedView extends PagedView {
}
if (v != null) {
- if (lastView != null) {
- isSorted &= comparator.compare(lastView, v) <= 0;
- }
-
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) v.getLayoutParams();
newX = position % mGridCountX;
newY = position / mGridCountX;
@@ -488,7 +320,6 @@ public class FolderPagedView extends PagedView {
v, -1, mFolder.mLauncher.getViewIdForItem(info), lp, true);
}
- lastView = v;
rank ++;
position++;
}
@@ -506,23 +337,10 @@ public class FolderPagedView extends PagedView {
setEnableOverscroll(getPageCount() > 1);
// Update footer
- if (ALLOW_ITEM_SORTING) {
- setIsSorted(isSorted, saveChanges);
- if (getPageCount() > 1) {
- mPageIndicator.setVisibility(View.VISIBLE);
- mSortButton.setVisibility(View.VISIBLE);
- mFolder.mFolderName.setGravity(rtlLayout ? Gravity.RIGHT : Gravity.LEFT);
- } else {
- mPageIndicator.setVisibility(View.GONE);
- mSortButton.setVisibility(View.GONE);
- mFolder.mFolderName.setGravity(Gravity.CENTER_HORIZONTAL);
- }
- } else {
- int indicatorVisibility = mPageIndicator.getVisibility();
- mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
- if (indicatorVisibility != mPageIndicator.getVisibility()) {
- mFolder.updateFooterHeight();
- }
+ int indicatorVisibility = mPageIndicator.getVisibility();
+ mPageIndicator.setVisibility(getPageCount() > 1 ? View.VISIBLE : View.GONE);
+ if (indicatorVisibility != mPageIndicator.getVisibility()) {
+ mFolder.updateFooterHeight();
}
}
@@ -559,7 +377,7 @@ public class FolderPagedView extends PagedView {
public int findNearestArea(int pixelX, int pixelY) {
int pageIndex = getNextPage();
CellLayout page = getPageAt(pageIndex);
- page.findNearestArea(pixelX, pixelY, 1, 1, null, false, sTempPosArray);
+ page.findNearestArea(pixelX, pixelY, 1, 1, sTempPosArray);
if (mFolder.isLayoutRtl()) {
sTempPosArray[0] = page.getCountX() - sTempPosArray[0] - 1;
}
@@ -630,17 +448,6 @@ public class FolderPagedView extends PagedView {
if (mFolder != null) {
mFolder.updateTextViewFocus();
}
- if (ALLOW_ITEM_SORTING && mSortOperationPending && getNextPage() == 0) {
- post(new Runnable() {
-
- @Override
- public void run() {
- if (mSortOperationPending) {
- doSort();
- }
- }
- });
- }
}
/**
@@ -829,14 +636,4 @@ public class FolderPagedView extends PagedView {
}
}
}
-
- private static class ViewComparator implements Comparator<View> {
- private final Collator mCollator = Collator.getInstance();
-
- @Override
- public int compare(View lhs, View rhs) {
- return mCollator.compare( ((ShortcutInfo) lhs.getTag()).title.toString(),
- ((ShortcutInfo) rhs.getTag()).title.toString());
- }
- }
}
diff --git a/src/com/android/launcher3/InfoDropTarget.java b/src/com/android/launcher3/InfoDropTarget.java
index e48640c93..f1ff48da3 100644
--- a/src/com/android/launcher3/InfoDropTarget.java
+++ b/src/com/android/launcher3/InfoDropTarget.java
@@ -21,7 +21,6 @@ import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
-import com.android.launcher3.R;
import com.android.launcher3.compat.UserHandleCompat;
public class InfoDropTarget extends ButtonDropTarget {
@@ -66,9 +65,13 @@ public class InfoDropTarget extends ButtonDropTarget {
@Override
protected boolean supportsDrop(DragSource source, Object info) {
- return source.supportsAppInfoDropTarget() &&
- Settings.Global.getInt(getContext().getContentResolver(),
- Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1;
+ return source.supportsAppInfoDropTarget() && supportsDrop(getContext(), info);
+ }
+
+ public static boolean supportsDrop(Context context, Object info) {
+ return (Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 1) &&
+ (info instanceof AppInfo || info instanceof PendingAddItemInfo);
}
@Override
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 20844777f..8c920f0b8 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -100,8 +100,10 @@ import com.android.launcher3.compat.LauncherActivityInfoCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.launcher3.widget.WidgetHostViewLoader;
import com.android.launcher3.widget.WidgetsContainerView;
import java.io.DataInputStream;
@@ -302,7 +304,7 @@ public class Launcher extends Activity
@Thunk static LocaleConfiguration sLocaleConfiguration = null;
- private static HashMap<Long, FolderInfo> sFolders = new HashMap<Long, FolderInfo>();
+ private static LongArrayMap<FolderInfo> sFolders = new LongArrayMap<>();
private View.OnTouchListener mHapticFeedbackTouchListener;
@@ -2047,12 +2049,6 @@ public class Launcher extends Activity
TextKeyListener.getInstance().release();
- // Disconnect any of the callbacks and drawables associated with ItemInfos on the workspace
- // to prevent leaking Launcher activities on orientation change.
- if (mModel != null) {
- mModel.unbindItemInfosAndClearQueuedBindRunnables();
- }
-
getContentResolver().unregisterContentObserver(mWidgetObserver);
unregisterReceiver(mCloseSystemDialogsReceiver);
@@ -3892,7 +3888,7 @@ public class Launcher extends Activity
/**
* Implementation of the method from LauncherModel.Callbacks.
*/
- public void bindFolders(final HashMap<Long, FolderInfo> folders) {
+ public void bindFolders(final LongArrayMap<FolderInfo> folders) {
Runnable r = new Runnable() {
public void run() {
bindFolders(folders);
@@ -3901,8 +3897,7 @@ public class Launcher extends Activity
if (waitUntilResume(r)) {
return;
}
- sFolders.clear();
- sFolders.putAll(folders);
+ sFolders = folders.clone();
}
/**
@@ -3950,7 +3945,7 @@ public class Launcher extends Activity
pendingInfo.minSpanX = item.minSpanX;
pendingInfo.minSpanY = item.minSpanY;
Bundle options = null;
- // AppsCustomizePagedView.getDefaultOptionsForWidget(this, pendingInfo);
+ WidgetHostViewLoader.getDefaultOptionsForWidget(this, pendingInfo);
int newWidgetId = mAppWidgetHost.allocateAppWidgetId();
boolean success = mAppWidgetManager.bindAppWidgetIdIfAllowed(
diff --git a/src/com/android/launcher3/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
index 8ba02ea5f..a60e16024 100644
--- a/src/com/android/launcher3/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/LauncherAccessibilityDelegate.java
@@ -1,16 +1,13 @@
package com.android.launcher3;
import android.annotation.TargetApi;
-import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
-import android.support.v4.view.accessibility.AccessibilityEventCompat;
-import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
+import android.text.TextUtils;
import android.util.SparseArray;
import android.view.View;
import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -68,18 +65,21 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
if (!(host.getTag() instanceof ItemInfo)) return;
ItemInfo item = (ItemInfo) host.getTag();
+ if (DeleteDropTarget.supportsDrop(item)) {
+ info.addAction(mActions.get(REMOVE));
+ }
+ if (UninstallDropTarget.supportsDrop(host.getContext(), item)) {
+ info.addAction(mActions.get(UNINSTALL));
+ }
+ if (InfoDropTarget.supportsDrop(host.getContext(), item)) {
+ info.addAction(mActions.get(INFO));
+ }
+
if ((item instanceof ShortcutInfo)
|| (item instanceof LauncherAppWidgetInfo)
|| (item instanceof FolderInfo)) {
- // Workspace shortcut / widget
- info.addAction(mActions.get(REMOVE));
info.addAction(mActions.get(MOVE));
- } else if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
- // App or Widget from customization tray
- if (item instanceof AppInfo) {
- info.addAction(mActions.get(UNINSTALL));
- }
- info.addAction(mActions.get(INFO));
+ } if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
info.addAction(mActions.get(ADD_TO_WORKSPACE));
}
}
@@ -94,10 +94,9 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
}
public boolean performAction(View host, ItemInfo item, int action) {
- Resources res = mLauncher.getResources();
if (action == REMOVE) {
if (DeleteDropTarget.removeWorkspaceOrFolderItem(mLauncher, item, host)) {
- announceConfirmation(R.string.item_removed_from_workspace);
+ announceConfirmation(R.string.item_removed);
return true;
}
return false;
@@ -105,9 +104,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
InfoDropTarget.startDetailsActivityForInfo(item, mLauncher);
return true;
} else if (action == UNINSTALL) {
- AppInfo info = (AppInfo) item;
- mLauncher.startApplicationUninstallActivity(info.componentName, info.flags, info.user);
- return true;
+ return UninstallDropTarget.startUninstallActivity(mLauncher, item);
} else if (action == MOVE) {
beginAccessibleDrag(host, item);
} else if (action == ADD_TO_WORKSPACE) {
@@ -158,19 +155,31 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate {
return mDragInfo;
}
- public void handleAccessibleDrop(CellLayout targetContainer, Rect dropLocation,
+ /**
+ * @param clickedTarget the actual view that was clicked
+ * @param dropLocation relative to {@param clickedTarget}. If provided, its center is used
+ * as the actual drop location otherwise the views center is used.
+ */
+ public void handleAccessibleDrop(View clickedTarget, Rect dropLocation,
String confirmation) {
if (!isInAccessibleDrag()) return;
int[] loc = new int[2];
- loc[0] = dropLocation.centerX();
- loc[1] = dropLocation.centerY();
+ if (dropLocation == null) {
+ loc[0] = clickedTarget.getWidth() / 2;
+ loc[1] = clickedTarget.getHeight() / 2;
+ } else {
+ loc[0] = dropLocation.centerX();
+ loc[1] = dropLocation.centerY();
+ }
- mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(targetContainer, loc);
+ mLauncher.getDragLayer().getDescendantCoordRelativeToSelf(clickedTarget, loc);
mLauncher.getDragController().completeAccessibleDrag(loc);
endAccessibleDrag();
- announceConfirmation(confirmation);
+ if (!TextUtils.isEmpty(confirmation)) {
+ announceConfirmation(confirmation);
+ }
}
public void beginAccessibleDrag(View item, ItemInfo info) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 5a65cab82..00afd98d0 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -28,7 +28,6 @@ import android.content.Context;
import android.content.Intent;
import android.content.Intent.ShortcutIconResource;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
@@ -61,6 +60,7 @@ import com.android.launcher3.compat.PackageInstallerCompat.PackageInstallInfo;
import com.android.launcher3.compat.UserHandleCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.ManagedProfileHeuristic;
import com.android.launcher3.util.Thunk;
@@ -109,11 +109,6 @@ public class LauncherModel extends BroadcastReceiver
@Thunk LoaderTask mLoaderTask;
@Thunk boolean mIsLoaderTaskRunning;
- // Specific runnable types that are run on the main thread deferred handler, this allows us to
- // clear all queued binding runnables when the Launcher activity is destroyed.
- private static final int MAIN_THREAD_NORMAL_RUNNABLE = 0;
- private static final int MAIN_THREAD_BINDING_RUNNABLE = 1;
-
private static final String MIGRATE_AUTHORITY = "com.android.launcher2.settings";
@Thunk static final HandlerThread sWorkerThread = new HandlerThread("launcher-loader");
@@ -147,7 +142,7 @@ public class LauncherModel extends BroadcastReceiver
// sBgItemsIdMap maps *all* the ItemInfos (shortcuts, folders, and widgets) created by
// LauncherModel to their ids
- static final HashMap<Long, ItemInfo> sBgItemsIdMap = new HashMap<Long, ItemInfo>();
+ static final LongArrayMap<ItemInfo> sBgItemsIdMap = new LongArrayMap<>();
// sBgWorkspaceItems is passed to bindItems, which expects a list of all folders and shortcuts
// created by LauncherModel that are directly on the home screen (however, no widgets or
@@ -159,7 +154,7 @@ public class LauncherModel extends BroadcastReceiver
new ArrayList<LauncherAppWidgetInfo>();
// sBgFolders is all FolderInfos created by LauncherModel. Passed to bindFolders()
- static final HashMap<Long, FolderInfo> sBgFolders = new HashMap<Long, FolderInfo>();
+ static final LongArrayMap<FolderInfo> sBgFolders = new LongArrayMap<>();
// sBgWorkspaceScreens is the ordered set of workspace screens.
static final ArrayList<Long> sBgWorkspaceScreens = new ArrayList<Long>();
@@ -188,7 +183,7 @@ public class LauncherModel extends BroadcastReceiver
boolean forceAnimateIcons);
public void bindScreens(ArrayList<Long> orderedScreenIds);
public void bindAddScreens(ArrayList<Long> orderedScreenIds);
- public void bindFolders(HashMap<Long,FolderInfo> folders);
+ public void bindFolders(LongArrayMap<FolderInfo> folders);
public void finishBindingItems();
public void bindAppWidget(LauncherAppWidgetInfo info);
public void bindAllApplications(ArrayList<AppInfo> apps);
@@ -256,9 +251,6 @@ public class LauncherModel extends BroadcastReceiver
/** Runs the specified runnable immediately if called from the main thread, otherwise it is
* posted on the main thread handler. */
@Thunk void runOnMainThread(Runnable r) {
- runOnMainThread(r, 0);
- }
- @Thunk void runOnMainThread(Runnable r, int type) {
if (sWorkerThread.getThreadId() == Process.myTid()) {
// If we are on the worker thread, post onto the main handler
mHandler.post(r);
@@ -295,7 +287,7 @@ public class LauncherModel extends BroadcastReceiver
return;
}
- for (ItemInfo info : sBgItemsIdMap.values()) {
+ for (ItemInfo info : sBgItemsIdMap) {
if (info instanceof ShortcutInfo) {
ShortcutInfo si = (ShortcutInfo) info;
ComponentName cn = si.getTargetComponent();
@@ -349,7 +341,7 @@ public class LauncherModel extends BroadcastReceiver
final ArrayList<ShortcutInfo> updates = new ArrayList<>();
final UserHandleCompat user = UserHandleCompat.myUserHandle();
- for (ItemInfo info : sBgItemsIdMap.values()) {
+ for (ItemInfo info : sBgItemsIdMap) {
if (info instanceof ShortcutInfo) {
ShortcutInfo si = (ShortcutInfo) info;
ComponentName cn = si.getTargetComponent();
@@ -442,7 +434,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
}
- return CellLayout.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
+ return Utilities.findVacantCell(xy, spanX, spanY, xCount, yCount, occupied);
}
/**
@@ -679,7 +671,7 @@ public class LauncherModel extends BroadcastReceiver
runOnWorkerThread(r);
}
- public void unbindItemInfosAndClearQueuedBindRunnables() {
+ private void unbindItemInfosAndClearQueuedBindRunnables() {
if (sWorkerThread.getThreadId() == Process.myTid()) {
throw new RuntimeException("Expected unbindLauncherItemInfos() to be called from the " +
"main thread");
@@ -689,8 +681,9 @@ public class LauncherModel extends BroadcastReceiver
synchronized (mDeferredBindRunnables) {
mDeferredBindRunnables.clear();
}
- // Remove any queued bind runnables
- mHandler.cancelAllRunnablesOfType(MAIN_THREAD_BINDING_RUNNABLE);
+
+ // Remove any queued UI runnables
+ mHandler.cancelAll();
// Unbind all the workspace items
unbindWorkspaceItemsOnMainThread();
}
@@ -699,19 +692,15 @@ public class LauncherModel extends BroadcastReceiver
void unbindWorkspaceItemsOnMainThread() {
// Ensure that we don't use the same workspace items data structure on the main thread
// by making a copy of workspace items first.
- final ArrayList<ItemInfo> tmpWorkspaceItems = new ArrayList<ItemInfo>();
- final ArrayList<ItemInfo> tmpAppWidgets = new ArrayList<ItemInfo>();
+ final ArrayList<ItemInfo> tmpItems = new ArrayList<ItemInfo>();
synchronized (sBgLock) {
- tmpWorkspaceItems.addAll(sBgWorkspaceItems);
- tmpAppWidgets.addAll(sBgAppWidgets);
+ tmpItems.addAll(sBgWorkspaceItems);
+ tmpItems.addAll(sBgAppWidgets);
}
Runnable r = new Runnable() {
@Override
public void run() {
- for (ItemInfo item : tmpWorkspaceItems) {
- item.unbind();
- }
- for (ItemInfo item : tmpAppWidgets) {
+ for (ItemInfo item : tmpItems) {
item.unbind();
}
}
@@ -1008,7 +997,7 @@ public class LauncherModel extends BroadcastReceiver
}
synchronized (sBgLock) {
- for (ItemInfo item : sBgItemsIdMap.values()) {
+ for (ItemInfo item : sBgItemsIdMap) {
if (item instanceof ShortcutInfo) {
ShortcutInfo info = (ShortcutInfo) item;
if (intentWithPkg.equals(info.getIntent())
@@ -1024,7 +1013,7 @@ public class LauncherModel extends BroadcastReceiver
/**
* Find a folder in the db, creating the FolderInfo if necessary, and adding it to folderList.
*/
- FolderInfo getFolderById(Context context, HashMap<Long,FolderInfo> folderList, long id) {
+ FolderInfo getFolderById(Context context, LongArrayMap<FolderInfo> folderList, long id) {
final ContentResolver cr = context.getContentResolver();
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI, null,
"_id=? and (itemType=? or itemType=?)",
@@ -1144,7 +1133,7 @@ public class LauncherModel extends BroadcastReceiver
return cn.getPackageName().equals(pn) && info.user.equals(user);
}
};
- return filterItemInfos(sBgItemsIdMap.values(), filter);
+ return filterItemInfos(sBgItemsIdMap, filter);
}
/**
@@ -1184,7 +1173,7 @@ public class LauncherModel extends BroadcastReceiver
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
sBgFolders.remove(item.id);
- for (ItemInfo info: sBgItemsIdMap.values()) {
+ for (ItemInfo info: sBgItemsIdMap) {
if (info.container == item.id) {
// We are deleting a folder which still contains items that
// think they are contained by that folder.
@@ -1297,6 +1286,9 @@ public class LauncherModel extends BroadcastReceiver
*/
public void initialize(Callbacks callbacks) {
synchronized (mLock) {
+ // Disconnect any of the callbacks and drawables associated with ItemInfos on the
+ // workspace to prevent leaking Launcher activities on orientation change.
+ unbindItemInfosAndClearQueuedBindRunnables();
mCallbacks = new WeakReference<Callbacks>(callbacks);
}
}
@@ -1486,7 +1478,7 @@ public class LauncherModel extends BroadcastReceiver
mDeferredBindRunnables.clear();
}
for (final Runnable r : deferredBindRunnables) {
- mHandler.post(r, MAIN_THREAD_BINDING_RUNNABLE);
+ mHandler.post(r);
}
}
}
@@ -1758,7 +1750,7 @@ public class LauncherModel extends BroadcastReceiver
}
// check & update map of what's occupied; used to discard overlapping/invalid items
- private boolean checkItemPlacement(HashMap<Long, ItemInfo[][]> occupied, ItemInfo item) {
+ private boolean checkItemPlacement(LongArrayMap<ItemInfo[][]> occupied, ItemInfo item) {
LauncherAppState app = LauncherAppState.getInstance();
DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
final int countX = (int) grid.numColumns;
@@ -1906,7 +1898,7 @@ public class LauncherModel extends BroadcastReceiver
// +1 for the hotseat (it can be larger than the workspace)
// Load workspace in reverse order to ensure that latest items are loaded first (and
// before any earlier duplicates)
- final HashMap<Long, ItemInfo[][]> occupied = new HashMap<Long, ItemInfo[][]>();
+ final LongArrayMap<ItemInfo[][]> occupied = new LongArrayMap<>();
try {
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
@@ -2445,7 +2437,7 @@ public class LauncherModel extends BroadcastReceiver
// Remove any empty screens
ArrayList<Long> unusedScreens = new ArrayList<Long>(sBgWorkspaceScreens);
- for (ItemInfo item: sBgItemsIdMap.values()) {
+ for (ItemInfo item: sBgItemsIdMap) {
long screenId = item.screenId;
if (item.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
unusedScreens.contains(screenId)) {
@@ -2470,14 +2462,13 @@ public class LauncherModel extends BroadcastReceiver
for (int y = 0; y < countY; y++) {
String line = "";
- Iterator<Long> iter = occupied.keySet().iterator();
- while (iter.hasNext()) {
- long screenId = iter.next();
+ for (int i = 0; i < nScreens; i++) {
+ long screenId = occupied.keyAt(i);
if (screenId > 0) {
line += " | ";
}
+ ItemInfo[][] screen = occupied.valueAt(i);
for (int x = 0; x < countX; x++) {
- ItemInfo[][] screen = occupied.get(screenId);
if (x < screen.length && y < screen[x].length) {
line += (screen[x][y] != null) ? "#" : ".";
} else {
@@ -2568,14 +2559,17 @@ public class LauncherModel extends BroadcastReceiver
/** Filters the set of folders which are on the specified screen. */
private void filterCurrentFolders(long currentScreenId,
- HashMap<Long, ItemInfo> itemsIdMap,
- HashMap<Long, FolderInfo> folders,
- HashMap<Long, FolderInfo> currentScreenFolders,
- HashMap<Long, FolderInfo> otherScreenFolders) {
+ LongArrayMap<ItemInfo> itemsIdMap,
+ LongArrayMap<FolderInfo> folders,
+ LongArrayMap<FolderInfo> currentScreenFolders,
+ LongArrayMap<FolderInfo> otherScreenFolders) {
+
+ int total = folders.size();
+ for (int i = 0; i < total; i++) {
+ long id = folders.keyAt(i);
+ FolderInfo folder = folders.valueAt(i);
- for (long id : folders.keySet()) {
ItemInfo info = itemsIdMap.get(id);
- FolderInfo folder = folders.get(id);
if (info == null || folder == null) continue;
if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
info.screenId == currentScreenId) {
@@ -2619,13 +2613,13 @@ public class LauncherModel extends BroadcastReceiver
}
}
};
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
private void bindWorkspaceItems(final Callbacks oldCallbacks,
final ArrayList<ItemInfo> workspaceItems,
final ArrayList<LauncherAppWidgetInfo> appWidgets,
- final HashMap<Long, FolderInfo> folders,
+ final LongArrayMap<FolderInfo> folders,
ArrayList<Runnable> deferredBindRunnables) {
final boolean postOnMainThread = (deferredBindRunnables != null);
@@ -2650,7 +2644,7 @@ public class LauncherModel extends BroadcastReceiver
deferredBindRunnables.add(r);
}
} else {
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
}
@@ -2669,7 +2663,7 @@ public class LauncherModel extends BroadcastReceiver
deferredBindRunnables.add(r);
}
} else {
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
}
@@ -2688,7 +2682,7 @@ public class LauncherModel extends BroadcastReceiver
if (postOnMainThread) {
deferredBindRunnables.add(r);
} else {
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
}
}
@@ -2713,15 +2707,18 @@ public class LauncherModel extends BroadcastReceiver
ArrayList<ItemInfo> workspaceItems = new ArrayList<ItemInfo>();
ArrayList<LauncherAppWidgetInfo> appWidgets =
new ArrayList<LauncherAppWidgetInfo>();
- HashMap<Long, FolderInfo> folders = new HashMap<Long, FolderInfo>();
- HashMap<Long, ItemInfo> itemsIdMap = new HashMap<Long, ItemInfo>();
ArrayList<Long> orderedScreenIds = new ArrayList<Long>();
+
+ final LongArrayMap<FolderInfo> folders;
+ final LongArrayMap<ItemInfo> itemsIdMap;
+
synchronized (sBgLock) {
workspaceItems.addAll(sBgWorkspaceItems);
appWidgets.addAll(sBgAppWidgets);
- folders.putAll(sBgFolders);
- itemsIdMap.putAll(sBgItemsIdMap);
orderedScreenIds.addAll(sBgWorkspaceScreens);
+
+ folders = sBgFolders.clone();
+ itemsIdMap = sBgItemsIdMap.clone();
}
final boolean isLoadingSynchronously =
@@ -2747,8 +2744,8 @@ public class LauncherModel extends BroadcastReceiver
new ArrayList<LauncherAppWidgetInfo>();
ArrayList<LauncherAppWidgetInfo> otherAppWidgets =
new ArrayList<LauncherAppWidgetInfo>();
- HashMap<Long, FolderInfo> currentFolders = new HashMap<Long, FolderInfo>();
- HashMap<Long, FolderInfo> otherFolders = new HashMap<Long, FolderInfo>();
+ LongArrayMap<FolderInfo> currentFolders = new LongArrayMap<>();
+ LongArrayMap<FolderInfo> otherFolders = new LongArrayMap<>();
filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,
otherWorkspaceItems);
@@ -2768,7 +2765,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
};
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
bindWorkspaceScreens(oldCallbacks, orderedScreenIds);
@@ -2784,7 +2781,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
};
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
// Load all the remaining pages (if we are loading synchronously, we want to defer this
@@ -2817,7 +2814,7 @@ public class LauncherModel extends BroadcastReceiver
mDeferredBindRunnables.add(r);
}
} else {
- runOnMainThread(r, MAIN_THREAD_BINDING_RUNNABLE);
+ runOnMainThread(r);
}
}
@@ -2888,8 +2885,6 @@ public class LauncherModel extends BroadcastReceiver
// Clear the list of apps
mBgAllAppsList.clear();
- SharedPreferences prefs = mContext.getSharedPreferences(
- LauncherAppState.getSharedPreferencesKey(), Context.MODE_PRIVATE);
for (UserHandleCompat user : profiles) {
// Query for the set of apps
final long qiaTime = DEBUG_LOADERS ? SystemClock.uptimeMillis() : 0;
@@ -2913,7 +2908,7 @@ public class LauncherModel extends BroadcastReceiver
if (!updatedPackages.isEmpty()) {
final ArrayList<ShortcutInfo> updates = new ArrayList<ShortcutInfo>();
synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap.values()) {
+ for (ItemInfo info : sBgItemsIdMap) {
if (info instanceof ShortcutInfo && user.equals(info.user)
&& info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
ShortcutInfo si = (ShortcutInfo) info;
@@ -3162,7 +3157,7 @@ public class LauncherModel extends BroadcastReceiver
HashSet<String> packageSet = new HashSet<String>(Arrays.asList(packages));
synchronized (sBgLock) {
- for (ItemInfo info : sBgItemsIdMap.values()) {
+ for (ItemInfo info : sBgItemsIdMap) {
if (info instanceof ShortcutInfo && mUser.equals(info.user)) {
ShortcutInfo si = (ShortcutInfo) info;
boolean infoUpdated = false;
@@ -3538,7 +3533,7 @@ public class LauncherModel extends BroadcastReceiver
return info;
}
- static ArrayList<ItemInfo> filterItemInfos(Collection<ItemInfo> infos,
+ static ArrayList<ItemInfo> filterItemInfos(Iterable<ItemInfo> infos,
ItemInfoFilter f) {
HashSet<ItemInfo> filtered = new HashSet<ItemInfo>();
for (ItemInfo i : infos) {
@@ -3579,7 +3574,7 @@ public class LauncherModel extends BroadcastReceiver
}
}
};
- return filterItemInfos(sBgItemsIdMap.values(), filter);
+ return filterItemInfos(sBgItemsIdMap, filter);
}
/**
@@ -3689,7 +3684,7 @@ public class LauncherModel extends BroadcastReceiver
* Return an existing FolderInfo object if we have encountered this ID previously,
* or make a new one.
*/
- @Thunk static FolderInfo findOrMakeFolder(HashMap<Long, FolderInfo> folders, long id) {
+ @Thunk static FolderInfo findOrMakeFolder(LongArrayMap<FolderInfo> folders, long id) {
// See if a placeholder was created for us already
FolderInfo folderInfo = folders.get(id);
if (folderInfo == null) {
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index f91cfa07b..9e005f29a 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -258,7 +258,7 @@ public class LauncherStateTransitionAnimation {
// Setup the reveal view animation
int width = revealView.getMeasuredWidth();
int height = revealView.getMeasuredHeight();
- float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+ float revealRadius = (float) Math.hypot(width / 2, height / 2);
revealView.setVisibility(View.VISIBLE);
revealView.setAlpha(0f);
revealView.setTranslationY(0f);
@@ -563,7 +563,7 @@ public class LauncherStateTransitionAnimation {
if (fromView.getVisibility() == View.VISIBLE) {
int width = revealView.getMeasuredWidth();
int height = revealView.getMeasuredHeight();
- float revealRadius = (float) Math.sqrt((width * width) / 4 + (height * height) / 4);
+ float revealRadius = (float) Math.hypot(width / 2, height / 2);
revealView.setVisibility(View.VISIBLE);
revealView.setAlpha(1f);
revealView.setTranslationY(0);
diff --git a/src/com/android/launcher3/SearchDropTargetBar.java b/src/com/android/launcher3/SearchDropTargetBar.java
index af8bc7580..44a76b73b 100644
--- a/src/com/android/launcher3/SearchDropTargetBar.java
+++ b/src/com/android/launcher3/SearchDropTargetBar.java
@@ -180,6 +180,9 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
prepareStartAnimation(mDropTargetBar);
mShowDropTargetBarAnim.start();
hideSearchBar(true);
+ if (mQSBSearchBar != null) {
+ mQSBSearchBar.setVisibility(View.GONE);
+ }
}
/**
@@ -190,6 +193,9 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
prepareStartAnimation(mDropTargetBar);
mShowDropTargetBarAnim.reverse();
showSearchBar(true);
+ if (mQSBSearchBar != null) {
+ mQSBSearchBar.setVisibility(View.VISIBLE);
+ }
}
/*
@@ -228,4 +234,13 @@ public class SearchDropTargetBar extends FrameLayout implements DragController.D
return null;
}
}
+
+ public void enableAccessibleDrag(boolean enable) {
+ if (mQSBSearchBar != null) {
+ mQSBSearchBar.setVisibility(enable ? View.GONE : View.VISIBLE);
+ }
+ mInfoDropTarget.enableAccessibleDrag(enable);
+ mDeleteDropTarget.enableAccessibleDrag(enable);
+ mUninstallDropTarget.enableAccessibleDrag(enable);
+ }
}
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 15b617683..56c8b39b6 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -76,14 +76,6 @@ public class ShortcutAndWidgetContainer extends ViewGroup {
return null;
}
- public void addView(View child, int index, LayoutParams params, boolean inLayout) {
- if (!inLayout) {
- addView(child, index, params);
- } else {
- addViewInLayout(child, index, params, false);
- }
- }
-
@Override
protected void dispatchDraw(Canvas canvas) {
@SuppressWarnings("all") // suppress dead code warning
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 4a7fffeb2..4c52d7e0f 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -33,9 +33,12 @@ public class UninstallDropTarget extends ButtonDropTarget {
@Override
protected boolean supportsDrop(DragSource source, Object info) {
+ return supportsDrop(getContext(), info);
+ }
+
+ public static boolean supportsDrop(Context context, Object info) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- UserManager userManager = (UserManager)
- getContext().getSystemService(Context.USER_SERVICE);
+ UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
Bundle restrictions = userManager.getUserRestrictions();
if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
|| restrictions.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS, false)) {
@@ -78,8 +81,7 @@ public class UninstallDropTarget extends ButtonDropTarget {
void completeDrop(final DragObject d) {
final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(d.dragInfo);
final UserHandleCompat user = ((ItemInfo) d.dragInfo).user;
- if (mLauncher.startApplicationUninstallActivity(
- componentInfo.first, componentInfo.second, user)) {
+ if (startUninstallActivity(mLauncher, d.dragInfo)) {
final Runnable checkIfUninstallWasSuccess = new Runnable() {
@Override
@@ -96,6 +98,13 @@ public class UninstallDropTarget extends ButtonDropTarget {
}
}
+ public static boolean startUninstallActivity(Launcher launcher, Object info) {
+ final Pair<ComponentName, Integer> componentInfo = getAppInfoFlags(info);
+ final UserHandleCompat user = ((ItemInfo) info).user;
+ return launcher.startApplicationUninstallActivity(
+ componentInfo.first, componentInfo.second, user);
+ }
+
@Thunk void sendUninstallResult(DragSource target, boolean result) {
if (target instanceof UninstallSource) {
((UninstallSource) target).onUninstallActivityReturned(result);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 22677c8ea..2dbf078a4 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -583,4 +583,37 @@ public final class Utilities {
return lhs.rank - rhs.rank;
}
};
+
+ /**
+ * Find the first vacant cell, if there is one.
+ *
+ * @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 static boolean findVacantCell(int[] vacant, int spanX, int spanY,
+ int xCount, int yCount, boolean[][] occupied) {
+
+ for (int y = 0; (y + spanY) <= yCount; y++) {
+ for (int x = 0; (x + spanX) <= xCount; x++) {
+ boolean available = !occupied[x][y];
+ out: for (int i = x; i < x + spanX; i++) {
+ for (int j = y; j < y + spanY; j++) {
+ available = available && !occupied[i][j];
+ if (!available) break out;
+ }
+ }
+
+ if (available) {
+ vacant[0] = x;
+ vacant[1] = y;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index abb8489fd..2efd20739 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -63,6 +63,7 @@ import com.android.launcher3.Launcher.LauncherOverlay;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.UninstallDropTarget.UninstallSource;
import com.android.launcher3.compat.UserHandleCompat;
+import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.WallpaperUtils;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -71,7 +72,6 @@ import com.android.launcher3.widget.PendingAddWidgetInfo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -120,7 +120,7 @@ public class Workspace extends SmoothPagedView
final static long EXTRA_EMPTY_SCREEN_ID = -201;
private final static long CUSTOM_CONTENT_SCREEN_ID = -301;
- @Thunk HashMap<Long, CellLayout> mWorkspaceScreens = new HashMap<Long, CellLayout>();
+ @Thunk LongArrayMap<CellLayout> mWorkspaceScreens = new LongArrayMap<>();
@Thunk ArrayList<Long> mScreenOrder = new ArrayList<Long>();
@Thunk Runnable mRemoveEmptyScreenRunnable;
@@ -834,12 +834,9 @@ public class Workspace extends SmoothPagedView
}
public long getIdForScreen(CellLayout layout) {
- Iterator<Long> iter = mWorkspaceScreens.keySet().iterator();
- while (iter.hasNext()) {
- long id = iter.next();
- if (mWorkspaceScreens.get(id) == layout) {
- return id;
- }
+ int index = mWorkspaceScreens.indexOfValue(layout);
+ if (index != -1) {
+ return mWorkspaceScreens.keyAt(index);
}
return -1;
}
@@ -874,8 +871,10 @@ public class Workspace extends SmoothPagedView
int currentPage = getNextPage();
ArrayList<Long> removeScreens = new ArrayList<Long>();
- for (Long id: mWorkspaceScreens.keySet()) {
- CellLayout cl = mWorkspaceScreens.get(id);
+ int total = mWorkspaceScreens.size();
+ for (int i = 0; i < total; i++) {
+ long id = mWorkspaceScreens.keyAt(i);
+ CellLayout cl = mWorkspaceScreens.valueAt(i);
if (id >= 0 && cl.getShortcutsAndWidgets().getChildCount() == 0) {
removeScreens.add(id);
}
@@ -1615,6 +1614,7 @@ public class Workspace extends SmoothPagedView
// Reset our click listener
setOnClickListener(mLauncher);
}
+ mLauncher.getSearchBar().enableAccessibleDrag(enable);
mLauncher.getHotseat().getLayout().enableAccessibleDrag(enable);
}
diff --git a/src/com/android/launcher3/util/LongArrayMap.java b/src/com/android/launcher3/util/LongArrayMap.java
new file mode 100644
index 000000000..e3c96cd42
--- /dev/null
+++ b/src/com/android/launcher3/util/LongArrayMap.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 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.launcher3.util;
+
+import android.util.LongSparseArray;
+
+import java.util.Iterator;
+
+/**
+ * Extension of {@link LongSparseArray} with some utility methods.
+ */
+public class LongArrayMap<E> extends LongSparseArray<E> implements Iterable<E> {
+
+ public boolean containsKey(long key) {
+ return indexOfKey(key) >= 0;
+ }
+
+ public boolean isEmpty() {
+ return size() <= 0;
+ }
+
+ @Override
+ public LongArrayMap<E> clone() {
+ return (LongArrayMap<E>) super.clone();
+ }
+
+ @Override
+ public Iterator<E> iterator() {
+ return new ValueIterator();
+ }
+
+ private class ValueIterator implements Iterator<E> {
+
+ private int mNextIndex = 0;
+
+ @Override
+ public boolean hasNext() {
+ return mNextIndex < size();
+ }
+
+ @Override
+ public E next() {
+ return valueAt(mNextIndex ++);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 1ae75c3cc..0bc7333ec 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -24,8 +24,6 @@ import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
-import android.util.TypedValue;
-import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
import android.widget.ImageView;
@@ -43,7 +41,7 @@ import com.android.launcher3.WidgetPreviewLoader.PreviewLoadRequest;
import com.android.launcher3.compat.AppWidgetManagerCompat;
/**
- * The linear layout used strictly for the widget tray.
+ * Represents the individual cell of the widget inside the widget tray.
*/
public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
@@ -53,14 +51,12 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
private static final int FADE_IN_DURATION_MS = 70;
private int mPresetPreviewSize;
- private static WidgetCell sShortpressTarget = null;
-
+ private ImageView mWidgetImage;
+ private TextView mWidgetName;
+ private TextView mWidgetDims;
private final Rect mOriginalImagePadding = new Rect();
private String mDimensionsFormatString;
- private CheckForShortPress mPendingCheckForShortPress = null;
- private ShortPressListener mShortPressListener = null;
- private boolean mShortPressTriggered = false;
private boolean mIsAppWidget;
private Object mInfo;
@@ -92,57 +88,27 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
protected void onFinishInflate() {
super.onFinishInflate();
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
- mOriginalImagePadding.left = image.getPaddingLeft();
- mOriginalImagePadding.top = image.getPaddingTop();
- mOriginalImagePadding.right = image.getPaddingRight();
- mOriginalImagePadding.bottom = image.getPaddingBottom();
+ mWidgetImage = (ImageView) findViewById(R.id.widget_preview);
+ mOriginalImagePadding.left = mWidgetImage.getPaddingLeft();
+ mOriginalImagePadding.top = mWidgetImage.getPaddingTop();
+ mOriginalImagePadding.right = mWidgetImage.getPaddingRight();
+ mOriginalImagePadding.bottom = mWidgetImage.getPaddingBottom();
// Ensure we are using the right text size
- LauncherAppState app = LauncherAppState.getInstance();
- DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
- TextView name = (TextView) findViewById(R.id.widget_name);
- if (name != null) {
- name.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
- }
- TextView dims = (TextView) findViewById(R.id.widget_dims);
- if (dims != null) {
- dims.setTextSize(TypedValue.COMPLEX_UNIT_PX, grid.iconTextSizePx);
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- if (DEBUG) {
- Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
- }
- super.onDetachedFromWindow();
- deletePreview(false);
+ DeviceProfile profile = LauncherAppState.getInstance().getDynamicGrid().getDeviceProfile();
+ mWidgetName = ((TextView) findViewById(R.id.widget_name));
+ mWidgetDims = ((TextView) findViewById(R.id.widget_dims));
}
public void reset() {
- ImageView image = (ImageView) findViewById(R.id.widget_preview);
- final TextView name = (TextView) findViewById(R.id.widget_name);
- final TextView dims = (TextView) findViewById(R.id.widget_dims);
- image.setImageDrawable(null);
- name.setText(null);
- dims.setText(null);
- }
-
- public void deletePreview(boolean recycleImage) {
- if (recycleImage) {
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
- if (image != null) {
- image.setImageDrawable(null);
- }
- }
-
- if (mActiveRequest != null) {
- mActiveRequest.cancel(recycleImage);
- mActiveRequest = null;
- }
+ mWidgetImage.setImageDrawable(null);
+ mWidgetName.setText(null);
+ mWidgetDims.setText(null);
}
+ /**
+ * Apply the widget provider info to the view.
+ */
public void applyFromAppWidgetProviderInfo(LauncherAppWidgetProviderInfo info,
int maxWidth, WidgetPreviewLoader loader) {
LauncherAppState app = LauncherAppState.getInstance();
@@ -150,37 +116,41 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
mIsAppWidget = true;
mInfo = info;
- final ImageView image = (ImageView) findViewById(R.id.widget_preview);
if (maxWidth > -1) {
- image.setMaxWidth(maxWidth);
- }
- final TextView name = (TextView) findViewById(R.id.widget_name);
- name.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
- final TextView dims = (TextView) findViewById(R.id.widget_dims);
- if (dims != null) {
- int hSpan = Math.min(info.spanX, (int) grid.numColumns);
- int vSpan = Math.min(info.spanY, (int) grid.numRows);
- dims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
+ mWidgetImage.setMaxWidth(maxWidth);
}
+ // TODO(hyunyoungs): setup a cache for these labels.
+ mWidgetName.setText(AppWidgetManagerCompat.getInstance(getContext()).loadLabel(info));
+ int hSpan = Math.min(info.spanX, (int) grid.numColumns);
+ int vSpan = Math.min(info.spanY, (int) grid.numRows);
+ mWidgetDims.setText(String.format(mDimensionsFormatString, hSpan, vSpan));
mWidgetPreviewLoader = loader;
}
+ /**
+ * Apply the resolve info to the view.
+ */
public void applyFromResolveInfo(
PackageManager pm, ResolveInfo info, WidgetPreviewLoader loader) {
mIsAppWidget = false;
mInfo = info;
CharSequence label = info.loadLabel(pm);
- final TextView name = (TextView) findViewById(R.id.widget_name);
- name.setText(label);
- final TextView dims = (TextView) findViewById(R.id.widget_dims);
- if (dims != null) {
- dims.setText(String.format(mDimensionsFormatString, 1, 1));
- }
+ mWidgetName.setText(label);
+ mWidgetDims.setText(String.format(mDimensionsFormatString, 1, 1));
mWidgetPreviewLoader = loader;
}
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ deletePreview(false);
+
+ if (DEBUG) {
+ Log.d(TAG, String.format("[tag=%s] onDetachedFromWindow", getTagToString()));
+ }
+ }
+
public int[] getPreviewSize() {
- final ImageView i = (ImageView) findViewById(R.id.widget_preview);
int[] maxSize = new int[2];
maxSize[0] = mPresetPreviewSize;
maxSize[1] = mPresetPreviewSize;
@@ -189,110 +159,28 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
public void applyPreview(Bitmap bitmap) {
FastBitmapDrawable preview = new FastBitmapDrawable(bitmap);
- final WidgetImageView image =
- (WidgetImageView) findViewById(R.id.widget_preview);
if (DEBUG) {
Log.d(TAG, String.format("[tag=%s] applyPreview preview: %s",
getTagToString(), preview));
}
if (preview != null) {
- image.mAllowRequestLayout = false;
- image.setImageDrawable(preview);
+ mWidgetImage.setImageDrawable(preview);
if (mIsAppWidget) {
// center horizontally
int[] imageSize = getPreviewSize();
int centerAmount = (imageSize[0] - preview.getIntrinsicWidth()) / 2;
- image.setPadding(mOriginalImagePadding.left + centerAmount,
+ mWidgetImage.setPadding(mOriginalImagePadding.left + centerAmount,
mOriginalImagePadding.top,
mOriginalImagePadding.right,
mOriginalImagePadding.bottom);
}
- image.setAlpha(0f);
- image.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
- image.mAllowRequestLayout = true;
- image.requestLayout();
- }
- }
-
- void setShortPressListener(ShortPressListener listener) {
- mShortPressListener = listener;
- }
-
- interface ShortPressListener {
- void onShortPress(View v);
- void cleanUpShortPress(View v);
- }
-
- class CheckForShortPress implements Runnable {
- public void run() {
- if (sShortpressTarget != null) return;
- if (mShortPressListener != null) {
- mShortPressListener.onShortPress(WidgetCell.this);
- sShortpressTarget = WidgetCell.this;
- }
- mShortPressTriggered = true;
+ mWidgetImage.setAlpha(0f);
+ mWidgetImage.animate().alpha(1.0f).setDuration(FADE_IN_DURATION_MS);
+ // TODO(hyunyoungs): figure out why this has to be called explicitly.
+ mWidgetImage.requestLayout();
}
}
- private void checkForShortPress() {
- if (sShortpressTarget != null) return;
- if (mPendingCheckForShortPress == null) {
- mPendingCheckForShortPress = new CheckForShortPress();
- }
- postDelayed(mPendingCheckForShortPress, 120);
- }
-
- /**
- * Remove the longpress detection timer.
- */
- private void removeShortPressCallback() {
- if (mPendingCheckForShortPress != null) {
- removeCallbacks(mPendingCheckForShortPress);
- }
- }
-
- private void cleanUpShortPress() {
- removeShortPressCallback();
- if (mShortPressTriggered) {
- if (mShortPressListener != null) {
- mShortPressListener.cleanUpShortPress(WidgetCell.this);
- }
- mShortPressTriggered = false;
- }
- }
-
- static void resetShortPressTarget() {
- sShortpressTarget = null;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- super.onTouchEvent(event);
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- cleanUpShortPress();
- break;
- case MotionEvent.ACTION_DOWN:
- checkForShortPress();
- break;
- case MotionEvent.ACTION_CANCEL:
- cleanUpShortPress();
- break;
- case MotionEvent.ACTION_MOVE:
- break;
- }
-
- // We eat up the touch events here, since the PagedView (which uses the same swiping
- // touch code as Workspace previously) uses onInterceptTouchEvent() to determine when
- // the user is scrolling between pages. This means that if the pages themselves don't
- // handle touch events, it gets forwarded up to PagedView itself, and it's own
- // onTouchEvent() handling will prevent further intercept touch events from being called
- // (it's the same view in that case). This is not ideal, but to prevent more changes,
- // we just always mark the touch event as handled.
- return true;
- }
-
public void ensurePreview() {
if (mActiveRequest != null) {
return;
@@ -331,6 +219,16 @@ public class WidgetCell extends LinearLayout implements OnLayoutChangeListener {
return Math.min(size[0], info.spanX * cellWidth);
}
+
+ private void deletePreview(boolean recycleImage) {
+ mWidgetImage.setImageDrawable(null);
+
+ if (mActiveRequest != null) {
+ mActiveRequest.cancel(recycleImage);
+ mActiveRequest = null;
+ }
+ }
+
/**
* Helper method to get the string info of the tag.
*/
diff --git a/src/com/android/launcher3/widget/WidgetHostViewLoader.java b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
new file mode 100644
index 000000000..d65455053
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetHostViewLoader.java
@@ -0,0 +1,197 @@
+package com.android.launcher3.widget;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+
+import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.DragLayer;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+
+public class WidgetHostViewLoader {
+
+ private static final boolean DEBUG = false;
+ private static final String TAG = "WidgetHostViewLoader";
+
+ /* constants used for widget loading state. */
+ private static final int WIDGET_NO_CLEANUP_REQUIRED = -1;
+ private static final int WIDGET_PRELOAD_PENDING = 0;
+ private static final int WIDGET_BOUND = 1;
+ private static final int WIDGET_INFLATED = 2;
+
+ int mState = WIDGET_NO_CLEANUP_REQUIRED;
+
+ /* Runnables to handle inflation and binding. */
+ private Runnable mInflateWidgetRunnable = null;
+ private Runnable mBindWidgetRunnable = null;
+
+ /* Id of the widget being handled. */
+ int mWidgetLoadingId = -1;
+ PendingAddWidgetInfo mCreateWidgetInfo = null;
+
+ // TODO: technically, this class should not have to know the existence of the launcher.
+ private Launcher mLauncher;
+ private Handler mHandler;
+
+ public WidgetHostViewLoader(Launcher launcher) {
+ mLauncher = launcher;
+ mHandler = new Handler();
+ }
+
+ /**
+ * Start loading the widget.
+ */
+ public void load(View v) {
+ if (mCreateWidgetInfo != null) {
+ // Just in case the cleanup process wasn't properly executed.
+ finish(false);
+ }
+ boolean status = false;
+ if (v.getTag() instanceof PendingAddWidgetInfo) {
+ mCreateWidgetInfo = new PendingAddWidgetInfo((PendingAddWidgetInfo) v.getTag());
+ status = preloadWidget(v, mCreateWidgetInfo);
+ }
+ if (DEBUG) {
+ Log.d(TAG, String.format("load started on [state=%d, status=%s]", mState, status));
+ }
+ }
+
+
+ /**
+ * Clean up according to what the last known state was.
+ * @param widgetIdUsed {@code true} if the widgetId was consumed which can happen only
+ * when view is fully inflated
+ */
+ public void finish(boolean widgetIdUsed) {
+ if (DEBUG) {
+ Log.d(TAG, String.format("cancel on state [%d] widgetId=[%d]",
+ mState, mWidgetLoadingId));
+ }
+
+ // If the widget was not added, we may need to do further cleanup.
+ PendingAddWidgetInfo info = mCreateWidgetInfo;
+ mCreateWidgetInfo = null;
+
+ if (mState == WIDGET_PRELOAD_PENDING) {
+ // We never did any preloading, so just remove pending callbacks to do so
+ mHandler.removeCallbacks(mBindWidgetRunnable);
+ mHandler.removeCallbacks(mInflateWidgetRunnable);
+ } else if (mState == WIDGET_BOUND) {
+ // Delete the widget id which was allocated
+ if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
+ mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+ }
+
+ // We never got around to inflating the widget, so remove the callback to do so.
+ mHandler.removeCallbacks(mInflateWidgetRunnable);
+ } else if (mState == WIDGET_INFLATED && !widgetIdUsed) {
+ // Delete the widget id which was allocated
+ if (mWidgetLoadingId != -1 && !info.isCustomWidget()) {
+ mLauncher.getAppWidgetHost().deleteAppWidgetId(mWidgetLoadingId);
+ }
+
+ // The widget was inflated and added to the DragLayer -- remove it.
+ AppWidgetHostView widget = info.boundWidget;
+ mLauncher.getDragLayer().removeView(widget);
+ }
+ setState(WIDGET_NO_CLEANUP_REQUIRED);
+ mWidgetLoadingId = -1;
+ }
+
+ private boolean preloadWidget(final View v, final PendingAddWidgetInfo info) {
+ final LauncherAppWidgetProviderInfo pInfo = info.info;
+
+ final Bundle options = pInfo.isCustomWidget ? null :
+ getDefaultOptionsForWidget(mLauncher, info);
+
+ // If there is a configuration activity, do not follow thru bound and inflate.
+ if (pInfo.configure != null) {
+ info.bindOptions = options;
+ return false;
+ }
+ setState(WIDGET_PRELOAD_PENDING);
+ mBindWidgetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (pInfo.isCustomWidget) {
+ setState(WIDGET_BOUND);
+ return;
+ }
+
+ mWidgetLoadingId = mLauncher.getAppWidgetHost().allocateAppWidgetId();
+ if(AppWidgetManagerCompat.getInstance(mLauncher).bindAppWidgetIdIfAllowed(
+ mWidgetLoadingId, pInfo, options)) {
+ setState(WIDGET_BOUND);
+ }
+ }
+ };
+ mHandler.post(mBindWidgetRunnable);
+
+ mInflateWidgetRunnable = new Runnable() {
+ @Override
+ public void run() {
+ if (mState != WIDGET_BOUND) {
+ return;
+ }
+ AppWidgetHostView hostView = mLauncher.getAppWidgetHost().createView(
+ (Context) mLauncher, mWidgetLoadingId, pInfo);
+ info.boundWidget = hostView;
+ setState(WIDGET_INFLATED);
+ hostView.setVisibility(View.INVISIBLE);
+ int[] unScaledSize = mLauncher.getWorkspace().estimateItemSize(info, false);
+
+ // We want the first widget layout to be the correct size. This will be important
+ // for width size reporting to the AppWidgetManager.
+ DragLayer.LayoutParams lp = new DragLayer.LayoutParams(unScaledSize[0],
+ unScaledSize[1]);
+ lp.x = lp.y = 0;
+ lp.customPosition = true;
+ hostView.setLayoutParams(lp);
+ mLauncher.getDragLayer().addView(hostView);
+ v.setTag(info);
+ }
+ };
+ mHandler.post(mInflateWidgetRunnable);
+ return true;
+ }
+
+ public static Bundle getDefaultOptionsForWidget(Launcher launcher, PendingAddWidgetInfo info) {
+ Bundle options = null;
+ Rect rect = new Rect();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ AppWidgetResizeFrame.getWidgetSizeRanges(launcher, info.spanX, info.spanY, rect);
+ Rect padding = AppWidgetHostView.getDefaultPaddingForWidget(launcher,
+ info.componentName, null);
+
+ float density = launcher.getResources().getDisplayMetrics().density;
+ int xPaddingDips = (int) ((padding.left + padding.right) / density);
+ int yPaddingDips = (int) ((padding.top + padding.bottom) / density);
+
+ options = new Bundle();
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH,
+ rect.left - xPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT,
+ rect.top - yPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH,
+ rect.right - xPaddingDips);
+ options.putInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT,
+ rect.bottom - yPaddingDips);
+ }
+ return options;
+ }
+
+ private void setState(int state) {
+ if (DEBUG) {
+ Log.d(TAG, String.format(" state [%d -> %d]", mState, state));
+ }
+ mState = state;
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsContainerView.java b/src/com/android/launcher3/widget/WidgetsContainerView.java
index 292a5de20..27a3ea13d 100644
--- a/src/com/android/launcher3/widget/WidgetsContainerView.java
+++ b/src/com/android/launcher3/widget/WidgetsContainerView.java
@@ -30,6 +30,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import android.widget.Toast;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeleteDropTarget;
@@ -54,15 +55,17 @@ import java.util.ArrayList;
/**
* The widgets list view container.
*/
-public class WidgetsContainerView extends FrameLayout implements Insettable, View.OnTouchListener,
- View.OnLongClickListener, DragSource{
+public class WidgetsContainerView extends FrameLayout implements Insettable,
+ View.OnLongClickListener, View.OnClickListener, DragSource{
- private static final String TAG = "WidgetContainerView";
+ private static final String TAG = "WidgetsContainerView";
private static final boolean DEBUG = false;
/* {@link RecyclerView} will keep following # of views in cache, before recycling. */
private static final int WIDGET_CACHE_SIZE = 2;
+ private static final int SPRING_MODE_DELAY_MS = 150;
+
/* Global instances that are used inside this container. */
private Launcher mLauncher;
private DragController mDragController;
@@ -75,12 +78,13 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
private RecyclerView mView;
private WidgetsListAdapter mAdapter;
- /* Dragging related. */
- private boolean mDraggingWidget = false; // TODO(hyunyoungs): seems not needed? check!
- private Point mLastTouchDownPos = new Point();
+ /* Touch handling related member variables. */
+ private Toast mWidgetInstructionToast;
/* Rendering related. */
private WidgetPreviewLoader mWidgetPreviewLoader;
+ private WidgetHostViewLoader mWidgetHostViewLoader;
+
private Rect mPadding = new Rect();
public WidgetsContainerView(Context context) {
@@ -95,8 +99,8 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
super(context, attrs, defStyleAttr);
mLauncher = (Launcher) context;
mDragController = mLauncher.getDragController();
-
- mAdapter = new WidgetsListAdapter(context, this, mLauncher, this, mLauncher);
+ mWidgetHostViewLoader = new WidgetHostViewLoader(mLauncher);
+ mAdapter = new WidgetsListAdapter(context, this, this, mLauncher);
mWidgets = new WidgetsModel(context, mAdapter);
mAdapter.setWidgetsModel(mWidgets);
mIconCache = (LauncherAppState.getInstance()).getIconCache();
@@ -147,11 +151,26 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
//
@Override
+ public void onClick(View v) {
+ // When we have exited widget tray or are in transition, disregard clicks
+ if (!mLauncher.isWidgetsViewVisible()
+ || mLauncher.getWorkspace().isSwitchingState()
+ || !(v instanceof WidgetCell)) return;
+
+ // Let the user know that they have to long press to add a widget
+ if (mWidgetInstructionToast != null) {
+ mWidgetInstructionToast.cancel();
+ }
+ mWidgetInstructionToast = Toast.makeText(getContext(),R.string.long_press_widget_to_add,
+ Toast.LENGTH_SHORT);
+ mWidgetInstructionToast.show();
+ }
+
+ @Override
public boolean onLongClick(View v) {
if (DEBUG) {
Log.d(TAG, String.format("onLonglick [v=%s]", v));
}
-
// Return early if this is not initiated from a touch
if (!v.isInTouchMode()) return false;
// When we have exited all apps or are in transition, disregard long clicks
@@ -161,7 +180,11 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
Log.d(TAG, String.format("onLonglick dragging enabled?.", v));
if (!mLauncher.isDraggingEnabled()) return false;
- return beginDragging(v);
+ boolean status = beginDragging(v);
+ if (status) {
+ mWidgetHostViewLoader.load(v);
+ }
+ return status;
}
private boolean beginDragging(View v) {
@@ -174,7 +197,7 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
}
// We delay entering spring-loaded mode slightly to make sure the UI
- // thready is free of any work.
+ // thread is free of any work.
postDelayed(new Runnable() {
@Override
public void run() {
@@ -184,13 +207,12 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
mLauncher.enterSpringLoadedDragMode();
}
}
- }, 150);
+ }, SPRING_MODE_DELAY_MS);
return true;
}
private boolean beginDraggingWidget(WidgetCell v) {
- mDraggingWidget = true;
// Get the widget preview as the drag representation
ImageView image = (ImageView) v.findViewById(R.id.widget_preview);
PendingAddItemInfo createItemInfo = (PendingAddItemInfo) v.getTag();
@@ -198,7 +220,6 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
// If the ImageView doesn't have a drawable yet, the widget preview hasn't been loaded and
// we abort the drag.
if (image.getDrawable() == null) {
- mDraggingWidget = false;
return false;
}
@@ -259,19 +280,6 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
return true;
}
- /*
- * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
- */
- @Override
- public boolean onTouch(View v, MotionEvent ev) {
- Log.d(TAG, String.format("onTouch [MotionEvent=%s]", ev));
- if (ev.getAction() == MotionEvent.ACTION_DOWN ||
- ev.getAction() == MotionEvent.ACTION_MOVE) {
- mLastTouchDownPos.set((int) ev.getX(), (int) ev.getY());
- }
- return false;
- }
-
//
// Drag related handling methods that implement {@link DragSource} interface.
//
@@ -340,6 +348,10 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
}
d.deferDragViewCleanupPostAnimation = false;
}
+ //TODO(hyunyoungs): if drop fails, this call cleans up correctly.
+ // However, in rare corner case where drop succeeds but doesn't end up using the widget
+ // id created by the loader, this finish will leave dangling widget id.
+ mWidgetHostViewLoader.finish(success);
}
//
@@ -368,5 +380,4 @@ public class WidgetsContainerView extends FrameLayout implements Insettable, Vie
}
return mWidgetPreviewLoader;
}
-
} \ No newline at end of file
diff --git a/src/com/android/launcher3/widget/WidgetsListAdapter.java b/src/com/android/launcher3/widget/WidgetsListAdapter.java
index afeb2d385..f6ab21eb4 100644
--- a/src/com/android/launcher3/widget/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/WidgetsListAdapter.java
@@ -56,20 +56,16 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
private WidgetsModel mWidgetsModel;
private WidgetPreviewLoader mWidgetPreviewLoader;
- private View.OnTouchListener mTouchListener;
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
-
public WidgetsListAdapter(Context context,
- View.OnTouchListener touchListener,
View.OnClickListener iconClickListener,
View.OnLongClickListener iconLongClickListener,
Launcher launcher) {
mLayoutInflater = LayoutInflater.from(context);
mContext = context;
- mTouchListener = touchListener;
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener;
@@ -109,7 +105,6 @@ public class WidgetsListAdapter extends Adapter<WidgetsRowViewHolder> {
// set up touch.
widget.setOnClickListener(mIconClickListener);
widget.setOnLongClickListener(mIconLongClickListener);
- widget.setOnTouchListener(mTouchListener);
row.addView(widget);
}
} else if (diff < 0) {