From 1e2d004dd591b0d4c41f23ca97455f2e5f805252 Mon Sep 17 00:00:00 2001 From: Samuel Fufa Date: Mon, 18 Nov 2019 17:12:46 -0800 Subject: [PATCH] Hybrid hotseat predicted icon visuals Bug:142753423 Test: Manual Change-Id: I6f056aaec905c8ca357b7cf78a657cdaac84e2f1 --- .../res/layout/predicted_app_icon.xml | 17 ++ .../HotseatPredictionController.java | 122 +++++++----- .../uioverrides/PredictedAppIcon.java | 188 ++++++++++++++++++ src/com/android/launcher3/CellLayout.java | 80 +++++--- .../launcher3/folder/PreviewBackground.java | 37 +++- 5 files changed, 357 insertions(+), 87 deletions(-) create mode 100644 quickstep/recents_ui_overrides/res/layout/predicted_app_icon.xml create mode 100644 quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java diff --git a/quickstep/recents_ui_overrides/res/layout/predicted_app_icon.xml b/quickstep/recents_ui_overrides/res/layout/predicted_app_icon.xml new file mode 100644 index 0000000000..70a765a562 --- /dev/null +++ b/quickstep/recents_ui_overrides/res/layout/predicted_app_icon.xml @@ -0,0 +1,17 @@ + + + + diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java index fe9fd604e2..17a3d9185a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java @@ -18,6 +18,7 @@ package com.android.launcher3; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import android.animation.Animator; +import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.prediction.AppPredictionContext; import android.app.prediction.AppPredictionManager; @@ -40,10 +41,9 @@ import com.android.launcher3.appprediction.DynamicItemCache; import com.android.launcher3.dragndrop.DragController; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.icons.IconCache; -import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.shortcuts.ShortcutKey; -import com.android.launcher3.touch.ItemLongClickListener; +import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.ComponentKey; @@ -81,12 +81,14 @@ public class HotseatPredictionController implements DragController.DragListener, private AppPredictor mAppPredictor; private AllAppsStore mAllAppsStore; + private List mOutlineDrawings = new ArrayList<>(); + public HotseatPredictionController(Launcher launcher) { mLauncher = launcher; mHotseat = launcher.getHotseat(); mAllAppsStore = mLauncher.getAppsView().getAppsStore(); mAllAppsStore.addUpdateListener(this); - mDynamicItemCache = new DynamicItemCache(mLauncher, () -> fillGapsWithPrediction(false)); + mDynamicItemCache = new DynamicItemCache(mLauncher, this::fillGapsWithPrediction); mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons; launcher.getDeviceProfile().inv.addOnChangeListener(this); mHotseat.addOnAttachStateChangeListener(this); @@ -102,16 +104,17 @@ public class HotseatPredictionController implements DragController.DragListener, mLauncher.getDragController().removeDragListener(this); } - /** - * Fills gaps in the hotseat with predictions - */ - public void fillGapsWithPrediction(boolean animate) { + private void fillGapsWithPrediction() { + fillGapsWithPrediction(false, null); + } + + private void fillGapsWithPrediction(boolean animate, Runnable callback) { if (mDragObject != null) { return; } List predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers); int predictionIndex = 0; - ArrayList newItemsToAdd = new ArrayList<>(); + ArrayList newItems = new ArrayList<>(); for (int rank = 0; rank < mHotSeatItemsCount; rank++) { View child = mHotseat.getChildAt( mHotseat.getCellXFromOrder(rank), @@ -130,21 +133,37 @@ public class HotseatPredictionController implements DragController.DragListener, WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++); if (isPredictedIcon(child)) { - BubbleTextView icon = (BubbleTextView) child; + PredictedAppIcon icon = (PredictedAppIcon) child; icon.applyFromWorkspaceItem(predictedItem); + icon.finishBinding(); } else { - newItemsToAdd.add(predictedItem); + newItems.add(predictedItem); } preparePredictionInfo(predictedItem, rank); } - mLauncher.bindItems(newItemsToAdd, animate); - for (BubbleTextView icon : getPredictedIcons()) { - icon.verifyHighRes(); - icon.setOnLongClickListener((v) -> { - PopupContainerWithArrow.showForIcon((BubbleTextView) v); - return true; + bindItems(newItems, animate, callback); + } + + private void bindItems(List itemsToAdd, boolean animate, Runnable callback) { + AnimatorSet animationSet = new AnimatorSet(); + for (WorkspaceItemInfo item : itemsToAdd) { + PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item); + mLauncher.getWorkspace().addInScreenFromBind(icon, item); + icon.finishBinding(); + if (animate) { + animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1)); + } + } + if (animate) { + animationSet.addListener(new AnimationSuccessListener() { + @Override + public void onAnimationSuccess(Animator animator) { + if (callback != null) callback.run(); + } }); - icon.setBackgroundResource(R.drawable.predicted_icon_background); + animationSet.start(); + } else { + if (callback != null) callback.run(); } } @@ -179,6 +198,7 @@ public class HotseatPredictionController implements DragController.DragListener, .build()); mAppPredictor.registerPredictionUpdates(mLauncher.getMainExecutor(), this::setPredictedApps); + mAppPredictor.requestPredictionUpdate(); } @@ -210,7 +230,7 @@ public class HotseatPredictionController implements DragController.DragListener, mComponentKeyMappers.add(new ComponentKeyMapper(key, mDynamicItemCache)); } updateDependencies(); - fillGapsWithPrediction(false); + fillGapsWithPrediction(); } private void updateDependencies() { @@ -219,7 +239,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private void pinPrediction(ItemInfo info) { - BubbleTextView icon = (BubbleTextView) mHotseat.getChildAt( + PredictedAppIcon icon = (PredictedAppIcon) mHotseat.getChildAt( mHotseat.getCellXFromOrder(info.rank), mHotseat.getCellYFromOrder(info.rank)); if (icon == null) { @@ -230,9 +250,7 @@ public class HotseatPredictionController implements DragController.DragListener, LauncherSettings.Favorites.CONTAINER_HOTSEAT, workspaceItemInfo.screenId, workspaceItemInfo.cellX, workspaceItemInfo.cellY); ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 1, 0.8f, 1).start(); - icon.reset(); - icon.applyFromWorkspaceItem(workspaceItemInfo); - icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE); + icon.pin(workspaceItemInfo); AppTarget appTarget = getAppTargetFromItemInfo(workspaceItemInfo); notifyItemAction(appTarget, AppTargetEvent.ACTION_PIN); } @@ -265,37 +283,35 @@ public class HotseatPredictionController implements DragController.DragListener, return predictedApps; } - private List getPredictedIcons() { - List icons = new ArrayList<>(); + private List getPredictedIcons() { + List icons = new ArrayList<>(); ViewGroup vg = mHotseat.getShortcutsAndWidgets(); for (int i = 0; i < vg.getChildCount(); i++) { View child = vg.getChildAt(i); if (isPredictedIcon(child)) { - icons.add((BubbleTextView) child); + icons.add((PredictedAppIcon) child); } } return icons; } - private void removePredictedApps(boolean animate) { - for (BubbleTextView icon : getPredictedIcons()) { - if (animate) { - icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() { - @Override - public void onAnimationSuccess(Animator animator) { - if (icon.getParent() != null) { - mHotseat.removeView(icon); - } + private void removePredictedApps(List outlines) { + for (PredictedAppIcon icon : getPredictedIcons()) { + int rank = ((WorkspaceItemInfo) icon.getTag()).rank; + outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing( + mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon)); + icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() { + @Override + public void onAnimationSuccess(Animator animator) { + if (icon.getParent() != null) { + mHotseat.removeView(icon); } - }); - } else { - if (icon.getParent() != null) { - mHotseat.removeView(icon); } - } + }); } } + private void notifyItemAction(AppTarget target, int action) { if (mAppPredictor != null) { mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target, action).build()); @@ -304,8 +320,13 @@ public class HotseatPredictionController implements DragController.DragListener, @Override public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { - removePredictedApps(true); + removePredictedApps(mOutlineDrawings); mDragObject = dragObject; + if (mOutlineDrawings.isEmpty()) return; + for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { + mHotseat.addDelegatedCellDrawing(outlineDrawing); + } + mHotseat.invalidate(); } @Override @@ -322,7 +343,14 @@ public class HotseatPredictionController implements DragController.DragListener, } } mDragObject = null; - fillGapsWithPrediction(true); + fillGapsWithPrediction(true, () -> { + if (mOutlineDrawings.isEmpty()) return; + for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) { + mHotseat.removeDelegatedCellDrawing(outlineDrawing); + } + mHotseat.invalidate(); + mOutlineDrawings.clear(); + }); } @Nullable @@ -351,8 +379,7 @@ public class HotseatPredictionController implements DragController.DragListener, @Override public void onAppsUpdated() { - updateDependencies(); - fillGapsWithPrediction(false); + fillGapsWithPrediction(); } @Override @@ -375,7 +402,7 @@ public class HotseatPredictionController implements DragController.DragListener, } private static boolean isPredictedIcon(View view) { - return view instanceof BubbleTextView && view.getTag() instanceof WorkspaceItemInfo + return view instanceof PredictedAppIcon && view.getTag() instanceof WorkspaceItemInfo && ((WorkspaceItemInfo) view.getTag()).container == LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; } @@ -396,9 +423,8 @@ public class HotseatPredictionController implements DragController.DragListener, private static AppTarget getAppTargetFromItemInfo(ItemInfo info) { if (info.getTargetComponent() == null) return null; - return new AppTarget.Builder( - new AppTargetId("app:" + info.getTargetComponent().getPackageName()), - info.getTargetComponent().getPackageName(), info.user).setClassName( - info.getTargetComponent().getClassName()).build(); + ComponentName cn = info.getTargetComponent(); + return new AppTarget.Builder(new AppTargetId("app:" + cn.getPackageName()), + cn.getPackageName(), info.user).setClassName(cn.getClassName()).build(); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java new file mode 100644 index 0000000000..e41c75a2c2 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2019 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.uioverrides; + +import static com.android.launcher3.graphics.IconShape.getShape; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.DashPathEffect; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import androidx.core.graphics.ColorUtils; + +import com.android.launcher3.BubbleTextView; +import com.android.launcher3.CellLayout; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; +import com.android.launcher3.R; +import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.graphics.IconPalette; +import com.android.launcher3.icons.IconNormalizer; +import com.android.launcher3.popup.PopupContainerWithArrow; +import com.android.launcher3.touch.ItemClickHandler; +import com.android.launcher3.touch.ItemLongClickListener; + +/** + * A BubbleTextView with a ring around it's drawable + */ +public class PredictedAppIcon extends BubbleTextView { + + private static final float RING_EFFECT_RATIO = 0.12f; + + private DeviceProfile mDeviceProfile; + private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + private boolean mIsPinned = false; + private int mNormalizedIconRadius; + + + public PredictedAppIcon(Context context) { + this(context, null, 0); + } + + public PredictedAppIcon(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public PredictedAppIcon(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + mDeviceProfile = Launcher.getLauncher(context).getDeviceProfile(); + mNormalizedIconRadius = IconNormalizer.getNormalizedCircleSize(getIconSize()) / 2; + setOnClickListener(ItemClickHandler.INSTANCE); + setOnFocusChangeListener(Launcher.getLauncher(context).mFocusHandler); + } + + @Override + public void onDraw(Canvas canvas) { + int count = canvas.save(); + if (!mIsPinned) { + drawEffect(canvas); + canvas.translate(getWidth() * RING_EFFECT_RATIO, getHeight() * RING_EFFECT_RATIO); + canvas.scale(1 - 2 * RING_EFFECT_RATIO, 1 - 2 * RING_EFFECT_RATIO); + } + super.onDraw(canvas); + canvas.restoreToCount(count); + } + + @Override + public void applyFromWorkspaceItem(WorkspaceItemInfo info) { + super.applyFromWorkspaceItem(info); + int color = IconPalette.getMutedColor(info.bitmap.color, 0.54f); + mIconRingPaint.setColor(ColorUtils.setAlphaComponent(color, 200)); + } + + /** + * Removes prediction ring from app icon + */ + public void pin(WorkspaceItemInfo info) { + if (mIsPinned) return; + applyFromWorkspaceItem(info); + setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE); + mIsPinned = true; + invalidate(); + } + + /** + * prepares prediction icon for usage after bind + */ + public void finishBinding() { + setOnLongClickListener((v) -> { + PopupContainerWithArrow.showForIcon((BubbleTextView) v); + if (getParent() != null) { + getParent().requestDisallowInterceptTouchEvent(true); + } + return true; + }); + setTextVisibility(false); + verifyHighRes(); + } + + @Override + public void getIconBounds(Rect outBounds) { + super.getIconBounds(outBounds); + if (!mIsPinned) { + int predictionInset = (int) (getIconSize() * RING_EFFECT_RATIO); + outBounds.inset(predictionInset, predictionInset); + } + } + + private int getOutlineOffsetX() { + return (getMeasuredWidth() / 2) - mNormalizedIconRadius; + } + + private int getOutlineOffsetY() { + return getPaddingTop() + mDeviceProfile.folderIconOffsetYPx; + } + + private void drawEffect(Canvas canvas) { + getShape().drawShape(canvas, getOutlineOffsetX(), getOutlineOffsetY(), + mNormalizedIconRadius, mIconRingPaint); + } + + /** + * Creates and returns a new instance of PredictedAppIcon from WorkspaceItemInfo + */ + public static PredictedAppIcon createIcon(ViewGroup parent, WorkspaceItemInfo info) { + PredictedAppIcon icon = (PredictedAppIcon) LayoutInflater.from(parent.getContext()) + .inflate(R.layout.predicted_app_icon, parent, false); + icon.applyFromWorkspaceItem(info); + return icon; + } + + /** + * Draws Predicted Icon outline on cell layout + */ + public static class PredictedIconOutlineDrawing extends CellLayout.DelegatedCellDrawing { + + private int mOffsetX; + private int mOffsetY; + private int mIconRadius; + private Paint mOutlinePaint = new Paint(Paint.ANTI_ALIAS_FLAG); + + public PredictedIconOutlineDrawing(int cellX, int cellY, PredictedAppIcon icon) { + mDelegateCellX = cellX; + mDelegateCellY = cellY; + mOffsetX = icon.getOutlineOffsetX(); + mOffsetY = icon.getOutlineOffsetY(); + mIconRadius = icon.mNormalizedIconRadius; + mOutlinePaint.setStyle(Paint.Style.STROKE); + mOutlinePaint.setStrokeWidth(5); + mOutlinePaint.setPathEffect(new DashPathEffect(new float[]{15, 15}, 0)); + mOutlinePaint.setColor(Color.argb(100, 245, 245, 245)); + } + + /** + * Draws predicted app icon outline under CellLayout + */ + @Override + public void drawUnderItem(Canvas canvas) { + getShape().drawShape(canvas, mOffsetX, mOffsetY, mIconRadius, mOutlinePaint); + } + + /** + * Draws PredictedAppIcon outline over CellLayout + */ + @Override + public void drawOverItem(Canvas canvas) { + // Does nothing + } + } +} diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 976ccd52ed..89bec98bd2 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -110,7 +110,7 @@ public class CellLayout extends ViewGroup implements Transposable { private OnTouchListener mInterceptTouchListener; - private final ArrayList mFolderBackgrounds = new ArrayList<>(); + private final ArrayList mDelegatedCellDrawings = new ArrayList<>(); final PreviewBackground mFolderLeaveBehind = new PreviewBackground(); private static final int[] BACKGROUND_STATE_ACTIVE = new int[] { android.R.attr.state_active }; @@ -219,8 +219,8 @@ public class CellLayout extends ViewGroup implements Transposable { mPreviousReorderDirection[0] = INVALID_DIRECTION; mPreviousReorderDirection[1] = INVALID_DIRECTION; - mFolderLeaveBehind.delegateCellX = -1; - mFolderLeaveBehind.delegateCellY = -1; + mFolderLeaveBehind.mDelegateCellX = -1; + mFolderLeaveBehind.mDelegateCellY = -1; setAlwaysDrawnWithCacheEnabled(false); final Resources res = getResources(); @@ -466,21 +466,18 @@ public class CellLayout extends ViewGroup implements Transposable { } } - for (int i = 0; i < mFolderBackgrounds.size(); i++) { - PreviewBackground bg = mFolderBackgrounds.get(i); - cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation); + for (int i = 0; i < mDelegatedCellDrawings.size(); i++) { + DelegatedCellDrawing cellDrawing = mDelegatedCellDrawings.get(i); + cellToPoint(cellDrawing.mDelegateCellX, cellDrawing.mDelegateCellY, mTempLocation); canvas.save(); canvas.translate(mTempLocation[0], mTempLocation[1]); - bg.drawBackground(canvas); - if (!bg.isClipping) { - bg.drawBackgroundStroke(canvas); - } + cellDrawing.drawUnderItem(canvas); canvas.restore(); } - if (mFolderLeaveBehind.delegateCellX >= 0 && mFolderLeaveBehind.delegateCellY >= 0) { - cellToPoint(mFolderLeaveBehind.delegateCellX, - mFolderLeaveBehind.delegateCellY, mTempLocation); + if (mFolderLeaveBehind.mDelegateCellX >= 0 && mFolderLeaveBehind.mDelegateCellY >= 0) { + cellToPoint(mFolderLeaveBehind.mDelegateCellX, + mFolderLeaveBehind.mDelegateCellY, mTempLocation); canvas.save(); canvas.translate(mTempLocation[0], mTempLocation[1]); mFolderLeaveBehind.drawLeaveBehind(canvas); @@ -492,23 +489,28 @@ public class CellLayout extends ViewGroup implements Transposable { protected void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); - for (int i = 0; i < mFolderBackgrounds.size(); i++) { - PreviewBackground bg = mFolderBackgrounds.get(i); - if (bg.isClipping) { - cellToPoint(bg.delegateCellX, bg.delegateCellY, mTempLocation); - canvas.save(); - canvas.translate(mTempLocation[0], mTempLocation[1]); - bg.drawBackgroundStroke(canvas); - canvas.restore(); - } + for (int i = 0; i < mDelegatedCellDrawings.size(); i++) { + DelegatedCellDrawing bg = mDelegatedCellDrawings.get(i); + cellToPoint(bg.mDelegateCellX, bg.mDelegateCellY, mTempLocation); + canvas.save(); + canvas.translate(mTempLocation[0], mTempLocation[1]); + bg.drawOverItem(canvas); + canvas.restore(); } } - public void addFolderBackground(PreviewBackground bg) { - mFolderBackgrounds.add(bg); + /** + * Add Delegated cell drawing + */ + public void addDelegatedCellDrawing(DelegatedCellDrawing bg) { + mDelegatedCellDrawings.add(bg); } - public void removeFolderBackground(PreviewBackground bg) { - mFolderBackgrounds.remove(bg); + + /** + * Remove item from DelegatedCellDrawings + */ + public void removeDelegatedCellDrawing(DelegatedCellDrawing bg) { + mDelegatedCellDrawings.remove(bg); } public void setFolderLeaveBehindCell(int x, int y) { @@ -516,14 +518,14 @@ public class CellLayout extends ViewGroup implements Transposable { mFolderLeaveBehind.setup(getContext(), mActivity, null, child.getMeasuredWidth(), child.getPaddingTop()); - mFolderLeaveBehind.delegateCellX = x; - mFolderLeaveBehind.delegateCellY = y; + mFolderLeaveBehind.mDelegateCellX = x; + mFolderLeaveBehind.mDelegateCellY = y; invalidate(); } public void clearFolderLeaveBehind() { - mFolderLeaveBehind.delegateCellX = -1; - mFolderLeaveBehind.delegateCellY = -1; + mFolderLeaveBehind.mDelegateCellX = -1; + mFolderLeaveBehind.mDelegateCellY = -1; invalidate(); } @@ -2743,6 +2745,24 @@ public class CellLayout extends ViewGroup implements Transposable { } } + /** + * A Delegated cell Drawing for drawing on CellLayout + */ + public abstract static class DelegatedCellDrawing { + public int mDelegateCellX; + public int mDelegateCellY; + + /** + * Draw under CellLayout + */ + public abstract void drawUnderItem(Canvas canvas); + + /** + * Draw over CellLayout + */ + public abstract void drawOverItem(Canvas canvas); + } + /** * Returns whether an item can be placed in this CellLayout (after rearranging and/or resizing * if necessary). diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java index b2c0ca7213..2d177d2f2d 100644 --- a/src/com/android/launcher3/folder/PreviewBackground.java +++ b/src/com/android/launcher3/folder/PreviewBackground.java @@ -48,7 +48,7 @@ import com.android.launcher3.views.ActivityContext; * This object represents a FolderIcon preview background. It stores drawing / measurement * information, handles drawing, and animation (accept state <--> rest state). */ -public class PreviewBackground { +public class PreviewBackground extends CellLayout.DelegatedCellDrawing { private static final int CONSUMPTION_ANIMATION_DURATION = 100; @@ -76,8 +76,6 @@ public class PreviewBackground { int basePreviewOffsetY; private CellLayout mDrawingDelegate; - public int delegateCellX; - public int delegateCellY; // When the PreviewBackground is drawn under an icon (for creating a folder) the border // should not occlude the icon @@ -124,6 +122,27 @@ public class PreviewBackground { } }; + /** + * Draws folder background under cell layout + */ + @Override + public void drawUnderItem(Canvas canvas) { + drawBackground(canvas); + if (!isClipping) { + drawBackgroundStroke(canvas); + } + } + + /** + * Draws folder background on cell layout + */ + @Override + public void drawOverItem(Canvas canvas) { + if (isClipping) { + drawBackgroundStroke(canvas); + } + } + public void setup(Context context, ActivityContext activity, View invalidateDelegate, int availableSpaceX, int topPadding) { mInvalidateDelegate = invalidateDelegate; @@ -317,19 +336,19 @@ public class PreviewBackground { private void delegateDrawing(CellLayout delegate, int cellX, int cellY) { if (mDrawingDelegate != delegate) { - delegate.addFolderBackground(this); + delegate.addDelegatedCellDrawing(this); } mDrawingDelegate = delegate; - delegateCellX = cellX; - delegateCellY = cellY; + mDelegateCellX = cellX; + mDelegateCellY = cellY; invalidate(); } private void clearDrawingDelegate() { if (mDrawingDelegate != null) { - mDrawingDelegate.removeFolderBackground(this); + mDrawingDelegate.removeDelegatedCellDrawing(this); } mDrawingDelegate = null; @@ -395,8 +414,8 @@ public class PreviewBackground { // is saved and restored at the beginning of the animation, since cancelling the // existing animation can clear the delgate. CellLayout cl = mDrawingDelegate; - int cellX = delegateCellX; - int cellY = delegateCellY; + int cellX = mDelegateCellX; + int cellY = mDelegateCellY; animateScale(1f, 1f, () -> delegateDrawing(cl, cellX, cellY), this::clearDrawingDelegate); }