Let DragView use ActivityContext instead of Launcher
- Make DragView abstract and extended by LauncherDragView for the explicitly Launcher-specific parts.
- Some other methods like Utilities.getFullDrawable() now accept (Activity)Context rather than Launcher.
Test: Compiles and runs, manual drag and drop
Bug: 182981908
Change-Id: I77b7a2e48ce864dd711c3232217fdba4d60c546f
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4a7937b..892fb6d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1289,7 +1289,8 @@
}
}
- public FolderIcon findFolderIcon(final int folderIconId) {
+ @Override
+ public @Nullable FolderIcon findFolderIcon(final int folderIconId) {
return (FolderIcon) mWorkspace.getHomescreenIconByItemId(folderIconId);
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index cb9e1f3..becbb27 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -85,6 +85,7 @@
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -651,25 +652,26 @@
* @param outObj this is set to the internal data associated with {@param info},
* eg {@link LauncherActivityInfo} or {@link ShortcutInfo}.
*/
- public static Drawable getFullDrawable(Launcher launcher, ItemInfo info, int width, int height,
+ public static Drawable getFullDrawable(Context context, ItemInfo info, int width, int height,
Object[] outObj) {
- Drawable icon = loadFullDrawableWithoutTheme(launcher, info, width, height, outObj);
+ Drawable icon = loadFullDrawableWithoutTheme(context, info, width, height, outObj);
if (icon instanceof BitmapInfo.Extender) {
- icon = ((BitmapInfo.Extender) icon).getThemedDrawable(launcher);
+ icon = ((BitmapInfo.Extender) icon).getThemedDrawable(context);
}
return icon;
}
- private static Drawable loadFullDrawableWithoutTheme(Launcher launcher, ItemInfo info,
+ private static Drawable loadFullDrawableWithoutTheme(Context context, ItemInfo info,
int width, int height, Object[] outObj) {
- LauncherAppState appState = LauncherAppState.getInstance(launcher);
+ ActivityContext activity = ActivityContext.lookupContext(context);
+ LauncherAppState appState = LauncherAppState.getInstance(context);
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
- LauncherActivityInfo activityInfo = launcher.getSystemService(LauncherApps.class)
+ LauncherActivityInfo activityInfo = context.getSystemService(LauncherApps.class)
.resolveActivity(info.getIntent(), info.user);
outObj[0] = activityInfo;
- return activityInfo == null ? null : LauncherAppState.getInstance(launcher)
+ return activityInfo == null ? null : LauncherAppState.getInstance(context)
.getIconProvider().getIcon(
- activityInfo, launcher.getDeviceProfile().inv.fillResIconDpi);
+ activityInfo, activity.getDeviceProfile().inv.fillResIconDpi);
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
if (info instanceof PendingAddShortcutInfo) {
ShortcutConfigActivityInfo activityInfo =
@@ -678,18 +680,18 @@
return activityInfo.getFullResIcon(appState.getIconCache());
}
List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
- .buildRequest(launcher)
+ .buildRequest(context)
.query(ShortcutRequest.ALL);
if (si.isEmpty()) {
return null;
} else {
outObj[0] = si.get(0);
- return ShortcutCachingLogic.getIcon(launcher, si.get(0),
+ return ShortcutCachingLogic.getIcon(context, si.get(0),
appState.getInvariantDeviceProfile().fillResIconDpi);
}
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
FolderAdaptiveIcon icon = FolderAdaptiveIcon.createFolderAdaptiveIcon(
- launcher, info.id, new Point(width, height));
+ activity, info.id, new Point(width, height));
if (icon == null) {
return null;
}
@@ -707,8 +709,8 @@
* badge. When dragged from workspace or folder, it may contain app AND/OR work profile badge
**/
@TargetApi(Build.VERSION_CODES.O)
- public static Drawable getBadge(Launcher launcher, ItemInfo info, Object obj) {
- LauncherAppState appState = LauncherAppState.getInstance(launcher);
+ public static Drawable getBadge(Context context, ItemInfo info, Object obj) {
+ LauncherAppState appState = LauncherAppState.getInstance(context);
int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize;
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
boolean iconBadged = (info instanceof ItemInfoWithIcon)
@@ -728,7 +730,7 @@
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
return ((FolderAdaptiveIcon) obj).getBadge();
} else {
- return launcher.getPackageManager()
+ return context.getPackageManager()
.getUserBadgedIcon(new FixedSizeEmptyDrawable(iconSize), info.user);
}
}
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 1664980..fb1a6be 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -53,22 +53,19 @@
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.RunnableList;
-import com.android.launcher3.util.Thunk;
+import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.BaseDragLayer;
/** A custom view for rendering an icon, folder, shortcut or widget during drag-n-drop. */
-public class DragView extends FrameLayout implements StateListener<LauncherState> {
+public abstract class DragView<T extends Context & ActivityContext> extends FrameLayout {
public static final int VIEW_ZOOM_DURATION = 150;
@@ -81,19 +78,18 @@
private final int mHeight;
private final int mBlurSizeOutline;
- private final int mRegistrationX;
- private final int mRegistrationY;
+ protected final int mRegistrationX;
+ protected final int mRegistrationY;
private final float mInitialScale;
- private final float mScaleOnDrop;
- private final int[] mTempLoc = new int[2];
+ protected final float mScaleOnDrop;
+ protected final int[] mTempLoc = new int[2];
private final RunnableList mOnDragStartCallback = new RunnableList();
private Point mDragVisualizeOffset = null;
private Rect mDragRegion = null;
- private final Launcher mLauncher;
- private final DragLayer mDragLayer;
- @Thunk final DragController mDragController;
+ protected final T mActivity;
+ private final BaseDragLayer<T> mDragLayer;
private boolean mHasDrawn = false;
final ValueAnimator mAnim;
@@ -109,7 +105,7 @@
private Path mScaledMaskPath;
private Drawable mBadge;
- public DragView(Launcher launcher, Drawable drawable, int registrationX,
+ public DragView(T launcher, Drawable drawable, int registrationX,
int registrationY, final float initialScale, final float scaleOnDrop,
final float finalScaleDps) {
this(launcher, getViewFromDrawable(launcher, drawable),
@@ -122,7 +118,7 @@
* <p>
* The registration point is the point inside our view that the touch events should
* be centered upon.
- * @param launcher The Launcher instance
+ * @param activity The Launcher instance/ActivityContext this DragView is in.
* @param content the view content that is attached to the drag view.
* @param width the width of the dragView
* @param height the height of the dragView
@@ -132,13 +128,12 @@
* @param scaleOnDrop the scale used in the drop animation.
* @param finalScaleDps the scale used in the zoom out animation when the drag view is shown.
*/
- public DragView(Launcher launcher, View content, int width, int height, int registrationX,
+ public DragView(T activity, View content, int width, int height, int registrationX,
int registrationY, final float initialScale, final float scaleOnDrop,
final float finalScaleDps) {
- super(launcher);
- mLauncher = launcher;
- mDragLayer = launcher.getDragLayer();
- mDragController = launcher.getDragController();
+ super(activity);
+ mActivity = activity;
+ mDragLayer = activity.getDragLayer();
mContent = content;
mWidth = width;
@@ -187,24 +182,6 @@
setWillNotDraw(false);
}
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- mLauncher.getStateManager().addStateListener(this);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- mLauncher.getStateManager().removeStateListener(this);
- }
-
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- setVisibility((finalState == LauncherState.NORMAL
- || finalState == LauncherState.SPRING_LOADED) ? VISIBLE : INVISIBLE);
- }
-
/**
* Initialize {@code #mIconDrawable} if the item can be represented using
* an {@link AdaptiveIconDrawable} or {@link FolderAdaptiveIcon}.
@@ -221,10 +198,10 @@
Object[] outObj = new Object[1];
int w = mWidth;
int h = mHeight;
- Drawable dr = Utilities.getFullDrawable(mLauncher, info, w, h, outObj);
+ Drawable dr = Utilities.getFullDrawable(mActivity, info, w, h, outObj);
if (dr instanceof AdaptiveIconDrawable) {
- int blurMargin = (int) mLauncher.getResources()
+ int blurMargin = (int) mActivity.getResources()
.getDimension(R.dimen.blur_size_medium_outline) / 2;
Rect bounds = new Rect(0, 0, w, h);
@@ -232,13 +209,13 @@
// Badge is applied after icon normalization so the bounds for badge should not
// be scaled down due to icon normalization.
Rect badgeBounds = new Rect(bounds);
- mBadge = getBadge(mLauncher, info, outObj[0]);
+ mBadge = getBadge(mActivity, info, outObj[0]);
mBadge.setBounds(badgeBounds);
// Do not draw the background in case of folder as its translucent
final boolean shouldDrawBackground = !(dr instanceof FolderAdaptiveIcon);
- try (LauncherIcons li = LauncherIcons.obtain(mLauncher)) {
+ try (LauncherIcons li = LauncherIcons.obtain(mActivity)) {
Drawable nDr; // drawable to be normalized
if (shouldDrawBackground) {
nDr = dr;
@@ -429,12 +406,11 @@
applyTranslation();
}
- public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
- mTempLoc[0] = toTouchX - mRegistrationX;
- mTempLoc[1] = toTouchY - mRegistrationY;
- mDragLayer.animateViewIntoPosition(this, mTempLoc, 1f, mScaleOnDrop, mScaleOnDrop,
- DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
- }
+ /**
+ * Animate this DragView to the given DragLayer coordinates and then remove it.
+ */
+ public abstract void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable,
+ int duration);
public void animateShift(final int shiftX, final int shiftY) {
if (mAnim.isStarted()) {
@@ -470,7 +446,7 @@
Picture picture = new Picture();
mContent.draw(picture.beginRecording(mWidth, mHeight));
picture.endRecording();
- View view = new View(mLauncher);
+ View view = new View(mActivity);
view.setClipToOutline(mContent.getClipToOutline());
view.setOutlineProvider(mContent.getOutlineProvider());
view.setBackground(new PictureDrawable(picture));
diff --git a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
index ea1fbdb..6a6603c 100644
--- a/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
+++ b/src/com/android/launcher3/dragndrop/FolderAdaptiveIcon.java
@@ -32,12 +32,12 @@
import androidx.annotation.Nullable;
-import com.android.launcher3.Launcher;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
import com.android.launcher3.graphics.ShiftedBitmapDrawable;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.views.ActivityContext;
/**
* {@link AdaptiveIconDrawable} representation of a {@link FolderIcon}
@@ -70,14 +70,14 @@
}
public static @Nullable FolderAdaptiveIcon createFolderAdaptiveIcon(
- Launcher launcher, int folderId, Point dragViewSize) {
+ ActivityContext activity, int folderId, Point dragViewSize) {
Preconditions.assertNonUiThread();
// 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);
+ FolderIcon icon = activity.findFolderIcon(folderId);
return icon == null ? null : createDrawableOnUiThread(icon, dragViewSize);
}).get();
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java
index a98d70c..0e8b0a5 100644
--- a/src/com/android/launcher3/dragndrop/LauncherDragController.java
+++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java
@@ -96,7 +96,7 @@
final float scaleDps = mIsInPreDrag
? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
final DragView dragView = mDragObject.dragView = drawable != null
- ? new DragView(
+ ? new LauncherDragView(
mActivity,
drawable,
registrationX,
@@ -104,7 +104,7 @@
initialDragViewScale,
dragViewScaleOnDrop,
scaleDps)
- : new DragView(
+ : new LauncherDragView(
mActivity,
view,
view.getMeasuredWidth(),
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragView.java b/src/com/android/launcher3/dragndrop/LauncherDragView.java
new file mode 100644
index 0000000..cc68e2e
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/LauncherDragView.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 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.drawable.Drawable;
+import android.view.View;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.statemanager.StateManager;
+
+/**
+ * A DragView drawn/used by the Launcher activity.
+ */
+public class LauncherDragView extends DragView<Launcher>
+ implements StateManager.StateListener<LauncherState> {
+
+
+ public LauncherDragView(Launcher launcher, Drawable drawable, int registrationX,
+ int registrationY, float initialScale, float scaleOnDrop, float finalScaleDps) {
+ super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop,
+ finalScaleDps);
+ }
+
+ public LauncherDragView(Launcher launcher, View content, int width, int height,
+ int registrationX, int registrationY, float initialScale, float scaleOnDrop,
+ float finalScaleDps) {
+ super(launcher, content, width, height, registrationX, registrationY, initialScale,
+ scaleOnDrop, finalScaleDps);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mActivity.getStateManager().addStateListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mActivity.getStateManager().removeStateListener(this);
+ }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ setVisibility((finalState == LauncherState.NORMAL
+ || finalState == LauncherState.SPRING_LOADED) ? VISIBLE : INVISIBLE);
+ }
+
+ @Override
+ public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
+ mTempLoc[0] = toTouchX - mRegistrationX;
+ mTempLoc[1] = toTouchY - mRegistrationY;
+ mActivity.getDragLayer().animateViewIntoPosition(this, mTempLoc, 1f, mScaleOnDrop,
+ mScaleOnDrop, DragLayer.ANIMATION_END_DISAPPEAR, onCompleteRunnable, duration);
+ }
+}
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index a549750..f027b33 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -32,13 +32,13 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DraggableView;
import com.android.launcher3.icons.BitmapRenderer;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.util.SafeCloseable;
+import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import java.nio.ByteBuffer;
@@ -150,7 +150,7 @@
}
public float getScaleAndPosition(Drawable preview, int[] outPos) {
- float scale = Launcher.getLauncher(mView.getContext())
+ float scale = ActivityContext.lookupContext(mView.getContext())
.getDragLayer().getLocationInDragLayer(mView, outPos);
if (mView instanceof LauncherAppWidgetHostView) {
// App widgets are technically scaled, but are drawn at their expected size -- so the
@@ -167,7 +167,7 @@
/** Returns the scale and position of a given view for drag-n-drop. */
public float getScaleAndPosition(View view, int[] outPos) {
- float scale = Launcher.getLauncher(mView.getContext())
+ float scale = ActivityContext.lookupContext(mView.getContext())
.getDragLayer().getLocationInDragLayer(mView, outPos);
if (mView instanceof LauncherAppWidgetHostView) {
// App widgets are technically scaled, but are drawn at their expected size -- so the
@@ -201,7 +201,7 @@
public void run() {
Bitmap preview = convertPreviewToAlphaBitmap(mPreviewSnapshot);
if (mIsIcon) {
- int size = Launcher.getLauncher(mContext).getDeviceProfile().iconSizePx;
+ int size = ActivityContext.lookupContext(mContext).getDeviceProfile().iconSizePx;
preview = Bitmap.createScaledBitmap(preview, size, size, false);
}
//else case covers AppWidgetHost (doesn't drag/drop across different device profiles)
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 646b669..b95904e 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -21,9 +21,12 @@
import android.view.LayoutInflater;
import android.view.View.AccessibilityDelegate;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ViewCache;
@@ -100,6 +103,13 @@
}
/**
+ * Returns the FolderIcon with the given item id, if it exists.
+ */
+ default @Nullable FolderIcon findFolderIcon(final int folderIconId) {
+ return null;
+ }
+
+ /**
* Returns the ActivityContext associated with the given Context.
*/
static <T extends Context & ActivityContext> T lookupContext(Context context) {