Merge "Change work paused label font" into ub-launcher3-master
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index d82e9f0..801408f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -48,6 +48,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.allapps.AllAppsStore;
@@ -325,7 +326,7 @@
mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache));
}
predictionLog.append("]");
- if (false) FileLog.d(TAG, predictionLog.toString());
+ if (Utilities.IS_DEBUG_DEVICE) FileLog.d(TAG, predictionLog.toString());
updateDependencies();
if (isReady()) {
fillGapsWithPrediction();
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index e6f8a85..21a8fd4 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -46,6 +46,7 @@
import com.android.launcher3.Launcher.OnResumeCallback;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dot.DotInfo;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.graphics.IconShape;
@@ -65,7 +66,7 @@
* too aggressive.
*/
public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback,
- IconLabelDotView {
+ IconLabelDotView, DraggableView {
private static final int DISPLAY_WORKSPACE = 0;
private static final int DISPLAY_ALL_APPS = 1;
@@ -103,7 +104,7 @@
private final ActivityContext mActivity;
private Drawable mIcon;
- private final boolean mCenterVertically;
+ private boolean mCenterVertically;
private final int mDisplay;
@@ -701,4 +702,24 @@
public int getIconSize() {
return mIconSize;
}
+
+ @Override
+ public int getViewType() {
+ return DRAGGABLE_ICON;
+ }
+
+ @Override
+ public void getVisualDragBounds(Rect bounds) {
+ DeviceProfile grid = mActivity.getDeviceProfile();
+ BubbleTextView.getIconBounds(this, bounds, grid.iconSizePx);
+ }
+
+ @Override
+ public void prepareDrawDragView() {
+ if (getIcon() instanceof FastBitmapDrawable) {
+ FastBitmapDrawable icon = (FastBitmapDrawable) getIcon();
+ icon.setScale(1f);
+ }
+ setForceHideDot(true);
+ }
}
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index f2d07f2..9682d09 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -56,6 +56,7 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.graphics.RotationMode;
@@ -100,6 +101,11 @@
@Thunk final int[] mTmpPoint = new int[2];
@Thunk final int[] mTempLocation = new int[2];
+ // Used to visualize / debug the Grid of the CellLayout
+ private static final boolean VISUALIZE_GRID = false;
+ private Rect mVisualizeGridRect = new Rect();
+ private Paint mVisualizeGridPaint = new Paint();
+
private GridOccupancy mOccupied;
private GridOccupancy mTmpOccupied;
@@ -462,6 +468,37 @@
mFolderLeaveBehind.drawLeaveBehind(canvas);
canvas.restore();
}
+
+ if (VISUALIZE_GRID) {
+ visualizeGrid(canvas);
+ }
+ }
+
+ protected void visualizeGrid(Canvas canvas) {
+ mVisualizeGridRect.set(0, 0, mCellWidth, mCellHeight);
+ mVisualizeGridPaint.setStrokeWidth(4);
+
+ for (int i = 0; i < mCountX; i++) {
+ for (int j = 0; j < mCountY; j++) {
+ canvas.save();
+
+ int transX = i * mCellWidth;
+ int transY = j * mCellHeight;
+
+ canvas.translate(getPaddingLeft() + transX, getPaddingTop() + transY);
+
+ mVisualizeGridPaint.setStyle(Paint.Style.FILL);
+ mVisualizeGridPaint.setColor(Color.argb(80, 255, 100, 100));
+
+ canvas.drawRect(mVisualizeGridRect, mVisualizeGridPaint);
+
+ mVisualizeGridPaint.setStyle(Paint.Style.STROKE);
+ mVisualizeGridPaint.setColor(Color.argb(255, 255, 100, 100));
+
+ canvas.drawRect(mVisualizeGridRect, mVisualizeGridPaint);
+ canvas.restore();
+ }
+ }
}
@Override
@@ -928,8 +965,8 @@
return false;
}
- void visualizeDropLocation(View v, DragPreviewProvider outlineProvider, int cellX, int cellY,
- int spanX, int spanY, boolean resize, DropTarget.DragObject dragObject) {
+ void visualizeDropLocation(DraggableView v, DragPreviewProvider outlineProvider, int cellX, int
+ cellY, int spanX, int spanY, boolean resize, DropTarget.DragObject dragObject) {
final int oldDragCellX = mDragCell[0];
final int oldDragCellY = mDragCell[1];
@@ -939,9 +976,6 @@
Bitmap dragOutline = outlineProvider.generatedDragOutline;
if (cellX != oldDragCellX || cellY != oldDragCellY) {
- Point dragOffset = dragObject.dragView.getDragVisualizeOffset();
- Rect dragRegion = dragObject.dragView.getDragRegion();
-
mDragCell[0] = cellX;
mDragCell[1] = cellY;
@@ -950,50 +984,27 @@
mDragOutlineCurrent = (oldIndex + 1) % mDragOutlines.length;
Rect r = mDragOutlines[mDragOutlineCurrent];
+ cellToRect(cellX, cellY, spanX, spanY, r);
+ int left = r.left;
+ int top = r.top;
+
+ int width = dragOutline.getWidth();
+ int height = dragOutline.getHeight();
+
if (resize) {
- cellToRect(cellX, cellY, spanX, spanY, r);
- if (v instanceof LauncherAppWidgetHostView) {
- DeviceProfile profile = mActivity.getWallpaperDeviceProfile();
- Utilities.shrinkRect(r, profile.appWidgetScale.x, profile.appWidgetScale.y);
- }
- } else {
- // Find the top left corner of the rect the object will occupy
- final int[] topLeft = mTmpPoint;
- cellToPoint(cellX, cellY, topLeft);
-
- int left = topLeft[0];
- int top = topLeft[1];
-
- if (v != null && dragOffset == null) {
- // When drawing the drag outline, it did not account for margin offsets
- // added by the view's parent.
- MarginLayoutParams lp = (MarginLayoutParams) v.getLayoutParams();
- left += lp.leftMargin;
- top += lp.topMargin;
-
- // Offsets due to the size difference between the View and the dragOutline.
- // There is a size difference to account for the outer blur, which may lie
- // outside the bounds of the view.
- top += ((mCellHeight * spanY) - dragOutline.getHeight()) / 2;
- // We center about the x axis
- left += ((mCellWidth * spanX) - dragOutline.getWidth()) / 2;
- } else {
- if (dragOffset != null && dragRegion != null) {
- // Center the drag region *horizontally* in the cell and apply a drag
- // outline offset
- left += dragOffset.x + ((mCellWidth * spanX) - dragRegion.width()) / 2;
- int cHeight = getShortcutsAndWidgets().getCellContentHeight();
- int cellPaddingY = (int) Math.max(0, ((mCellHeight - cHeight) / 2f));
- top += dragOffset.y + cellPaddingY;
- } else {
- // Center the drag outline in the cell
- left += ((mCellWidth * spanX) - dragOutline.getWidth()) / 2;
- top += ((mCellHeight * spanY) - dragOutline.getHeight()) / 2;
- }
- }
- r.set(left, top, left + dragOutline.getWidth(), top + dragOutline.getHeight());
+ width = r.width();
+ height = r.height();
}
+ if (v != null && v.getViewType() == DraggableView.DRAGGABLE_ICON) {
+ left += ((mCellWidth * spanX) - dragOutline.getWidth()) / 2;
+ int cHeight = getShortcutsAndWidgets().getCellContentHeight();
+ int cellPaddingY = (int) Math.max(0, ((mCellHeight - cHeight) / 2f));
+ top += cellPaddingY;
+ }
+
+ r.set(left, top, left + width, top + height);
+
Utilities.scaleRectAboutCenter(r, mChildScale);
mDragOutlineAnims[mDragOutlineCurrent].setTag(dragOutline);
mDragOutlineAnims[mDragOutlineCurrent].animateIn();
@@ -1879,7 +1890,7 @@
// This method starts or changes the reorder preview animations
private void beginOrAdjustReorderPreviewAnimations(ItemConfiguration solution,
- View dragView, int delay, int mode) {
+ View dragView, int mode) {
int childCount = mShortcutsAndWidgets.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = mShortcutsAndWidgets.getChildAt(i);
@@ -1946,6 +1957,8 @@
this.child = child;
this.mode = mode;
+
+ // TODO issue!
setInitialAnimationValues(false);
finalScale = (mChildScale - (CHILD_DIVIDEND / child.getWidth())) * initScale;
finalDeltaX = initDeltaX;
@@ -2141,6 +2154,8 @@
*/
private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
int spanY, View dragView, int[] resultDirection) {
+
+ //TODO(adamcohen) b/151776141 use the items visual center for the direction vector
int[] targetDestination = new int[2];
findNearestArea(dragViewCenterX, dragViewCenterY, spanX, spanY, targetDestination);
@@ -2251,7 +2266,7 @@
setItemPlacementDirty(false);
} else {
beginOrAdjustReorderPreviewAnimations(swapSolution, dragView,
- REORDER_ANIMATION_DURATION, ReorderPreviewAnimation.MODE_PREVIEW);
+ ReorderPreviewAnimation.MODE_PREVIEW);
}
mShortcutsAndWidgets.requestLayout();
}
@@ -2305,7 +2320,7 @@
if (mode == MODE_SHOW_REORDER_HINT) {
if (finalSolution != null) {
- beginOrAdjustReorderPreviewAnimations(finalSolution, dragView, 0,
+ beginOrAdjustReorderPreviewAnimations(finalSolution, dragView,
ReorderPreviewAnimation.MODE_HINT);
result[0] = finalSolution.cellX;
result[1] = finalSolution.cellY;
@@ -2345,7 +2360,7 @@
setItemPlacementDirty(false);
} else {
beginOrAdjustReorderPreviewAnimations(finalSolution, dragView,
- REORDER_ANIMATION_DURATION, ReorderPreviewAnimation.MODE_PREVIEW);
+ ReorderPreviewAnimation.MODE_PREVIEW);
}
}
} else {
diff --git a/src/com/android/launcher3/DropTarget.java b/src/com/android/launcher3/DropTarget.java
index c03011b..ef02e87 100644
--- a/src/com/android/launcher3/DropTarget.java
+++ b/src/com/android/launcher3/DropTarget.java
@@ -23,6 +23,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.folder.FolderNameProvider;
/**
@@ -69,6 +70,10 @@
public FolderNameProvider folderNameProvider;
+ /** The source view (ie. icon, widget etc.) that is being dragged and which the
+ * DragView represents. May be an actual View class or a virtual stand-in */
+ public DraggableView originalView = null;
+
public DragObject(Context context) {
if (FeatureFlags.FOLDER_NAME_SUGGEST.get()) {
folderNameProvider = FolderNameProvider.newInstance(context);
diff --git a/src/com/android/launcher3/FolderInfo.java b/src/com/android/launcher3/FolderInfo.java
index 336e423..b75a5e7 100644
--- a/src/com/android/launcher3/FolderInfo.java
+++ b/src/com/android/launcher3/FolderInfo.java
@@ -79,7 +79,7 @@
* Add an app or shortcut for a specified rank.
*/
public void add(WorkspaceItemInfo item, int rank, boolean animate) {
- rank = Utilities.boundToRange(rank, 0, contents.size() + 1);
+ rank = Utilities.boundToRange(rank, 0, contents.size());
contents.add(rank, item);
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onAdd(item, rank);
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 24d0c41..e071777 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -324,6 +324,7 @@
public AnimatorPlaybackController createAnimationToNewWorkspace(LauncherState state,
StateAnimationConfig config) {
+ config.userControlled = true;
mConfig.reset();
config.copyTo(mConfig);
mConfig.playbackController = createAnimationToNewWorkspaceInternal(state)
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 1bd8263..c07dd9d 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -145,38 +145,46 @@
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
-
- if (child instanceof LauncherAppWidgetHostView) {
- LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child;
-
- // Scale and center the widget to fit within its cells.
- DeviceProfile profile = mActivity.getDeviceProfile();
- float scaleX = profile.appWidgetScale.x;
- float scaleY = profile.appWidgetScale.y;
-
- lahv.setScaleToFit(Math.min(scaleX, scaleY));
- lahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
- -(lp.height - (lp.height * scaleY)) / 2.0f);
- }
-
- int childLeft = lp.x;
- int childTop = lp.y;
- child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
-
- if (lp.dropped) {
- lp.dropped = false;
-
- final int[] cellXY = mTmpCellXY;
- getLocationOnScreen(cellXY);
- mWallpaperManager.sendWallpaperCommand(getWindowToken(),
- WallpaperManager.COMMAND_DROP,
- cellXY[0] + childLeft + lp.width / 2,
- cellXY[1] + childTop + lp.height / 2, 0, null);
- }
+ layoutChild(child);
}
}
}
+ /**
+ * Core logic to layout a child for this ViewGroup.
+ */
+ public void layoutChild(View child) {
+ CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
+ if (child instanceof LauncherAppWidgetHostView) {
+ LauncherAppWidgetHostView lahv = (LauncherAppWidgetHostView) child;
+
+ // Scale and center the widget to fit within its cells.
+ DeviceProfile profile = mActivity.getDeviceProfile();
+ float scaleX = profile.appWidgetScale.x;
+ float scaleY = profile.appWidgetScale.y;
+
+ lahv.setScaleToFit(Math.min(scaleX, scaleY));
+ lahv.setTranslationForCentering(-(lp.width - (lp.width * scaleX)) / 2.0f,
+ -(lp.height - (lp.height * scaleY)) / 2.0f);
+ }
+
+ int childLeft = lp.x;
+ int childTop = lp.y;
+ child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
+
+ if (lp.dropped) {
+ lp.dropped = false;
+
+ final int[] cellXY = mTmpCellXY;
+ getLocationOnScreen(cellXY);
+ mWallpaperManager.sendWallpaperCommand(getWindowToken(),
+ WallpaperManager.COMMAND_DROP,
+ cellXY[0] + childLeft + lp.width / 2,
+ cellXY[1] + childTop + lp.height / 2, 0, null);
+ }
+ }
+
+
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == ACTION_DOWN && getAlpha() == 0) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 46493b7..c42e480 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -70,6 +70,7 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.dragndrop.SpringLoadedDragController;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -81,7 +82,6 @@
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
-import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@@ -1452,12 +1452,17 @@
+ "View: " + child + " tag: " + child.getTag();
throw new IllegalStateException(msg);
}
- beginDragShared(child, source, (ItemInfo) dragObject,
+ beginDragShared(child, null, source, (ItemInfo) dragObject,
new DragPreviewProvider(child), options);
}
- public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject,
- DragPreviewProvider previewProvider, DragOptions dragOptions) {
+ /**
+ * Core functionality for beginning a drag operation for an item that will be dropped within
+ * the workspace
+ */
+ public DragView beginDragShared(View child, DraggableView draggableView, DragSource source,
+ ItemInfo dragObject, DragPreviewProvider previewProvider, DragOptions dragOptions) {
+
float iconScale = 1f;
if (child instanceof BubbleTextView) {
Drawable icon = ((BubbleTextView) child).getIcon();
@@ -1466,41 +1471,36 @@
}
}
+ // Clear the pressed state if necessary
child.clearFocus();
child.setPressed(false);
+ if (child instanceof BubbleTextView) {
+ BubbleTextView icon = (BubbleTextView) child;
+ icon.clearPressedBackground();
+ }
+
mOutlineProvider = previewProvider;
// The drag bitmap follows the touch point around on the screen
final Bitmap b = previewProvider.createDragBitmap();
int halfPadding = previewProvider.previewPadding / 2;
-
float scale = previewProvider.getScaleAndPosition(b, mTempXY);
int dragLayerX = mTempXY[0];
int dragLayerY = mTempXY[1];
- DeviceProfile grid = mLauncher.getDeviceProfile();
Point dragVisualizeOffset = null;
- Rect dragRect = null;
- if (child instanceof BubbleTextView) {
- dragRect = new Rect();
- BubbleTextView.getIconBounds(child, dragRect, grid.iconSizePx);
+ Rect dragRect = new Rect();
+
+ if (draggableView == null && child instanceof DraggableView) {
+ draggableView = (DraggableView) child;
+ }
+
+ if (draggableView != null) {
+ draggableView.getVisualDragBounds(dragRect);
dragLayerY += dragRect.top;
- // Note: The dragRect is used to calculate drag layer offsets, but the
- // dragVisualizeOffset in addition to the dragRect (the size) to position the outline.
- dragVisualizeOffset = new Point(- halfPadding, halfPadding);
- } else if (child instanceof FolderIcon) {
- int previewSize = grid.folderIconSizePx;
- dragVisualizeOffset = new Point(- halfPadding, halfPadding - child.getPaddingTop());
- dragRect = new Rect(0, child.getPaddingTop(), child.getWidth(), previewSize);
- } else if (previewProvider instanceof ShortcutDragPreviewProvider) {
dragVisualizeOffset = new Point(- halfPadding, halfPadding);
}
- // Clear the pressed state if necessary
- if (child instanceof BubbleTextView) {
- BubbleTextView icon = (BubbleTextView) child;
- icon.clearPressedBackground();
- }
if (child.getParent() instanceof ShortcutAndWidgetContainer) {
mDragSourceInternal = (ShortcutAndWidgetContainer) child.getParent();
@@ -1511,13 +1511,13 @@
.showForIcon((BubbleTextView) child);
if (popupContainer != null) {
dragOptions.preDragCondition = popupContainer.createPreDragCondition();
-
mLauncher.getUserEventDispatcher().resetElapsedContainerMillis("dragging started");
}
}
- DragView dv = mDragController.startDrag(b, dragLayerX, dragLayerY, source,
- dragObject, dragVisualizeOffset, dragRect, scale * iconScale, scale, dragOptions);
+ DragView dv = mDragController.startDrag(b, draggableView, dragLayerX, dragLayerY, source,
+ dragObject, dragVisualizeOffset, dragRect, scale * iconScale,
+ scale, dragOptions);
dv.setIntrinsicIconScaleFactor(dragOptions.intrinsicIconScaleFactor);
return dv;
}
@@ -2186,7 +2186,7 @@
item.spanY, child, mTargetCell);
if (!nearestDropOccupied) {
- mDragTargetLayout.visualizeDropLocation(child, mOutlineProvider,
+ mDragTargetLayout.visualizeDropLocation(d.originalView, mOutlineProvider,
mTargetCell[0], mTargetCell[1], item.spanX, item.spanY, false, d);
} else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
&& !mReorderAlarm.alarmPending() && (mLastReorderX != reorderX ||
@@ -2279,7 +2279,8 @@
private void manageFolderFeedback(float distance, DragObject dragObject) {
if (distance > mMaxDistanceForFolderCreation) {
- if (mDragMode != DRAG_MODE_NONE) {
+ if ((mDragMode == DRAG_MODE_ADD_TO_FOLDER
+ || mDragMode == DRAG_MODE_CREATE_FOLDER)) {
setDragMode(DRAG_MODE_NONE);
}
return;
@@ -2368,7 +2369,7 @@
}
boolean resize = resultSpan[0] != spanX || resultSpan[1] != spanY;
- mDragTargetLayout.visualizeDropLocation(child, mOutlineProvider,
+ mDragTargetLayout.visualizeDropLocation(dragObject.originalView, mOutlineProvider,
mTargetCell[0], mTargetCell[1], resultSpan[0], resultSpan[1], resize, dragObject);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 10a3060..dd0212a 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -38,6 +38,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.dynamicanimation.animation.DynamicAnimation;
+import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -610,6 +611,7 @@
final Rect padding = new Rect();
AllAppsRecyclerView recyclerView;
boolean verticalFadingEdge;
+ private View mOverlay;
boolean mWorkDisabled;
@@ -646,13 +648,20 @@
if (mWorkDisabled == workDisabled) return;
recyclerView.setContentDescription(
workDisabled ? mLauncher.getString(R.string.work_apps_paused_title) : null);
+ View overlayView = getOverlayView();
+ recyclerView.setItemAnimator(new DefaultItemAnimator());
if (workDisabled) {
+ overlayView.setAlpha(0);
appsList.updateItemFilter((info, cn) -> false);
- recyclerView.addAutoSizedOverlay(
- mLauncher.getLayoutInflater().inflate(R.layout.work_apps_paused, null));
+ recyclerView.addAutoSizedOverlay(overlayView);
+ overlayView.animate().alpha(1).withEndAction(
+ () -> recyclerView.setItemAnimator(null)).start();
} else if (mInfoMatcher != null) {
appsList.updateItemFilter(mInfoMatcher);
- recyclerView.clearAutoSizedOverlays();
+ overlayView.animate().alpha(0).withEndAction(() -> {
+ recyclerView.setItemAnimator(null);
+ recyclerView.clearAutoSizedOverlays();
+ }).start();
}
mWorkDisabled = workDisabled;
}
@@ -671,5 +680,12 @@
mAH[AdapterHolder.MAIN].recyclerView.setVerticalFadingEdgeEnabled(!mUsingTabs
&& verticalFadingEdge);
}
+
+ private View getOverlayView() {
+ if (mOverlay == null) {
+ mOverlay = mLauncher.getLayoutInflater().inflate(R.layout.work_apps_paused, null);
+ }
+ return mOverlay;
+ }
}
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 4df3b0a..b3f87f0 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -163,7 +163,7 @@
"Always use hardware optimization for folder animations.");
public static final BooleanFlag ENABLE_FIXED_ROTATION_TRANSFORM = getDebugFlag(
- FLAG_ENABLE_FIXED_ROTATION_TRANSFORM, true,
+ FLAG_ENABLE_FIXED_ROTATION_TRANSFORM, false,
"Launch/close apps without rotation animation. Fix Launcher to portrait");
public static void initialize(Context context) {
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 1539747..d0d9aaf 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -137,6 +137,8 @@
*
* @param b The bitmap to display as the drag image. It will be re-scaled to the
* enlarged size.
+ * @param originalView The source view (ie. icon, widget etc.) that is being dragged
+ * and which the DragView represents
* @param dragLayerX The x position in the DragLayer of the left-top of the bitmap.
* @param dragLayerY The y position in the DragLayer of the left-top of the bitmap.
* @param source An object representing where the drag originated
@@ -144,7 +146,7 @@
* @param dragRegion Coordinates within the bitmap b for the position of item being dragged.
* Makes dragging feel more precise, e.g. you can clip out a transparent border
*/
- public DragView startDrag(Bitmap b, int dragLayerX, int dragLayerY,
+ public DragView startDrag(Bitmap b, DraggableView originalView, int dragLayerX, int dragLayerY,
DragSource source, ItemInfo dragInfo, Point dragOffset, Rect dragRegion,
float initialDragViewScale, float dragViewScaleOnDrop, DragOptions options) {
if (PROFILE_DRAWING_DURING_DRAG) {
@@ -170,6 +172,7 @@
mLastDropTarget = null;
mDragObject = new DropTarget.DragObject(mLauncher.getApplicationContext());
+ mDragObject.originalView = originalView;
mIsInPreDrag = mOptions.preDragCondition != null
&& !mOptions.preDragCondition.shouldStartDrag(0);
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 9d07595..e18ca54 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -41,7 +41,6 @@
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.widget.FrameLayout;
-import android.widget.TextView;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.CellLayout;
@@ -52,7 +51,6 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.folder.Folder;
-import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.graphics.WorkspaceAndHotseatScrim;
@@ -90,6 +88,8 @@
private int mTopViewIndex;
private int mChildCountOnLastUpdate = -1;
+ private Rect mTmpRect = new Rect();
+
// Related to adjacent page hints
private final ViewGroupFocusHelper mFocusIndicatorHelper;
private final WorkspaceAndHotseatScrim mWorkspaceScrim;
@@ -254,59 +254,46 @@
public void animateViewIntoPosition(DragView dragView, final View child, int duration,
View anchorView) {
+
ShortcutAndWidgetContainer parentChildren = (ShortcutAndWidgetContainer) child.getParent();
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
parentChildren.measureChild(child);
+ parentChildren.layoutChild(child);
- Rect r = new Rect();
- getViewRectRelativeToSelf(dragView, r);
+ getViewRectRelativeToSelf(dragView, mTmpRect);
+ final int fromX = mTmpRect.left;
+ final int fromY = mTmpRect.top;
float coord[] = new float[2];
float childScale = child.getScaleX();
+
coord[0] = lp.x + (child.getMeasuredWidth() * (1 - childScale) / 2);
coord[1] = lp.y + (child.getMeasuredHeight() * (1 - childScale) / 2);
// Since the child hasn't necessarily been laid out, we force the lp to be updated with
// the correct coordinates (above) and use these to determine the final location
float scale = getDescendantCoordRelativeToSelf((View) child.getParent(), coord);
+
// We need to account for the scale of the child itself, as the above only accounts for
// for the scale in parents.
scale *= childScale;
int toX = Math.round(coord[0]);
int toY = Math.round(coord[1]);
float toScale = scale;
- if (child instanceof TextView) {
- TextView tv = (TextView) child;
- // Account for the source scale of the icon (ie. from AllApps to Workspace, in which
- // the workspace may have smaller icon bounds).
- toScale = scale / dragView.getIntrinsicIconScaleFactor();
- // The child may be scaled (always about the center of the view) so to account for it,
- // we have to offset the position by the scaled size. Once we do that, we can center
- // the drag view about the scaled child view.
- // padding will remain constant (does not scale with size)
- toY += tv.getPaddingTop();
- toY -= dragView.getMeasuredHeight() * (1 - toScale) / 2;
- if (dragView.getDragVisualizeOffset() != null) {
- toY -= Math.round(toScale * dragView.getDragVisualizeOffset().y);
- }
+ if (child instanceof DraggableView) {
+ DraggableView d = (DraggableView) child;
+ d.getVisualDragBounds(mTmpRect);
- toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
- } else if (child instanceof FolderIcon) {
- // Account for holographic blur padding on the drag view
- toY += Math.round(scale * (child.getPaddingTop() - dragView.getDragRegionTop()));
- toY -= scale * dragView.getBlurSizeOutline() / 2;
- toY -= (1 - scale) * dragView.getMeasuredHeight() / 2;
- // Center in the x coordinate about the target's drawable
- toX -= (dragView.getMeasuredWidth() - Math.round(scale * child.getMeasuredWidth())) / 2;
- } else {
- toY -= (Math.round(scale * (dragView.getHeight() - child.getMeasuredHeight()))) / 2;
- toX -= (Math.round(scale * (dragView.getMeasuredWidth()
- - child.getMeasuredWidth()))) / 2;
+ // This accounts for the offset of the DragView created by scaling it about its
+ // center as it animates into place.
+ float scaleShiftX = dragView.getMeasuredWidth() * (1 - scale) / 2;
+ float scaleShiftY = dragView.getMeasuredHeight() * (1 - scale) / 2;
+
+ toX += scale * (mTmpRect.left - dragView.getBlurSizeOutline() / 2) - scaleShiftX;
+ toY += scale * (mTmpRect.top - dragView.getBlurSizeOutline() / 2) - scaleShiftY;
}
- final int fromX = r.left;
- final int fromY = r.top;
child.setVisibility(INVISIBLE);
Runnable onCompleteRunnable = () -> child.setVisibility(VISIBLE);
animateViewIntoPosition(dragView, fromX, fromY, toX, toY, 1, 1, 1, toScale, toScale,
diff --git a/src/com/android/launcher3/dragndrop/DraggableView.java b/src/com/android/launcher3/dragndrop/DraggableView.java
new file mode 100644
index 0000000..df99902
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/DraggableView.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 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.dragndrop;
+
+import android.graphics.Rect;
+
+/**
+ * Interface defining methods required for drawing and previewing DragViews, drag previews, and
+ * related animations
+ */
+public interface DraggableView {
+ int DRAGGABLE_ICON = 0;
+ int DRAGGABLE_WIDGET = 1;
+
+ /**
+ * Static ctr for a simple instance which just returns the view type.
+ */
+ static DraggableView ofType(int type) {
+ return () -> type;
+ }
+
+ /**
+ * Certain handling of DragViews depend only on whether this is an Icon Type item or a Widget
+ * Type item.
+ *
+ * @return DRAGGABLE_ICON or DRAGGABLE_WIDGET as appropriate
+ */
+ int getViewType();
+
+ /**
+ * Before rendering as a DragView bitmap, some views need a preparation step.
+ */
+ default void prepareDrawDragView() { }
+
+ /**
+ * If an actual View subclass, this method returns the rectangle (within the View's coordinates)
+ * of the visual region that should get dragged. This is used to extract exactly that element
+ * as well as to offset that element as appropriate for various animations
+ *
+ * @param bounds Visual bounds in the views coordinates will be written here.
+ */
+ default void getVisualDragBounds(Rect bounds) { }
+}
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index 0bb3fba..ea1fbdb 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -20,10 +20,10 @@
import android.annotation.TargetApi;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -33,7 +33,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.ShiftedBitmapDrawable;
@@ -50,6 +49,7 @@
private final Drawable mBadge;
private final Path mMask;
private final ConstantState mConstantState;
+ private static final Rect sTmpRect = new Rect();
private FolderAdaptiveIcon(Drawable bg, Drawable fg, Drawable badge, Path mask) {
super(bg, fg);
@@ -72,23 +72,14 @@
public static @Nullable FolderAdaptiveIcon createFolderAdaptiveIcon(
Launcher launcher, int folderId, Point dragViewSize) {
Preconditions.assertNonUiThread();
- int margin = launcher.getResources()
- .getDimensionPixelSize(R.dimen.blur_size_medium_outline);
-
- // Allocate various bitmaps on the background thread, because why not!
- int width = dragViewSize.x - margin;
- int height = dragViewSize.y - margin;
- if (width <= 0 || height <= 0) {
- return null;
- }
- final Bitmap badge = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// Create the actual drawable on the UI thread to avoid race conditions with
// FolderIcon draw pass
try {
return MAIN_EXECUTOR.submit(() -> {
FolderIcon icon = launcher.findFolderIcon(folderId);
- return icon == null ? null : createDrawableOnUiThread(icon, badge, dragViewSize);
+ return icon == null ? null : createDrawableOnUiThread(icon, dragViewSize);
+
}).get();
} catch (Exception e) {
Log.e(TAG, "Unable to create folder icon", e);
@@ -96,49 +87,50 @@
}
}
- /**
- * Initializes various bitmaps on the UI thread and returns the final drawable.
- */
private static FolderAdaptiveIcon createDrawableOnUiThread(FolderIcon icon,
- Bitmap badgeBitmap, Point dragViewSize) {
+ Point dragViewSize) {
Preconditions.assertUIThread();
- float margin = icon.getResources().getDimension(R.dimen.blur_size_medium_outline) / 2;
- Canvas c = new Canvas();
+ icon.getPreviewBounds(sTmpRect);
+
PreviewBackground bg = icon.getFolderBackground();
- // Initialize badge
- c.setBitmap(badgeBitmap);
- bg.drawShadow(c);
- bg.drawBackgroundStroke(c);
- icon.drawDot(c);
+ // assume square
+ assert (dragViewSize.x == dragViewSize.y);
+ final int previewSize = sTmpRect.width();
- // Initialize preview
- final float sizeScaleFactor = 1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction();
- final int previewWidth = (int) (dragViewSize.x * sizeScaleFactor);
- final int previewHeight = (int) (dragViewSize.y * sizeScaleFactor);
+ final int margin = (dragViewSize.x - previewSize) / 2;
+ final float previewShiftX = -sTmpRect.left + margin;
+ final float previewShiftY = -sTmpRect.top + margin;
- final float shiftFactor = AdaptiveIconDrawable.getExtraInsetFraction() / sizeScaleFactor;
- final float previewShiftX = shiftFactor * previewWidth;
- final float previewShiftY = shiftFactor * previewHeight;
-
- Bitmap previewBitmap = BitmapRenderer.createHardwareBitmap(previewWidth, previewHeight,
+ // Initialize badge, which consists of the outline stroke, shadow and dot; these
+ // must be rendered above the foreground
+ Bitmap badgeBmp = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
(canvas) -> {
- int count = canvas.save();
+ canvas.save();
canvas.translate(previewShiftX, previewShiftY);
- icon.getPreviewItemManager().draw(canvas);
- canvas.restoreToCount(count);
+ bg.drawShadow(canvas);
+ bg.drawBackgroundStroke(canvas);
+ icon.drawDot(canvas);
+ canvas.restore();
});
// Initialize mask
Path mask = new Path();
Matrix m = new Matrix();
- m.setTranslate(margin, margin);
+ m.setTranslate(previewShiftX, previewShiftY);
bg.getClipPath().transform(m, mask);
- ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBitmap, margin, margin);
- ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap,
- margin - previewShiftX, margin - previewShiftY);
+ Bitmap previewBitmap = BitmapRenderer.createHardwareBitmap(dragViewSize.x, dragViewSize.y,
+ (canvas) -> {
+ canvas.save();
+ canvas.translate(previewShiftX, previewShiftY);
+ icon.getPreviewItemManager().draw(canvas);
+ canvas.restore();
+ });
+
+ ShiftedBitmapDrawable badge = new ShiftedBitmapDrawable(badgeBmp, 0, 0);
+ ShiftedBitmapDrawable foreground = new ShiftedBitmapDrawable(previewBitmap, 0, 0);
return new FolderAdaptiveIcon(new ColorDrawable(bg.getBgColor()), foreground, badge, mask);
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 14fa1f4..365e76f 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -81,6 +81,7 @@
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.Workspace.ItemOperator;
import com.android.launcher3.WorkspaceItemInfo;
@@ -962,6 +963,7 @@
View icon = (mCurrentDragView != null && mCurrentDragView.getTag() == info)
? mCurrentDragView : mContent.createNewView(info);
ArrayList<View> views = getIconsInReadingOrder();
+ info.rank = Utilities.boundToRange(info.rank, 0, views.size());
views.add(info.rank, icon);
mContent.arrangeChildren(views);
mItemsInvalidated = true;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index ab1ff10..f0d18ae 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -63,6 +63,7 @@
import com.android.launcher3.dragndrop.BaseItemDragListener;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Executors;
@@ -78,7 +79,8 @@
/**
* An icon that can appear on in the workspace representing an {@link Folder}.
*/
-public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView {
+public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView,
+ DraggableView {
@Thunk ActivityContext mActivity;
@Thunk Folder mFolder;
@@ -230,6 +232,16 @@
mBackground.getBounds(outBounds);
}
+ @Override
+ public int getViewType() {
+ return DRAGGABLE_ICON;
+ }
+
+ @Override
+ public void getVisualDragBounds(Rect bounds) {
+ getPreviewBounds(bounds);
+ }
+
public float getBackgroundStrokeWidth() {
return mBackground.getStrokeWidth();
}
@@ -525,6 +537,10 @@
invalidate();
}
+ public boolean getIconVisible() {
+ return mBackgroundIsVisible;
+ }
+
public PreviewBackground getFolderBackground() {
return mBackground;
}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index 94d30f6..ed9dfbb 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -30,14 +30,12 @@
import android.view.View;
import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.launcher3.widget.PendingAppWidgetHostView;
import java.nio.ByteBuffer;
@@ -53,7 +51,7 @@
// The padding added to the drag view during the preview generation.
public final int previewPadding;
- protected final int blurSizeOutline;
+ public final int blurSizeOutline;
private OutlineGeneratorCallback mOutlineGeneratorCallback;
public Bitmap generatedDragOutline;
@@ -66,56 +64,25 @@
mView = view;
blurSizeOutline =
context.getResources().getDimensionPixelSize(R.dimen.blur_size_medium_outline);
-
- if (mView instanceof BubbleTextView) {
- Drawable d = ((BubbleTextView) mView).getIcon();
- Rect bounds = getDrawableBounds(d);
- previewPadding = blurSizeOutline - bounds.left - bounds.top;
- } else {
- previewPadding = blurSizeOutline;
- }
+ previewPadding = blurSizeOutline;
}
/**
* Draws the {@link #mView} into the given {@param destCanvas}.
*/
protected void drawDragView(Canvas destCanvas, float scale) {
- destCanvas.save();
+ int saveCount = destCanvas.save();
destCanvas.scale(scale, scale);
- if (mView instanceof BubbleTextView) {
- Drawable d = ((BubbleTextView) mView).getIcon();
- Rect bounds = getDrawableBounds(d);
- destCanvas.translate(blurSizeOutline / 2 - bounds.left,
- blurSizeOutline / 2 - bounds.top);
- if (d instanceof FastBitmapDrawable) {
- ((FastBitmapDrawable) d).setScale(1);
- }
- d.draw(destCanvas);
- } else {
- final Rect clipRect = mTempRect;
- mView.getDrawingRect(clipRect);
-
- boolean textVisible = false;
- if (mView instanceof FolderIcon) {
- // For FolderIcons the text can bleed into the icon area, and so we need to
- // hide the text completely (which can't be achieved by clipping).
- if (((FolderIcon) mView).getTextVisible()) {
- ((FolderIcon) mView).setTextVisible(false);
- textVisible = true;
- }
- }
- destCanvas.translate(-mView.getScrollX() + blurSizeOutline / 2,
- -mView.getScrollY() + blurSizeOutline / 2);
- destCanvas.clipRect(clipRect);
+ if (mView instanceof DraggableView) {
+ DraggableView dv = (DraggableView) mView;
+ dv.prepareDrawDragView();
+ dv.getVisualDragBounds(mTempRect);
+ destCanvas.translate(blurSizeOutline / 2 - mTempRect.left,
+ blurSizeOutline / 2 - mTempRect.top);
mView.draw(destCanvas);
-
- // Restore text visibility of FolderIcon if necessary
- if (textVisible) {
- ((FolderIcon) mView).setTextVisible(true);
- }
}
- destCanvas.restore();
+ destCanvas.restoreToCount(saveCount);
}
/**
@@ -123,28 +90,15 @@
* Responsibility for the bitmap is transferred to the caller.
*/
public Bitmap createDragBitmap() {
- int width = mView.getWidth();
- int height = mView.getHeight();
-
- if (mView instanceof BubbleTextView) {
- Drawable d = ((BubbleTextView) mView).getIcon();
- Rect bounds = getDrawableBounds(d);
- width = bounds.width();
- height = bounds.height();
- } else if (mView instanceof LauncherAppWidgetHostView) {
- float scale = ((LauncherAppWidgetHostView) mView).getScaleToFit();
- width = (int) (mView.getWidth() * scale);
- height = (int) (mView.getHeight() * scale);
-
- if (mView instanceof PendingAppWidgetHostView) {
- // Use hardware renderer as the icon for the pending app widget may be a hw bitmap
- return BitmapRenderer.createHardwareBitmap(width + blurSizeOutline,
- height + blurSizeOutline, (c) -> drawDragView(c, scale));
- } else {
- // Use software renderer for widgets as we know that they already work
- return BitmapRenderer.createSoftwareBitmap(width + blurSizeOutline,
- height + blurSizeOutline, (c) -> drawDragView(c, scale));
- }
+ int width = 0;
+ int height = 0;
+ if (mView instanceof DraggableView) {
+ ((DraggableView) mView).getVisualDragBounds(mTempRect);
+ width = mTempRect.width();
+ height = mTempRect.height();
+ } else {
+ width = mView.getWidth();
+ height = mView.getHeight();
}
return BitmapRenderer.createHardwareBitmap(width + blurSizeOutline,
diff --git a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
index 3fb2bf6..7b7ab5e 100644
--- a/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
+++ b/src/com/android/launcher3/graphics/WorkspaceAndHotseatScrim.java
@@ -40,12 +40,14 @@
import android.util.DisplayMetrics;
import android.util.FloatProperty;
import android.view.View;
+import android.view.WindowInsets;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.CellLayout;
import com.android.launcher3.R;
import com.android.launcher3.ResourceUtils;
+import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.util.Themes;
@@ -198,9 +200,22 @@
* Determines whether to draw the top and/or bottom scrim based on new insets.
*/
public void onInsetsChanged(Rect insets, boolean allowSysuiScrims) {
- mDrawTopScrim = allowSysuiScrims && mTopScrim != null && insets.top > 0;
- mDrawBottomScrim = allowSysuiScrims && mBottomMask != null
- && !mLauncher.getDeviceProfile().isVerticalBarLayout();
+ mDrawTopScrim = allowSysuiScrims
+ && mTopScrim != null
+ && insets.top > 0;
+ mDrawBottomScrim = allowSysuiScrims
+ && mBottomMask != null
+ && !mLauncher.getDeviceProfile().isVerticalBarLayout()
+ && hasBottomNavButtons();
+ }
+
+ private boolean hasBottomNavButtons() {
+ if (Utilities.ATLEAST_Q && mLauncher.getRootView() != null
+ && mLauncher.getRootView().getRootWindowInsets() != null) {
+ WindowInsets windowInsets = mLauncher.getRootView().getRootWindowInsets();
+ return windowInsets.getTappableElementInsets().bottom > 0;
+ }
+ return true;
}
@Override
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index a9d10d7..1b70fde 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.logging;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType.NAVBAR;
-
import android.util.ArrayMap;
import android.util.SparseArray;
import android.view.View;
@@ -27,12 +25,9 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.userevent.nano.LauncherLogExtensions.TargetExtension;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-import com.android.launcher3.userevent.nano.LauncherLogProto.TipType;
import com.android.launcher3.util.InstantAppResolver;
import java.lang.reflect.Field;
@@ -70,93 +65,6 @@
return result != null ? result : UNKNOWN;
}
- public static String getActionStr(Action action) {
- String str = "";
- switch (action.type) {
- case Action.Type.TOUCH:
- str += getFieldName(action.touch, Action.Touch.class);
- if (action.touch == Action.Touch.SWIPE || action.touch == Action.Touch.FLING) {
- str += " direction=" + getFieldName(action.dir, Action.Direction.class);
- }
- break;
- case Action.Type.COMMAND:
- str += getFieldName(action.command, Action.Command.class);
- break;
- default: return getFieldName(action.type, Action.Type.class);
- }
- if (action.touch == Action.Touch.SWIPE || action.touch == Action.Touch.FLING ||
- (action.command == Action.Command.BACK && action.dir != Action.Direction.NONE)) {
- str += " direction=" + getFieldName(action.dir, Action.Direction.class);
- }
- return str;
- }
-
- public static String getTargetStr(Target t) {
- if (t == null) {
- return "";
- }
- String str = "";
- switch (t.type) {
- case Target.Type.ITEM:
- str = getItemStr(t);
- break;
- case Target.Type.CONTROL:
- str = getFieldName(t.controlType, ControlType.class);
- break;
- case Target.Type.CONTAINER:
- str = getFieldName(t.containerType, ContainerType.class);
- if (t.containerType == ContainerType.WORKSPACE ||
- t.containerType == ContainerType.HOTSEAT ||
- t.containerType == NAVBAR) {
- str += " id=" + t.pageIndex;
- } else if (t.containerType == ContainerType.FOLDER) {
- str += " grid(" + t.gridX + "," + t.gridY + ")";
- }
- break;
- default:
- str += "UNKNOWN TARGET TYPE";
- }
-
- if (t.spanX != 1 || t.spanY != 1) {
- str += " span(" + t.spanX + "," + t.spanY + ")";
- }
-
- if (t.tipType != TipType.DEFAULT_NONE) {
- str += " " + getFieldName(t.tipType, TipType.class);
- }
-
- return str;
- }
-
- private static String getItemStr(Target t) {
- String typeStr = getFieldName(t.itemType, ItemType.class);
- if (t.packageNameHash != 0) {
- typeStr += ", packageHash=" + t.packageNameHash;
- }
- if (t.componentHash != 0) {
- typeStr += ", componentHash=" + t.componentHash;
- }
- if (t.intentHash != 0) {
- typeStr += ", intentHash=" + t.intentHash;
- }
- if (t.itemType == ItemType.FOLDER_ICON) {
- typeStr += ", grid(" + t.gridX + "," + t.gridY + ")";
- } else if ((t.packageNameHash != 0 || t.componentHash != 0 || t.intentHash != 0)
- && t.itemType != ItemType.TASK) {
- typeStr +=
- ", isWorkApp=" + t.isWorkApp + ", predictiveRank=" + t.predictedRank + ", grid("
- + t.gridX + "," + t.gridY + "), span(" + t.spanX + "," + t.spanY
- + "), pageIdx=" + t.pageIndex;
- }
- if (t.searchQueryLength != 0) {
- typeStr += ", searchQueryLength=" + t.searchQueryLength;
- }
- if (t.itemType == ItemType.TASK) {
- typeStr += ", pageIdx=" + t.pageIndex;
- }
- return typeStr;
- }
-
public static Target newItemTarget(int itemType) {
Target t = newTarget(Target.Type.ITEM);
t.itemType = itemType;
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 32fce0b..fdfcef1 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -424,7 +424,8 @@
// Now add the new shortcuts to the map.
for (ShortcutInfo shortcut : shortcuts) {
boolean shouldShowInContainer = shortcut.isEnabled()
- && (shortcut.isDeclaredInManifest() || shortcut.isDynamic());
+ && (shortcut.isDeclaredInManifest() || shortcut.isDynamic())
+ && shortcut.getActivity() != null;
if (shouldShowInContainer) {
ComponentKey targetComponent
= new ComponentKey(shortcut.getActivity(), shortcut.getUserHandle());
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 5af5ebb..9bac259 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -59,6 +59,7 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationItemView;
import com.android.launcher3.notification.NotificationKeyData;
@@ -662,7 +663,8 @@
iconShift.x = mIconLastTouchPos.x - sv.getIconCenter().x;
iconShift.y = mIconLastTouchPos.y - mLauncher.getDeviceProfile().iconSizePx;
- DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getIconView(),
+ DraggableView draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
+ DragView dv = mLauncher.getWorkspace().beginDragShared(sv.getIconView(), draggableView,
mContainer, sv.getFinalInfo(),
new ShortcutDragPreviewProvider(sv.getIconView(), iconShift),
new DragOptions());
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index fae0fe2..8c8aa9b 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -134,7 +134,7 @@
*/
private void updateForcedRotation(boolean setValueFromPrefs) {
boolean isForcedRotation = mFeatureFlagsPrefs
- .getBoolean(FLAG_ENABLE_FIXED_ROTATION_TRANSFORM, true)
+ .getBoolean(FLAG_ENABLE_FIXED_ROTATION_TRANSFORM, false)
&& !getAllowRotationDefaultValue();
if (mForcedRotation == isForcedRotation) {
return;
diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java
new file mode 100644
index 0000000..478141a
--- /dev/null
+++ b/src/com/android/launcher3/views/ClipIconView.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2020 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.views;
+
+import static com.android.launcher3.Utilities.mapToRange;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.graphics.Path;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewOutlineProvider;
+
+import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
+import androidx.dynamicanimation.animation.SpringAnimation;
+import androidx.dynamicanimation.animation.SpringForce;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InsettableFrameLayout.LayoutParams;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
+import com.android.launcher3.graphics.IconShape;
+
+/**
+ * A view used to draw both layers of an {@link AdaptiveIconDrawable}.
+ * Supports springing just the foreground layer.
+ * Supports clipping the icon to/from its icon shape.
+ */
+@TargetApi(Build.VERSION_CODES.Q)
+public class ClipIconView extends View implements ClipPathView {
+
+ private static final Rect sTmpRect = new Rect();
+
+ // We spring the foreground drawable relative to the icon's movement in the DragLayer.
+ // We then use these two factor values to scale the movement of the fg within this view.
+ private static final int FG_TRANS_X_FACTOR = 60;
+ private static final int FG_TRANS_Y_FACTOR = 75;
+
+ private static final FloatPropertyCompat<ClipIconView> mFgTransYProperty =
+ new FloatPropertyCompat<ClipIconView>("ClipIconViewFgTransY") {
+ @Override
+ public float getValue(ClipIconView view) {
+ return view.mFgTransY;
+ }
+
+ @Override
+ public void setValue(ClipIconView view, float transY) {
+ view.mFgTransY = transY;
+ view.invalidate();
+ }
+ };
+
+ private static final FloatPropertyCompat<ClipIconView> mFgTransXProperty =
+ new FloatPropertyCompat<ClipIconView>("ClipIconViewFgTransX") {
+ @Override
+ public float getValue(ClipIconView view) {
+ return view.mFgTransX;
+ }
+
+ @Override
+ public void setValue(ClipIconView view, float transX) {
+ view.mFgTransX = transX;
+ view.invalidate();
+ }
+ };
+
+ private final Launcher mLauncher;
+ private final int mBlurSizeOutline;
+ private final boolean mIsRtl;
+
+ private @Nullable Drawable mForeground;
+ private @Nullable Drawable mBackground;
+
+ private boolean mIsVerticalBarLayout = false;
+ private boolean mIsAdaptiveIcon = false;
+
+ private ValueAnimator mRevealAnimator;
+
+ private final Rect mStartRevealRect = new Rect();
+ private final Rect mEndRevealRect = new Rect();
+ private Path mClipPath;
+ private float mTaskCornerRadius;
+
+ private final Rect mOutline = new Rect();
+ private final Rect mFinalDrawableBounds = new Rect();
+
+ private final SpringAnimation mFgSpringY;
+ private float mFgTransY;
+ private final SpringAnimation mFgSpringX;
+ private float mFgTransX;
+
+ public ClipIconView(Context context) {
+ this(context, null);
+ }
+
+ public ClipIconView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ClipIconView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+ mBlurSizeOutline = getResources().getDimensionPixelSize(
+ R.dimen.blur_size_medium_outline);
+ mIsRtl = Utilities.isRtl(getResources());
+
+ mFgSpringX = new SpringAnimation(this, mFgTransXProperty)
+ .setSpring(new SpringForce()
+ .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW));
+ mFgSpringY = new SpringAnimation(this, mFgTransYProperty)
+ .setSpring(new SpringForce()
+ .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW));
+ }
+
+ void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
+ boolean isOpening, float scale, float minSize, LayoutParams parentLp) {
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ float dX = mIsRtl
+ ? rect.left - (dp.widthPx - parentLp.getMarginStart() - parentLp.width)
+ : rect.left - parentLp.getMarginStart();
+ float dY = rect.top - parentLp.topMargin;
+
+ // shapeRevealProgress = 1 when progress = shapeProgressStart + SHAPE_PROGRESS_DURATION
+ float toMax = isOpening ? 1 / SHAPE_PROGRESS_DURATION : 1f;
+ float shapeRevealProgress = Utilities.boundToRange(mapToRange(
+ Math.max(shapeProgressStart, progress), shapeProgressStart, 1f, 0, toMax,
+ LINEAR), 0, 1);
+
+ if (mIsVerticalBarLayout) {
+ mOutline.right = (int) (rect.width() / scale);
+ } else {
+ mOutline.bottom = (int) (rect.height() / scale);
+ }
+
+ mTaskCornerRadius = cornerRadius / scale;
+ if (mIsAdaptiveIcon) {
+ if (!isOpening && progress >= shapeProgressStart) {
+ if (mRevealAnimator == null) {
+ mRevealAnimator = (ValueAnimator) IconShape.getShape().createRevealAnimator(
+ this, mStartRevealRect, mOutline, mTaskCornerRadius, !isOpening);
+ mRevealAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mRevealAnimator = null;
+ }
+ });
+ mRevealAnimator.start();
+ // We pause here so we can set the current fraction ourselves.
+ mRevealAnimator.pause();
+ }
+ mRevealAnimator.setCurrentFraction(shapeRevealProgress);
+ }
+
+ float drawableScale = (mIsVerticalBarLayout ? mOutline.width() : mOutline.height())
+ / minSize;
+ setBackgroundDrawableBounds(drawableScale);
+ if (isOpening) {
+ // Center align foreground
+ int height = mFinalDrawableBounds.height();
+ int width = mFinalDrawableBounds.width();
+ int diffY = mIsVerticalBarLayout ? 0
+ : (int) (((height * drawableScale) - height) / 2);
+ int diffX = mIsVerticalBarLayout ? (int) (((width * drawableScale) - width) / 2)
+ : 0;
+ sTmpRect.set(mFinalDrawableBounds);
+ sTmpRect.offset(diffX, diffY);
+ mForeground.setBounds(sTmpRect);
+ } else {
+ // Spring the foreground relative to the icon's movement within the DragLayer.
+ int diffX = (int) (dX / dp.availableWidthPx * FG_TRANS_X_FACTOR);
+ int diffY = (int) (dY / dp.availableHeightPx * FG_TRANS_Y_FACTOR);
+
+ mFgSpringX.animateToFinalPosition(diffX);
+ mFgSpringY.animateToFinalPosition(diffY);
+ }
+ }
+ invalidate();
+ invalidateOutline();
+ }
+
+ private void setBackgroundDrawableBounds(float scale) {
+ sTmpRect.set(mFinalDrawableBounds);
+ Utilities.scaleRectAboutCenter(sTmpRect, scale);
+ // Since the drawable is at the top of the view, we need to offset to keep it centered.
+ if (mIsVerticalBarLayout) {
+ sTmpRect.offsetTo((int) (mFinalDrawableBounds.left * scale), sTmpRect.top);
+ } else {
+ sTmpRect.offsetTo(sTmpRect.left, (int) (mFinalDrawableBounds.top * scale));
+ }
+ mBackground.setBounds(sTmpRect);
+ }
+
+ protected void endReveal() {
+ if (mRevealAnimator != null) {
+ mRevealAnimator.end();
+ }
+ }
+
+ void setIcon(@Nullable Drawable drawable, int iconOffset, LayoutParams lp, boolean isOpening) {
+ mIsAdaptiveIcon = drawable instanceof AdaptiveIconDrawable;
+ if (mIsAdaptiveIcon) {
+ boolean isFolderIcon = drawable instanceof FolderAdaptiveIcon;
+
+ AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) drawable;
+ Drawable background = adaptiveIcon.getBackground();
+ if (background == null) {
+ background = new ColorDrawable(Color.TRANSPARENT);
+ }
+ mBackground = background;
+ Drawable foreground = adaptiveIcon.getForeground();
+ if (foreground == null) {
+ foreground = new ColorDrawable(Color.TRANSPARENT);
+ }
+ mForeground = foreground;
+
+ final int originalHeight = lp.height;
+ final int originalWidth = lp.width;
+
+ int blurMargin = mBlurSizeOutline / 2;
+ mFinalDrawableBounds.set(0, 0, originalWidth, originalHeight);
+
+ if (!isFolderIcon) {
+ mFinalDrawableBounds.inset(iconOffset - blurMargin, iconOffset - blurMargin);
+ }
+ mForeground.setBounds(mFinalDrawableBounds);
+ mBackground.setBounds(mFinalDrawableBounds);
+
+ mStartRevealRect.set(0, 0, originalWidth, originalHeight);
+
+ if (!isFolderIcon) {
+ Utilities.scaleRectAboutCenter(mStartRevealRect, IconShape.getNormalizationScale());
+ }
+
+ float aspectRatio = mLauncher.getDeviceProfile().aspectRatio;
+ if (mIsVerticalBarLayout) {
+ lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
+ } else {
+ lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
+ }
+
+ int left = mIsRtl
+ ? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width
+ : lp.leftMargin;
+ layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
+
+ float scale = Math.max((float) lp.height / originalHeight,
+ (float) lp.width / originalWidth);
+ float bgDrawableStartScale;
+ if (isOpening) {
+ bgDrawableStartScale = 1f;
+ mOutline.set(0, 0, originalWidth, originalHeight);
+ } else {
+ bgDrawableStartScale = scale;
+ mOutline.set(0, 0, lp.width, lp.height);
+ }
+ setBackgroundDrawableBounds(bgDrawableStartScale);
+ mEndRevealRect.set(0, 0, lp.width, lp.height);
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(mOutline, mTaskCornerRadius);
+ }
+ });
+ setClipToOutline(true);
+ } else {
+ setBackground(drawable);
+ setClipToOutline(false);
+ }
+
+ invalidate();
+ invalidateOutline();
+ }
+
+ @Override
+ public void setClipPath(Path clipPath) {
+ mClipPath = clipPath;
+ invalidate();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ int count = canvas.save();
+ if (mClipPath != null) {
+ canvas.clipPath(mClipPath);
+ }
+ super.draw(canvas);
+ if (mBackground != null) {
+ mBackground.draw(canvas);
+ }
+ if (mForeground != null) {
+ int count2 = canvas.save();
+ canvas.translate(mFgTransX, mFgTransY);
+ mForeground.draw(canvas);
+ canvas.restoreToCount(count2);
+ }
+ canvas.restoreToCount(count);
+ }
+
+ void recycle() {
+ setBackground(null);
+ mIsAdaptiveIcon = false;
+ mForeground = null;
+ mBackground = null;
+ mClipPath = null;
+ mFinalDrawableBounds.setEmpty();
+ if (mRevealAnimator != null) {
+ mRevealAnimator.cancel();
+ }
+ mRevealAnimator = null;
+ mTaskCornerRadius = 0;
+ mOutline.setEmpty();
+ mFgTransY = 0;
+ mFgSpringX.cancel();
+ mFgTransX = 0;
+ mFgSpringY.cancel();
+ }
+}
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index fa625ed..3e2560f 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -18,8 +18,6 @@
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.Utilities.getBadge;
import static com.android.launcher3.Utilities.getFullDrawable;
-import static com.android.launcher3.Utilities.mapToRange;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -28,17 +26,12 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Outline;
-import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.CancellationSignal;
@@ -46,19 +39,17 @@
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
+import android.widget.FrameLayout;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.annotation.WorkerThread;
-import androidx.dynamicanimation.animation.FloatPropertyCompat;
-import androidx.dynamicanimation.animation.SpringAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.InsettableFrameLayout.LayoutParams;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
@@ -66,8 +57,6 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.graphics.IconShape;
-import com.android.launcher3.graphics.ShiftedBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.DeepShortcutView;
@@ -76,8 +65,8 @@
* A view that is created to look like another view with the purpose of creating fluid animations.
*/
@TargetApi(Build.VERSION_CODES.Q)
-public class FloatingIconView extends View implements
- Animator.AnimatorListener, ClipPathView, OnGlobalLayoutListener {
+public class FloatingIconView extends FrameLayout implements
+ Animator.AnimatorListener, OnGlobalLayoutListener {
private static final String TAG = FloatingIconView.class.getSimpleName();
@@ -86,81 +75,34 @@
public static final float SHAPE_PROGRESS_DURATION = 0.10f;
private static final int FADE_DURATION_MS = 200;
- private static final Rect sTmpRect = new Rect();
private static final RectF sTmpRectF = new RectF();
private static final Object[] sTmpObjArray = new Object[1];
- // We spring the foreground drawable relative to the icon's movement in the DragLayer.
- // We then use these two factor values to scale the movement of the fg within this view.
- private static final int FG_TRANS_X_FACTOR = 60;
- private static final int FG_TRANS_Y_FACTOR = 75;
-
- private static final FloatPropertyCompat<FloatingIconView> mFgTransYProperty
- = new FloatPropertyCompat<FloatingIconView>("FloatingViewFgTransY") {
- @Override
- public float getValue(FloatingIconView view) {
- return view.mFgTransY;
- }
-
- @Override
- public void setValue(FloatingIconView view, float transY) {
- view.mFgTransY = transY;
- view.invalidate();
- }
- };
-
- private static final FloatPropertyCompat<FloatingIconView> mFgTransXProperty
- = new FloatPropertyCompat<FloatingIconView>("FloatingViewFgTransX") {
- @Override
- public float getValue(FloatingIconView view) {
- return view.mFgTransX;
- }
-
- @Override
- public void setValue(FloatingIconView view, float transX) {
- view.mFgTransX = transX;
- view.invalidate();
- }
- };
-
private Runnable mEndRunnable;
private CancellationSignal mLoadIconSignal;
private final Launcher mLauncher;
- private final int mBlurSizeOutline;
private final boolean mIsRtl;
private boolean mIsVerticalBarLayout = false;
- private boolean mIsAdaptiveIcon = false;
private boolean mIsOpening;
private IconLoadResult mIconLoadResult;
+ private ClipIconView mClipIconView;
private @Nullable Drawable mBadge;
- private @Nullable Drawable mForeground;
- private @Nullable Drawable mBackground;
+
private float mRotation;
- private ValueAnimator mRevealAnimator;
- private final Rect mStartRevealRect = new Rect();
- private final Rect mEndRevealRect = new Rect();
- private Path mClipPath;
- private float mTaskCornerRadius;
private View mOriginalIcon;
private RectF mPositionOut;
private Runnable mOnTargetChangeRunnable;
- private final Rect mOutline = new Rect();
private final Rect mFinalDrawableBounds = new Rect();
private AnimatorSet mFadeAnimatorSet;
private ListenerView mListenerView;
- private final SpringAnimation mFgSpringY;
- private float mFgTransY;
- private final SpringAnimation mFgSpringX;
- private float mFgTransX;
-
public FloatingIconView(Context context) {
this(context, null);
}
@@ -172,19 +114,11 @@
public FloatingIconView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mLauncher = Launcher.getLauncher(context);
- mBlurSizeOutline = getResources().getDimensionPixelSize(
- R.dimen.blur_size_medium_outline);
mIsRtl = Utilities.isRtl(getResources());
mListenerView = new ListenerView(context, attrs);
-
- mFgSpringX = new SpringAnimation(this, mFgTransXProperty)
- .setSpring(new SpringForce()
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
- .setStiffness(SpringForce.STIFFNESS_LOW));
- mFgSpringY = new SpringAnimation(this, mFgTransYProperty)
- .setSpring(new SpringForce()
- .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
- .setStiffness(SpringForce.STIFFNESS_LOW));
+ mClipIconView = new ClipIconView(context, attrs);
+ addView(mClipIconView);
+ setWillNotDraw(false);
}
@Override
@@ -213,10 +147,12 @@
float cornerRadius, boolean isOpening) {
setAlpha(alpha);
- LayoutParams lp = (LayoutParams) getLayoutParams();
+ InsettableFrameLayout.LayoutParams lp =
+ (InsettableFrameLayout.LayoutParams) getLayoutParams();
+
+ DeviceProfile dp = mLauncher.getDeviceProfile();
float dX = mIsRtl
- ? rect.left
- - (mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width)
+ ? rect.left - (dp.widthPx - lp.getMarginStart() - lp.width)
: rect.left - lp.getMarginStart();
float dY = rect.top - lp.topMargin;
setTranslationX(dX);
@@ -227,69 +163,15 @@
float scaleY = rect.height() / minSize;
float scale = Math.max(1f, Math.min(scaleX, scaleY));
+ mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, isOpening, scale,
+ minSize, lp);
+
setPivotX(0);
setPivotY(0);
setScaleX(scale);
setScaleY(scale);
- // shapeRevealProgress = 1 when progress = shapeProgressStart + SHAPE_PROGRESS_DURATION
- float toMax = isOpening ? 1 / SHAPE_PROGRESS_DURATION : 1f;
- float shapeRevealProgress = Utilities.boundToRange(mapToRange(
- Math.max(shapeProgressStart, progress), shapeProgressStart, 1f, 0, toMax,
- LINEAR), 0, 1);
-
- if (mIsVerticalBarLayout) {
- mOutline.right = (int) (rect.width() / scale);
- } else {
- mOutline.bottom = (int) (rect.height() / scale);
- }
-
- mTaskCornerRadius = cornerRadius / scale;
- if (mIsAdaptiveIcon) {
- if (!isOpening && progress >= shapeProgressStart) {
- if (mRevealAnimator == null) {
- mRevealAnimator = (ValueAnimator) IconShape.getShape().createRevealAnimator(
- this, mStartRevealRect, mOutline, mTaskCornerRadius, !isOpening);
- mRevealAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRevealAnimator = null;
- }
- });
- mRevealAnimator.start();
- // We pause here so we can set the current fraction ourselves.
- mRevealAnimator.pause();
- }
- mRevealAnimator.setCurrentFraction(shapeRevealProgress);
- }
-
- float drawableScale = (mIsVerticalBarLayout ? mOutline.width() : mOutline.height())
- / minSize;
- setBackgroundDrawableBounds(drawableScale);
- if (isOpening) {
- // Center align foreground
- int height = mFinalDrawableBounds.height();
- int width = mFinalDrawableBounds.width();
- int diffY = mIsVerticalBarLayout ? 0
- : (int) (((height * drawableScale) - height) / 2);
- int diffX = mIsVerticalBarLayout ? (int) (((width * drawableScale) - width) / 2)
- : 0;
- sTmpRect.set(mFinalDrawableBounds);
- sTmpRect.offset(diffX, diffY);
- mForeground.setBounds(sTmpRect);
- } else {
- // Spring the foreground relative to the icon's movement within the DragLayer.
- int diffX = (int) (dX / mLauncher.getDeviceProfile().availableWidthPx
- * FG_TRANS_X_FACTOR);
- int diffY = (int) (dY / mLauncher.getDeviceProfile().availableHeightPx
- * FG_TRANS_Y_FACTOR);
-
- mFgSpringX.animateToFinalPosition(diffX);
- mFgSpringY.animateToFinalPosition(diffY);
- }
- }
invalidate();
- invalidateOutline();
}
@Override
@@ -301,9 +183,7 @@
mEndRunnable.run();
} else {
// End runnable also ends the reveal animator, so we manually handle it here.
- if (mRevealAnimator != null) {
- mRevealAnimator.end();
- }
+ mClipIconView.endReveal();
}
}
@@ -315,23 +195,25 @@
*/
private void matchPositionOf(Launcher launcher, View v, boolean isOpening, RectF positionOut) {
float rotation = getLocationBoundsForView(launcher, v, isOpening, positionOut);
- final LayoutParams lp = new LayoutParams(
+ final InsettableFrameLayout.LayoutParams lp = new InsettableFrameLayout.LayoutParams(
Math.round(positionOut.width()),
Math.round(positionOut.height()));
updatePosition(rotation, positionOut, lp);
setLayoutParams(lp);
+
+ mClipIconView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
}
- private void updatePosition(float rotation, RectF position, LayoutParams lp) {
+ private void updatePosition(float rotation, RectF pos, InsettableFrameLayout.LayoutParams lp) {
mRotation = rotation;
- mPositionOut.set(position);
+ mPositionOut.set(pos);
lp.ignoreInsets = true;
// Position the floating view exactly on top of the original
- lp.topMargin = Math.round(position.top);
+ lp.topMargin = Math.round(pos.top);
if (mIsRtl) {
- lp.setMarginStart(Math.round(mLauncher.getDeviceProfile().widthPx - position.right));
+ lp.setMarginStart(Math.round(mLauncher.getDeviceProfile().widthPx - pos.right));
} else {
- lp.setMarginStart(Math.round(position.left));
+ lp.setMarginStart(Math.round(pos.left));
}
// Set the properties here already to make sure they are available when running the first
// animation frame.
@@ -412,9 +294,8 @@
drawable = originalView.getBackground();
}
} else {
- boolean isFolderIcon = originalView instanceof FolderIcon;
- int width = isFolderIcon ? originalView.getWidth() : (int) pos.width();
- int height = isFolderIcon ? originalView.getHeight() : (int) pos.height();
+ int width = (int) pos.width();
+ int height = (int) pos.height();
if (supportsAdaptiveIcons) {
drawable = getFullDrawable(l, info, width, height, sTmpObjArray);
if (drawable instanceof AdaptiveIconDrawable) {
@@ -451,110 +332,42 @@
/**
* Sets the drawables of the {@param originalView} onto this view.
*
- * @param originalView The View that the FloatingIconView will replace.
* @param drawable The drawable of the original view.
* @param badge The badge of the original view.
* @param iconOffset The amount of offset needed to match this view with the original view.
*/
@UiThread
- private void setIcon(View originalView, @Nullable Drawable drawable, @Nullable Drawable badge,
- int iconOffset) {
+ private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge, int iconOffset) {
+ final InsettableFrameLayout.LayoutParams lp =
+ (InsettableFrameLayout.LayoutParams) getLayoutParams();
mBadge = badge;
-
- mIsAdaptiveIcon = drawable instanceof AdaptiveIconDrawable;
- if (mIsAdaptiveIcon) {
- boolean isFolderIcon = drawable instanceof FolderAdaptiveIcon;
-
- AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) drawable;
- Drawable background = adaptiveIcon.getBackground();
- if (background == null) {
- background = new ColorDrawable(Color.TRANSPARENT);
- }
- mBackground = background;
- Drawable foreground = adaptiveIcon.getForeground();
- if (foreground == null) {
- foreground = new ColorDrawable(Color.TRANSPARENT);
- }
- mForeground = foreground;
-
- final LayoutParams lp = (LayoutParams) getLayoutParams();
+ mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening);
+ if (drawable instanceof AdaptiveIconDrawable) {
final int originalHeight = lp.height;
final int originalWidth = lp.width;
- int blurMargin = mBlurSizeOutline / 2;
mFinalDrawableBounds.set(0, 0, originalWidth, originalHeight);
- if (!isFolderIcon) {
- mFinalDrawableBounds.inset(iconOffset - blurMargin, iconOffset - blurMargin);
- }
- mForeground.setBounds(mFinalDrawableBounds);
- mBackground.setBounds(mFinalDrawableBounds);
-
- mStartRevealRect.set(0, 0, originalWidth, originalHeight);
-
- if (mBadge != null) {
- mBadge.setBounds(mStartRevealRect);
- if (!mIsOpening && !isFolderIcon) {
- DRAWABLE_ALPHA.set(mBadge, 0);
- }
- }
-
- if (isFolderIcon) {
- ((FolderIcon) originalView).getPreviewBounds(sTmpRect);
- float bgStroke = ((FolderIcon) originalView).getBackgroundStrokeWidth();
- if (mForeground instanceof ShiftedBitmapDrawable) {
- ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mForeground;
- sbd.setShiftX(sbd.getShiftX() - sTmpRect.left - bgStroke);
- sbd.setShiftY(sbd.getShiftY() - sTmpRect.top - bgStroke);
- }
- if (mBadge instanceof ShiftedBitmapDrawable) {
- ShiftedBitmapDrawable sbd = (ShiftedBitmapDrawable) mBadge;
- sbd.setShiftX(sbd.getShiftX() - sTmpRect.left - bgStroke);
- sbd.setShiftY(sbd.getShiftY() - sTmpRect.top - bgStroke);
- }
- } else {
- Utilities.scaleRectAboutCenter(mStartRevealRect,
- IconShape.getNormalizationScale());
- }
-
float aspectRatio = mLauncher.getDeviceProfile().aspectRatio;
if (mIsVerticalBarLayout) {
lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
} else {
lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
}
+ setLayoutParams(lp);
- int left = mIsRtl
- ? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width
- : lp.leftMargin;
- layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
+ final LayoutParams clipViewLp = (LayoutParams) mClipIconView.getLayoutParams();
+ final int clipViewOgHeight = clipViewLp.height;
+ final int clipViewOgWidth = clipViewLp.width;
+ clipViewLp.width = lp.width;
+ clipViewLp.height = lp.height;
+ mClipIconView.setLayoutParams(clipViewLp);
- float scale = Math.max((float) lp.height / originalHeight,
- (float) lp.width / originalWidth);
- float bgDrawableStartScale;
- if (mIsOpening) {
- bgDrawableStartScale = 1f;
- mOutline.set(0, 0, originalWidth, originalHeight);
- } else {
- bgDrawableStartScale = scale;
- mOutline.set(0, 0, lp.width, lp.height);
+ if (mBadge != null) {
+ mBadge.setBounds(0, 0, clipViewOgWidth, clipViewOgHeight);
}
- setBackgroundDrawableBounds(bgDrawableStartScale);
- mEndRevealRect.set(0, 0, lp.width, lp.height);
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(mOutline, mTaskCornerRadius);
- }
- });
- setClipToOutline(true);
- } else {
- setBackground(drawable);
- setClipToOutline(false);
}
-
invalidate();
- invalidateOutline();
}
/**
@@ -571,7 +384,7 @@
synchronized (mIconLoadResult) {
if (mIconLoadResult.isIconLoaded) {
- setIcon(originalView, mIconLoadResult.drawable, mIconLoadResult.badge,
+ setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
mIconLoadResult.iconOffset);
hideOriginalView(originalView);
} else {
@@ -580,7 +393,7 @@
return;
}
- setIcon(originalView, mIconLoadResult.drawable, mIconLoadResult.badge,
+ setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
mIconLoadResult.iconOffset);
setVisibility(VISIBLE);
@@ -600,23 +413,12 @@
}
}
- private void setBackgroundDrawableBounds(float scale) {
- sTmpRect.set(mFinalDrawableBounds);
- Utilities.scaleRectAboutCenter(sTmpRect, scale);
- // Since the drawable is at the top of the view, we need to offset to keep it centered.
- if (mIsVerticalBarLayout) {
- sTmpRect.offsetTo((int) (mFinalDrawableBounds.left * scale), sTmpRect.top);
- } else {
- sTmpRect.offsetTo(sTmpRect.left, (int) (mFinalDrawableBounds.top * scale));
- }
- mBackground.setBounds(sTmpRect);
- }
-
@WorkerThread
@SuppressWarnings("WrongThread")
private static int getOffsetForIconBounds(Launcher l, Drawable drawable, RectF position) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O ||
- !(drawable instanceof AdaptiveIconDrawable)) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O
+ || !(drawable instanceof AdaptiveIconDrawable)
+ || (drawable instanceof FolderAdaptiveIcon)) {
return 0;
}
int blurSizeOutline =
@@ -640,29 +442,11 @@
}
@Override
- public void setClipPath(Path clipPath) {
- mClipPath = clipPath;
- invalidate();
- }
-
- @Override
- public void draw(Canvas canvas) {
+ protected void dispatchDraw(Canvas canvas) {
int count = canvas.save();
canvas.rotate(mRotation,
mFinalDrawableBounds.exactCenterX(), mFinalDrawableBounds.exactCenterY());
- if (mClipPath != null) {
- canvas.clipPath(mClipPath);
- }
- super.draw(canvas);
- if (mBackground != null) {
- mBackground.draw(canvas);
- }
- if (mForeground != null) {
- int count2 = canvas.save();
- canvas.translate(mFgTransX, mFgTransY);
- mForeground.draw(canvas);
- canvas.restoreToCount(count2);
- }
+ super.dispatchDraw(canvas);
if (mBadge != null) {
mBadge.draw(canvas);
}
@@ -706,7 +490,8 @@
float rotation = getLocationBoundsForView(mLauncher, mOriginalIcon, mIsOpening,
sTmpRectF);
if (rotation != mRotation || !sTmpRectF.equals(mPositionOut)) {
- updatePosition(rotation, sTmpRectF, (LayoutParams) getLayoutParams());
+ updatePosition(rotation, sTmpRectF,
+ (InsettableFrameLayout.LayoutParams) getLayoutParams());
if (mOnTargetChangeRunnable != null) {
mOnTargetChangeRunnable.run();
}
@@ -822,12 +607,6 @@
}
});
- if (mBadge != null) {
- ObjectAnimator badgeFade = ObjectAnimator.ofInt(mBadge, DRAWABLE_ALPHA, 255);
- badgeFade.addUpdateListener(valueAnimator -> invalidate());
- fade.play(badgeFade);
- }
-
if (originalView instanceof IconLabelDotView) {
IconLabelDotView view = (IconLabelDotView) originalView;
fade.addListener(new AnimatorListenerAdapter() {
@@ -869,21 +648,12 @@
setScaleX(1);
setScaleY(1);
setAlpha(1);
- setBackground(null);
if (mLoadIconSignal != null) {
mLoadIconSignal.cancel();
}
mLoadIconSignal = null;
mEndRunnable = null;
- mIsAdaptiveIcon = false;
- mForeground = null;
- mBackground = null;
- mClipPath = null;
mFinalDrawableBounds.setEmpty();
- if (mRevealAnimator != null) {
- mRevealAnimator.cancel();
- }
- mRevealAnimator = null;
if (mFadeAnimatorSet != null) {
mFadeAnimatorSet.cancel();
}
@@ -892,15 +662,10 @@
mListenerView.setListener(null);
mOriginalIcon = null;
mOnTargetChangeRunnable = null;
- mTaskCornerRadius = 0;
- mOutline.setEmpty();
- mFgTransY = 0;
- mFgSpringX.cancel();
- mFgTransX = 0;
- mFgSpringY.cancel();
mBadge = null;
sTmpObjArray[0] = null;
mIconLoadResult = null;
+ mClipIconView.recycle();
}
private static class IconLoadResult {
@@ -911,7 +676,7 @@
Runnable onIconLoaded;
boolean isIconLoaded;
- public IconLoadResult(ItemInfo itemInfo) {
+ IconLoadResult(ItemInfo itemInfo) {
this.itemInfo = itemInfo;
}
}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index f3fd7ca..c1310e3 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.os.Handler;
import android.os.SystemClock;
import android.util.SparseBooleanArray;
@@ -44,6 +45,7 @@
import com.android.launcher3.StylusEventHelper;
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer.TouchCompleteListener;
@@ -52,7 +54,7 @@
* {@inheritDoc}
*/
public class LauncherAppWidgetHostView extends NavigableAppWidgetHostView
- implements TouchCompleteListener, View.OnLongClickListener {
+ implements TouchCompleteListener, View.OnLongClickListener, DraggableView {
// Related to the auto-advancing of widgets
private static final long ADVANCE_INTERVAL = 20000;
@@ -412,4 +414,18 @@
}
return false;
}
+
+ @Override
+ public int getViewType() {
+ return DRAGGABLE_WIDGET;
+ }
+
+ @Override
+ public void getVisualDragBounds(Rect bounds) {
+ int x = (int) (1 - getScaleToFit()) * getMeasuredWidth() / 2;
+ int y = (int) (1 - getScaleToFit()) * getMeasuredWidth() / 2;
+ int width = (int) getScaleToFit() * getMeasuredWidth();
+ int height = (int) getScaleToFit() * getMeasuredHeight();
+ bounds.set(x, y , x + width, y + height);
+ }
}
diff --git a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
index 68b1595..104ad77 100644
--- a/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/NavigableAppWidgetHostView.java
@@ -24,12 +24,15 @@
import android.view.ViewDebug;
import android.view.ViewGroup;
+import com.android.launcher3.dragndrop.DraggableView;
+
import java.util.ArrayList;
/**
* Extension of AppWidgetHostView with support for controlled keyboard navigation.
*/
-public abstract class NavigableAppWidgetHostView extends AppWidgetHostView {
+public abstract class NavigableAppWidgetHostView extends AppWidgetHostView
+ implements DraggableView {
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mChildrenFocused;
@@ -133,4 +136,14 @@
// The host view's background changes when selected, to indicate the focus is inside.
setSelected(childIsFocused);
}
+
+ @Override
+ public int getViewType() {
+ return DRAGGABLE_WIDGET;
+ }
+
+ @Override
+ public void getVisualDragBounds(Rect bounds) {
+ bounds.set(0, 0 , getMeasuredWidth(), getMeasuredHeight());
+ }
}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 662e627..3c11274 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -32,6 +32,7 @@
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.dragndrop.LivePreviewWidgetCell;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.icons.LauncherIcons;
@@ -79,6 +80,8 @@
mEstimatedCellSize = launcher.getWorkspace().estimateItemSize(mAddInfo);
+ DraggableView draggableView;
+
if (mAddInfo instanceof PendingAddWidgetInfo) {
PendingAddWidgetInfo createWidgetInfo = (PendingAddWidgetInfo) mAddInfo;
@@ -110,6 +113,7 @@
dragOffset = null;
dragRegion = null;
+ draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_WIDGET);
} else {
PendingAddShortcutInfo createShortcutInfo = (PendingAddShortcutInfo) mAddInfo;
Drawable icon = createShortcutInfo.activityInfo.getFullResIcon(app.getIconCache());
@@ -136,6 +140,7 @@
dragRegion.top = (mEstimatedCellSize[1]
- iconSize - dp.iconTextSizePx - dp.iconDrawablePaddingPx) / 2;
dragRegion.bottom = dragRegion.top + iconSize;
+ draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
}
// Since we are not going through the workspace for starting the drag, set drag related
@@ -148,8 +153,8 @@
+ (int) ((scale * preview.getHeight() - preview.getHeight()) / 2);
// Start the drag
- launcher.getDragController().startDrag(preview, dragLayerX, dragLayerY, source, mAddInfo,
- dragOffset, dragRegion, scale, scale, options);
+ launcher.getDragController().startDrag(preview, draggableView, dragLayerX, dragLayerY,
+ source, mAddInfo, dragOffset, dragRegion, scale, scale, options);
}
@Override
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index f5dd995..7cd656e 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -18,7 +18,6 @@
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
-import static com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -57,6 +56,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.testing.TestProtocol;
@@ -220,13 +220,19 @@
@Before
public void setUp() throws Exception {
+ Log.d(TAG, "Before disabling battery defender");
+ mDevice.executeShellCommand("setprop vendor.battery.defender.disable 1");
+ Log.d(TAG, "Before enabling stay awake");
mDevice.executeShellCommand("settings put global stay_on_while_plugged_in 3");
- if (hasSystemUiObject("keyguard_status_view")) {
+ for (int i = 0; i < 10 && hasSystemUiObject("keyguard_status_view"); ++i) {
Log.d(TAG, "Before unlocking the phone");
mDevice.executeShellCommand("input keyevent 82");
- } else {
- Log.d(TAG, "Phone isn't locked");
+ mDevice.waitForIdle();
}
+ Assert.assertTrue("Keyguard still visible",
+ mDevice.wait(
+ Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000));
+ Log.d(TAG, "Keyguard is not visible");
final String launcherPackageName = mDevice.getLauncherPackageName();
try {
@@ -288,7 +294,8 @@
protected void resetLoaderState() {
try {
mMainThreadExecutor.execute(
- () -> LauncherAppState.getInstance(mTargetContext).getModel().forceReload());
+ () -> LauncherAppState.getInstance(
+ mTargetContext).getModel().forceReload());
} catch (Throwable t) {
throw new IllegalArgumentException(t);
}
@@ -302,7 +309,8 @@
ContentResolver resolver = mTargetContext.getContentResolver();
int screenId = FIRST_SCREEN_ID;
// Update the screen id counter for the provider.
- LauncherSettings.Settings.call(resolver, LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
+ LauncherSettings.Settings.call(resolver,
+ LauncherSettings.Settings.METHOD_NEW_SCREEN_ID);
if (screenId > FIRST_SCREEN_ID) {
screenId = FIRST_SCREEN_ID;
@@ -316,7 +324,8 @@
item.screenId = screenId;
item.onAddToDatabase(writer);
writer.put(LauncherSettings.Favorites._ID, item.id);
- resolver.insert(LauncherSettings.Favorites.CONTENT_URI, writer.getValues(mTargetContext));
+ resolver.insert(LauncherSettings.Favorites.CONTENT_URI,
+ writer.getValues(mTargetContext));
resetLoaderState();
// Launch the home activity
@@ -347,7 +356,8 @@
});
}
- // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call expecting
+ // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call
+ // expecting
// the results of that gesture because the wait can hide flakeness.
protected void waitForState(String message, Supplier<LauncherState> state) {
waitForLauncherCondition(message,
@@ -360,7 +370,8 @@
// Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide
// flakiness.
- protected void waitForLauncherCondition(String message, Function<Launcher, Boolean> condition) {
+ protected void waitForLauncherCondition(String
+ message, Function<Launcher, Boolean> condition) {
waitForLauncherCondition(message, condition, DEFAULT_ACTIVITY_TIMEOUT);
}
@@ -436,7 +447,8 @@
public Intent blockingGetExtraIntent() throws InterruptedException {
Intent intent = blockingGetIntent();
- return intent == null ? null : (Intent) intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ return intent == null ? null : (Intent) intent.getParcelableExtra(
+ Intent.EXTRA_INTENT);
}
}
@@ -463,7 +475,8 @@
if (newTask) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
} else {
- intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
}
getInstrumentation().getTargetContext().startActivity(intent);
assertTrue("App didn't start: " + selector,
@@ -500,7 +513,8 @@
protected boolean isInState(Supplier<LauncherState> state) {
if (!TestHelpers.isInLauncherProcess()) return true;
- return getFromLauncher(launcher -> launcher.getStateManager().getState() == state.get());
+ return getFromLauncher(
+ launcher -> launcher.getStateManager().getState() == state.get());
}
protected int getAllAppsScroll(Launcher launcher) {
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 7e80e5d..8d571ff 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -16,6 +16,7 @@
package com.android.launcher3.ui;
import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -158,9 +159,11 @@
// dismiss personal edu
mDevice.pressHome();
+ waitForState("Launcher did not go home", () -> NORMAL);
// open work tab
executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
+ waitForState("Launcher did not switch to all apps", () -> ALL_APPS);
executeOnLauncher(launcher -> {
AllAppsPagedView pagedView = (AllAppsPagedView) launcher.getAppsView().getContentView();
pagedView.setCurrentPage(WORK_PAGE);