Merge "Optimizing some icon generation code:" into tm-qpr-dev
diff --git a/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java b/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java
index 5bf727a..8720bd8 100644
--- a/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java
+++ b/quickstep/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictionsImpl.java
@@ -18,7 +18,9 @@
import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
import android.content.Context;
+import android.view.View;
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.appprediction.AppsDividerView;
import com.android.launcher3.appprediction.PredictionRowView;
import com.android.launcher3.model.BgDataModel;
@@ -39,10 +41,13 @@
@Override
void updateAppDivider() {
OnboardingPrefs<?> onboardingPrefs = mActivityContext.getOnboardingPrefs();
- mActivityContext.getAppsView().getFloatingHeaderView()
- .findFixedRowByType(AppsDividerView.class)
- .setShowAllAppsLabel(!onboardingPrefs.hasReachedMaxCount(ALL_APPS_VISITED_COUNT));
- onboardingPrefs.incrementEventCount(ALL_APPS_VISITED_COUNT);
+ if (onboardingPrefs != null) {
+ mActivityContext.getAppsView().getFloatingHeaderView()
+ .findFixedRowByType(AppsDividerView.class)
+ .setShowAllAppsLabel(
+ !onboardingPrefs.hasReachedMaxCount(ALL_APPS_VISITED_COUNT));
+ onboardingPrefs.incrementEventCount(ALL_APPS_VISITED_COUNT);
+ }
}
@Override
@@ -51,4 +56,12 @@
.findFixedRowByType(PredictionRowView.class)
.setPredictedApps(item.items);
}
+
+ @Override
+ public void setLongClickListener(ActivityAllAppsContainerView<?> appsView,
+ View.OnLongClickListener onIconLongClickListener) {
+ appsView.getFloatingHeaderView()
+ .findFixedRowByType(PredictionRowView.class)
+ .setOnIconLongClickListener(onIconLongClickListener);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
index ce51f7d..e41c75f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java
@@ -20,10 +20,6 @@
import android.view.WindowInsets;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
-import com.android.launcher3.allapps.AllAppsGridAdapter;
-import com.android.launcher3.allapps.AlphabeticalAppsList;
-import com.android.launcher3.allapps.BaseAdapterProvider;
-import com.android.launcher3.allapps.BaseAllAppsAdapter;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
/** All apps container accessible from taskbar. */
@@ -43,12 +39,4 @@
setInsets(insets.getInsets(WindowInsets.Type.systemBars()).toRect());
return super.onApplyWindowInsets(insets);
}
-
- @Override
- protected BaseAllAppsAdapter<TaskbarOverlayContext> createAdapter(
- AlphabeticalAppsList<TaskbarOverlayContext> appsList,
- BaseAdapterProvider[] adapterProviders) {
- return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
- adapterProviders);
- }
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index ff612f5..a2e88f9 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -191,6 +191,7 @@
mStagePosition = mThumbnailPosition.equals(splitInfo.leftTopBounds) ?
STAGE_POSITION_TOP_OR_LEFT :
STAGE_POSITION_BOTTOM_OR_RIGHT;
+ mPositionHelper.setSplitBounds(convertSplitBounds(mSplitBounds), mStagePosition);
}
/**
@@ -418,4 +419,15 @@
return Math.max(Math.abs(mTempPoint[0]), Math.abs(mTempPoint[1]));
}
+ /**
+ * TODO(b/254378592): Remove this after consolidation of classes
+ */
+ public static com.android.wm.shell.util.SplitBounds convertSplitBounds(SplitBounds bounds) {
+ return new com.android.wm.shell.util.SplitBounds(
+ bounds.leftTopBounds,
+ bounds.rightBottomBounds,
+ bounds.leftTopTaskId,
+ bounds.rightBottomTaskId
+ );
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/ViewCapture.java b/quickstep/src/com/android/quickstep/util/ViewCapture.java
index 6171c5d..ba7d7f5 100644
--- a/quickstep/src/com/android/quickstep/util/ViewCapture.java
+++ b/quickstep/src/com/android/quickstep/util/ViewCapture.java
@@ -23,10 +23,9 @@
import android.content.Context;
import android.content.res.Resources;
-import android.os.Handler;
import android.os.Looper;
-import android.os.Message;
import android.os.Process;
+import android.os.SystemClock;
import android.os.Trace;
import android.text.TextUtils;
import android.util.Base64;
@@ -57,7 +56,9 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.Future;
+import java.util.concurrent.Executor;
+import java.util.concurrent.FutureTask;
+import java.util.function.Consumer;
import java.util.zip.GZIPOutputStream;
/**
@@ -83,7 +84,7 @@
private final List<WindowListener> mListeners = new ArrayList<>();
private final Context mContext;
- private final LooperExecutor mExecutor;
+ private final Executor mExecutor;
// Pool used for capturing view tree on the UI thread.
private ViewRef mPool = new ViewRef();
@@ -156,8 +157,13 @@
ViewIdProvider idProvider = new ViewIdProvider(mContext.getResources());
// Collect all the tasks first so that all the tasks are posted on the executor
- List<Pair<String, Future<ExportedData>>> tasks = mListeners.stream()
- .map(l -> Pair.create(l.name, mExecutor.submit(() -> l.dumpToProto(idProvider))))
+ List<Pair<String, FutureTask<ExportedData>>> tasks = mListeners.stream()
+ .map(l -> {
+ FutureTask<ExportedData> task =
+ new FutureTask<ExportedData>(() -> l.dumpToProto(idProvider));
+ mExecutor.execute(task);
+ return Pair.create(l.name, task);
+ })
.collect(toList());
tasks.forEach(pair -> {
@@ -187,7 +193,6 @@
private final View mRoot;
public final String name;
- private final Handler mHandler;
private final ViewRef mViewRef = new ViewRef();
private int mFrameIndexBg = -1;
@@ -196,20 +201,23 @@
private final ViewPropertyRef[] mNodesBg = new ViewPropertyRef[MEMORY_SIZE];
private boolean mDestroyed = false;
+ private final Consumer<ViewRef> mCaptureCallback = this::captureViewPropertiesBg;
WindowListener(View view, String name) {
mRoot = view;
this.name = name;
- mHandler = new Handler(mExecutor.getLooper(), this::captureViewPropertiesBg);
}
@Override
public void onDraw() {
Trace.beginSection("view_capture");
captureViewTree(mRoot, mViewRef);
- Message m = Message.obtain(mHandler);
- m.obj = mViewRef.next;
- mHandler.sendMessage(m);
+ ViewRef captured = mViewRef.next;
+ if (captured != null) {
+ captured.callback = mCaptureCallback;
+ captured.creationTime = SystemClock.uptimeMillis();
+ mExecutor.execute(captured);
+ }
mIsFirstFrame = false;
Trace.endSection();
}
@@ -219,12 +227,8 @@
* back to the pool
*/
@WorkerThread
- private boolean captureViewPropertiesBg(Message msg) {
- ViewRef viewRefStart = (ViewRef) msg.obj;
- long time = msg.getWhen();
- if (viewRefStart == null) {
- return false;
- }
+ private void captureViewPropertiesBg(ViewRef viewRefStart) {
+ long time = viewRefStart.creationTime;
mFrameIndexBg++;
if (mFrameIndexBg >= MEMORY_SIZE) {
mFrameIndexBg = 0;
@@ -292,7 +296,6 @@
viewRefEnd = viewRefEnd.next;
}
mNodesBg[mFrameIndexBg] = resultStart;
- return true;
}
private ViewPropertyRef findInLastFrame(int hashCode) {
@@ -464,11 +467,14 @@
}
}
- private static class ViewRef {
+ private static class ViewRef implements Runnable {
public View view;
public int childCount = 0;
public ViewRef next;
+ public Consumer<ViewRef> callback = null;
+ public long creationTime = 0;
+
public void transferTo(ViewPropertyRef out) {
out.childCount = this.childCount;
@@ -495,6 +501,15 @@
out.visibility = view.getVisibility();
out.willNotDraw = view.willNotDraw();
}
+
+ @Override
+ public void run() {
+ Consumer<ViewRef> oldCallback = callback;
+ callback = null;
+ if (oldCallback != null) {
+ oldCallback.accept(this);
+ }
+ }
}
private static final class ViewIdProvider {
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 71b0c60..64b5e0b 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -1,6 +1,5 @@
package com.android.quickstep.views;
-import static com.android.launcher3.AbstractFloatingView.getAnyView;
import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
@@ -14,11 +13,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
import com.android.launcher3.util.TransformingTouchDelegate;
import com.android.quickstep.RecentsModel;
@@ -26,8 +25,10 @@
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.util.CancellableTask;
import com.android.quickstep.util.RecentsOrientedState;
+import com.android.quickstep.util.TaskViewSimulator;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.HashMap;
@@ -86,9 +87,19 @@
mTaskIdContainer[1] = secondary.key.id;
mTaskIdAttributeContainer[1] = new TaskIdAttributeContainer(secondary, mSnapshotView2,
mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT);
- mTaskIdAttributeContainer[0].setStagePosition(STAGE_POSITION_TOP_OR_LEFT);
+ mTaskIdAttributeContainer[0].setStagePosition(
+ SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT);
mSnapshotView2.bind(secondary);
mSplitBoundsConfig = splitBoundsConfig;
+ if (mSplitBoundsConfig == null) {
+ return;
+ }
+ mSnapshotView.getPreviewPositionHelper().setSplitBounds(TaskViewSimulator
+ .convertSplitBounds(splitBoundsConfig),
+ PreviewPositionHelper.STAGE_POSITION_TOP_OR_LEFT);
+ mSnapshotView2.getPreviewPositionHelper().setSplitBounds(TaskViewSimulator
+ .convertSplitBounds(splitBoundsConfig),
+ PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT);
}
@Override
@@ -164,21 +175,6 @@
}
}
- @Override
- protected boolean showTaskMenuWithContainer(IconView iconView) {
- boolean showedTaskMenu = super.showTaskMenuWithContainer(iconView);
- if (iconView == mIconView2 && showedTaskMenu && !mActivity.getDeviceProfile().isTablet) {
- // Adjust the position of the secondary task's menu view (only on phones)
- TaskMenuView taskMenuView = getAnyView(mActivity, AbstractFloatingView.TYPE_TASK_MENU);
- DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- getRecentsView().getPagedOrientationHandler()
- .setSecondaryTaskMenuPosition(mSplitBoundsConfig, this,
- deviceProfile, mTaskIdAttributeContainer[0].getThumbnailView(),
- taskMenuView);
- }
- return showedTaskMenu;
- }
-
@Nullable
@Override
public RunnableList launchTaskAnimated() {
@@ -207,7 +203,8 @@
@Override
public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
getRecentsView().getSplitSelectController().launchTasks(mTask.key.id, mSecondaryTask.key.id,
- STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList, getSplitRatio());
+ SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList,
+ getSplitRatio());
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index ab19487..f60e08d 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1246,6 +1246,8 @@
if (!mActivity.getDeviceProfile().isTablet) {
mActionsView.updateDisabledFlags(OverviewActionsView.DISABLED_SCROLLING, true);
}
+ InteractionJankMonitorWrapper.begin(/* view= */ this,
+ InteractionJankMonitorWrapper.CUJ_RECENTS_SCROLLING);
}
@Override
@@ -1259,6 +1261,7 @@
if (getNextPage() > 0) {
setSwipeDownShouldLaunchApp(true);
}
+ InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_RECENTS_SCROLLING);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 6815745..2c9afb4 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -23,7 +23,6 @@
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Outline;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
@@ -32,7 +31,6 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewOutlineProvider;
-import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -56,13 +54,12 @@
/**
* Contains options for a recent task when long-pressing its icon.
*/
-public class TaskMenuView extends AbstractFloatingView implements OnScrollChangedListener {
+public class TaskMenuView extends AbstractFloatingView {
private static final Rect sTempRect = new Rect();
private static final int REVEAL_OPEN_DURATION = 150;
private static final int REVEAL_CLOSE_DURATION = 100;
- private final float mTaskInsetMargin;
private BaseDraggingActivity mActivity;
private TextView mTaskName;
@@ -81,7 +78,6 @@
mActivity = BaseDraggingActivity.fromContext(context);
setClipToOutline(true);
- mTaskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
}
@Override
@@ -129,33 +125,6 @@
};
}
- private void setPosition(float x, float y, int overscrollShift) {
- PagedOrientationHandler pagedOrientationHandler = mTaskView.getPagedOrientationHandler();
- // Inset due to margin
- PointF additionalInset = pagedOrientationHandler
- .getAdditionalInsetForTaskMenu(mTaskInsetMargin);
- DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- int taskTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
-
- float adjustedY = y + taskTopMargin - additionalInset.y;
- float adjustedX = x - additionalInset.x;
- // Changing pivot to make computations easier
- // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
- // which would render the X and Y position set here incorrect
- setPivotX(0);
- if (deviceProfile.isTablet) {
- // In tablet, set pivotY to original position without mThumbnailTopMargin adjustment.
- setPivotY(-taskTopMargin);
- } else {
- setPivotY(0);
- }
- setRotation(pagedOrientationHandler.getDegreesRotated());
- setX(pagedOrientationHandler.getTaskMenuX(adjustedX,
- mTaskContainer.getThumbnailView(), overscrollShift, deviceProfile));
- setY(pagedOrientationHandler.getTaskMenuY(
- adjustedY, mTaskContainer.getThumbnailView(), overscrollShift));
- }
-
public void onRotationChanged() {
if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
mOpenCloseAnimator.end();
@@ -187,17 +156,9 @@
return false;
}
post(this::animateOpen);
- ((RecentsView) mActivity.getOverviewPanel()).addOnScrollChangedListener(this);
return true;
}
- @Override
- public void onScrollChanged() {
- RecentsView rv = mActivity.getOverviewPanel();
- setPosition(mTaskView.getX() - rv.getScrollX(), mTaskView.getY() - rv.getScrollY(),
- rv.getOverScrollShift());
- }
-
/** @return true if successfully able to populate task view menu, false otherwise */
private boolean populateAndLayoutMenu() {
if (mTaskContainer.getTask().icon == null) {
@@ -234,18 +195,18 @@
RecentsView recentsView = mActivity.getOverviewPanel();
PagedOrientationHandler orientationHandler = recentsView.getPagedOrientationHandler();
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- orientationHandler.setTaskMenuAroundTaskView(this, mTaskInsetMargin);
// Get Position
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- mActivity.getDragLayer().getDescendantRectRelativeToSelf(mTaskView, sTempRect);
+ mActivity.getDragLayer().getDescendantRectRelativeToSelf(taskContainer.getThumbnailView(),
+ sTempRect);
Rect insets = mActivity.getDragLayer().getInsets();
BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
int padding = getResources()
.getDimensionPixelSize(R.dimen.task_menu_vertical_padding);
params.width = orientationHandler
.getTaskMenuWidth(taskContainer.getThumbnailView(),
- deviceProfile) - (2 * padding);
+ deviceProfile, taskContainer.getStagePosition()) - (2 * padding);
// Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start
params.gravity = Gravity.LEFT;
setLayoutParams(params);
@@ -260,7 +221,22 @@
orientationHandler.setTaskOptionsMenuLayoutOrientation(
deviceProfile, mOptionLayout, dividerSpacing, divider);
- setPosition(sTempRect.left - insets.left, sTempRect.top - insets.top, 0);
+ float thumbnailAlignedX = sTempRect.left - insets.left;
+ float thumbnailAlignedY = sTempRect.top - insets.top;
+ // Changing pivot to make computations easier
+ // NOTE: Changing the pivots means the rotated view gets rotated about the new pivots set,
+ // which would render the X and Y position set here incorrect
+ setPivotX(0);
+ setPivotY(0);
+ setRotation(orientationHandler.getDegreesRotated());
+
+ // Margin that insets the menuView inside the taskView
+ float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
+ setTranslationX(orientationHandler.getTaskMenuX(thumbnailAlignedX,
+ mTaskContainer.getThumbnailView(), deviceProfile, taskInsetMargin));
+ setTranslationY(orientationHandler.getTaskMenuY(
+ thumbnailAlignedY, mTaskContainer.getThumbnailView(),
+ mTaskContainer.getStagePosition(), this, taskInsetMargin));
}
private void animateOpen() {
@@ -306,7 +282,6 @@
private void closeComplete() {
mIsOpen = false;
mActivity.getDragLayer().removeView(this);
- ((RecentsView) mActivity.getOverviewPanel()).removeOnScrollChangedListener(this);
}
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 7881a26..1c26f04 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -218,6 +218,9 @@
public int overviewRowSpacing;
public int overviewGridSideMargin;
+ // Split staging
+ public int splitPlaceholderInset;
+
// Widgets
private final ViewScaleProvider mViewScaleProvider;
@@ -459,6 +462,8 @@
overviewRowSpacing = res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing);
overviewGridSideMargin = res.getDimensionPixelSize(R.dimen.overview_grid_side_margin);
+ splitPlaceholderInset = res.getDimensionPixelSize(R.dimen.split_placeholder_inset);
+
// Calculate all of the remaining variables.
extraSpace = updateAvailableDimensions(res);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index a8d1367..75c28f9 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -299,6 +299,10 @@
public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(
"ENABLE_TRANSIENT_TASKBAR", false, "Enables transient taskbar.");
+ public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(
+ "SECONDARY_DRAG_N_DROP_TO_PIN", false,
+ "Enable dragging and dropping to pin apps within secondary display");
+
public static void initialize(Context context) {
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java b/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java
index a0ed77e..f03c62a 100644
--- a/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java
+++ b/src/com/android/launcher3/secondarydisplay/PinnedAppsAdapter.java
@@ -168,15 +168,18 @@
mPrefs.unregisterOnSharedPreferenceChangeListener(this);
}
- private void update(ItemInfo info, Function<ComponentKey, Boolean> op) {
+ /**
+ * Pins or unpins apps from home screen
+ */
+ public void update(ItemInfo info, Function<ComponentKey, Boolean> op) {
ComponentKey key = new ComponentKey(info.getTargetComponent(), info.user);
if (op.apply(key)) {
createFilteredAppsList();
Set<ComponentKey> copy = new HashSet<>(mPinnedApps);
Executors.MODEL_EXECUTOR.submit(() ->
mPrefs.edit().putStringSet(PINNED_APPS_KEY,
- copy.stream().map(this::encode).collect(Collectors.toSet()))
- .apply());
+ copy.stream().map(this::encode).collect(Collectors.toSet()))
+ .apply());
}
}
@@ -210,6 +213,13 @@
mPinnedApps.contains(new ComponentKey(info.getTargetComponent(), info.user)));
}
+ /**
+ * Pins app to home screen
+ */
+ public void addPinnedApp(ItemInfo info) {
+ update(info, mPinnedApps::add);
+ }
+
private class PinUnPinShortcut extends SystemShortcut<SecondaryDisplayLauncher> {
private final boolean mIsPinned;
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index a55f7e3..7b32d8b 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -18,6 +18,9 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Intent;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
@@ -26,6 +29,9 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
@@ -33,6 +39,11 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.graphics.DragPreviewProvider;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.AppInfo;
@@ -52,11 +63,11 @@
* Launcher activity for secondary displays
*/
public class SecondaryDisplayLauncher extends BaseDraggingActivity
- implements BgDataModel.Callbacks {
+ implements BgDataModel.Callbacks, DragController.DragListener {
private LauncherModel mModel;
-
private BaseDragLayer mDragLayer;
+ private SecondaryDragController mDragController;
private ActivityAllAppsContainerView<SecondaryDisplayLauncher> mAppsView;
private View mAppsButton;
@@ -69,10 +80,13 @@
private boolean mBindingItems = false;
private SecondaryDisplayPredictions mSecondaryDisplayPredictions;
+ private final int[] mTempXY = new int[2];
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mModel = LauncherAppState.getInstance(this).getModel();
+ mDragController = new SecondaryDragController(this);
mOnboardingPrefs = new OnboardingPrefs<>(this, Utilities.getPrefs(this));
mSecondaryDisplayPredictions = SecondaryDisplayPredictions.newInstance(this);
if (getWindow().getDecorView().isAttachedToWindow()) {
@@ -86,6 +100,12 @@
initUi();
}
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ this.getDragController().removeDragListener(this);
+ }
+
private void initUi() {
if (mDragLayer != null) {
return;
@@ -106,6 +126,7 @@
mAppsView = findViewById(R.id.apps_view);
mAppsButton = findViewById(R.id.all_apps_button);
+ mDragController.addDragListener(this);
mPopupDataProvider = new PopupDataProvider(
mAppsView.getAppsStore()::updateNotificationDots);
@@ -113,6 +134,12 @@
}
@Override
+ protected void onPause() {
+ super.onPause();
+ mDragController.cancelDrag();
+ }
+
+ @Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
@@ -129,12 +156,21 @@
showAppDrawer(false);
}
+ public DragController getDragController() {
+ return mDragController;
+ }
+
@Override
public void onBackPressed() {
if (finishAutoCancelActionMode()) {
return;
}
+ if (mDragController.isDragging()) {
+ mDragController.cancelDrag();
+ return;
+ }
+
// Note: There should be at most one log per method call. This is enforced implicitly
// by using if-else statements.
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
@@ -202,7 +238,7 @@
float closeR = Themes.getDialogCornerRadius(this);
float startR = mAppsButton.getWidth() / 2f;
- float[] buttonPos = new float[] { startR, startR};
+ float[] buttonPos = new float[]{startR, startR};
mDragLayer.getDescendantCoordRelativeToSelf(mAppsButton, buttonPos);
mDragLayer.mapCoordInSelfToDescendant(mAppsView, buttonPos);
final Animator animator = ViewAnimationUtils.createCircularReveal(mAppsView,
@@ -236,6 +272,7 @@
@Override
public void startBinding() {
mBindingItems = true;
+ mDragController.cancelDrag();
}
@Override
@@ -266,6 +303,10 @@
}
}
+ public SecondaryDisplayPredictions getSecondaryDisplayPredictions() {
+ return mSecondaryDisplayPredictions;
+ }
+
@Override
public StringCache getStringCache() {
return mStringCache;
@@ -308,4 +349,101 @@
startActivitySafely(v, intent, item);
}
}
+
+ /**
+ * Core functionality for beginning a drag operation for an item that will be dropped within
+ * the secondary display grid home screen
+ */
+ public void beginDragShared(View child, DragSource source, DragOptions options) {
+ Object dragObject = child.getTag();
+ if (!(dragObject instanceof ItemInfo)) {
+ String msg = "Drag started with a view that has no tag set. This "
+ + "will cause a crash (issue 11627249) down the line. "
+ + "View: " + child + " tag: " + child.getTag();
+ throw new IllegalStateException(msg);
+ }
+ beginDragShared(child, source, (ItemInfo) dragObject,
+ new DragPreviewProvider(child), options);
+ }
+
+ private void beginDragShared(View child, DragSource source,
+ ItemInfo dragObject, DragPreviewProvider previewProvider, DragOptions options) {
+
+ float iconScale = 1f;
+ if (child instanceof BubbleTextView) {
+ FastBitmapDrawable icon = ((BubbleTextView) child).getIcon();
+ if (icon != null) {
+ iconScale = icon.getAnimatedScale();
+ }
+ }
+
+ // clear pressed state if necessary
+ child.clearFocus();
+ child.setPressed(false);
+ if (child instanceof BubbleTextView) {
+ BubbleTextView icon = (BubbleTextView) child;
+ icon.clearPressedBackground();
+ }
+
+ DraggableView draggableView = null;
+ if (child instanceof DraggableView) {
+ draggableView = (DraggableView) child;
+ }
+
+ final View contentView = previewProvider.getContentView();
+ final float scale;
+ // The draggable drawable follows the touch point around on the screen
+ final Drawable drawable;
+ if (contentView == null) {
+ drawable = previewProvider.createDrawable();
+ scale = previewProvider.getScaleAndPosition(drawable, mTempXY);
+ } else {
+ drawable = null;
+ scale = previewProvider.getScaleAndPosition(contentView, mTempXY);
+ }
+ int halfPadding = previewProvider.previewPadding / 2;
+ int dragLayerX = mTempXY[0];
+ int dragLayerY = mTempXY[1];
+
+ Point dragVisualizeOffset = null;
+ Rect dragRect = new Rect();
+ if (draggableView != null) {
+ draggableView.getSourceVisualDragBounds(dragRect);
+ dragLayerY += dragRect.top;
+ dragVisualizeOffset = new Point(-halfPadding, halfPadding);
+ }
+ if (contentView != null) {
+ mDragController.startDrag(
+ contentView,
+ draggableView,
+ dragLayerX,
+ dragLayerY,
+ source,
+ dragObject,
+ dragVisualizeOffset,
+ dragRect,
+ scale * iconScale,
+ scale,
+ options);
+ } else {
+ mDragController.startDrag(
+ drawable,
+ draggableView,
+ dragLayerX,
+ dragLayerY,
+ source,
+ dragObject,
+ dragVisualizeOffset,
+ dragRect,
+ scale * iconScale,
+ scale,
+ options);
+ }
+ }
+
+ @Override
+ public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) { }
+
+ @Override
+ public void onDragEnd() { }
}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java
index a58916a..21c50d3 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayPredictions.java
@@ -16,8 +16,10 @@
package com.android.launcher3.secondarydisplay;
import android.content.Context;
+import android.view.View;
import com.android.launcher3.R;
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -45,4 +47,12 @@
*/
public void setPredictedApps(BgDataModel.FixedContainerItems item) {
}
+
+ /**
+ * Set long click listener for predicted apps in top of app drawer.
+ */
+ public void setLongClickListener(
+ ActivityAllAppsContainerView<?> appsView,
+ View.OnLongClickListener onIconLongClickListener) {
+ }
}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java
new file mode 100644
index 0000000..9bf2764
--- /dev/null
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragController.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 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.secondarydisplay;
+
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.R;
+import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragDriver;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.testing.shared.TestProtocol;
+
+/**
+ * Drag controller for Secondary Launcher activity
+ */
+public class SecondaryDragController extends DragController<SecondaryDisplayLauncher> {
+
+ private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
+
+ public SecondaryDragController(SecondaryDisplayLauncher secondaryLauncher) {
+ super(secondaryLauncher);
+ }
+
+ @Override
+ protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view,
+ DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source,
+ ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale,
+ float dragViewScaleOnDrop, DragOptions options) {
+
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_DROP_TARGET, "5");
+ }
+
+ if (PROFILE_DRAWING_DURING_DRAG) {
+ android.os.Debug.startMethodTracing("Launcher");
+ }
+ mActivity.hideKeyboard();
+
+ mOptions = options;
+ if (mOptions.simulatedDndStartPoint != null) {
+ mLastTouch.x = mMotionDown.x = mOptions.simulatedDndStartPoint.x;
+ mLastTouch.y = mMotionDown.y = mOptions.simulatedDndStartPoint.y;
+ }
+
+ final int registrationX = mMotionDown.x - dragLayerX;
+ final int registrationY = mMotionDown.y - dragLayerY;
+
+ final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
+ final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
+
+ mLastDropTarget = null;
+
+ mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext());
+ mDragObject.originalView = originalView;
+
+ mIsInPreDrag = mOptions.preDragCondition != null
+ && !mOptions.preDragCondition.shouldStartDrag(0);
+
+ final Resources res = mActivity.getResources();
+ final float scaleDps = mIsInPreDrag
+ ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
+
+ final DragView dragView = mDragObject.dragView = drawable != null
+ ? new SecondaryDragView(
+ mActivity,
+ drawable,
+ registrationX,
+ registrationY,
+ initialDragViewScale,
+ dragViewScaleOnDrop,
+ scaleDps)
+ : new SecondaryDragView(
+ mActivity,
+ view,
+ view.getMeasuredWidth(),
+ view.getMeasuredHeight(),
+ registrationX,
+ registrationY,
+ initialDragViewScale,
+ dragViewScaleOnDrop,
+ scaleDps);
+ dragView.setItemInfo(dragInfo);
+ mDragObject.dragComplete = false;
+
+ mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft);
+ mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop);
+
+ mDragDriver = DragDriver.create(this, mOptions, ev -> {
+ });
+ if (!mOptions.isAccessibleDrag) {
+ mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
+ }
+
+ mDragObject.dragSource = source;
+ mDragObject.dragInfo = dragInfo;
+ mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
+
+ if (dragOffset != null) {
+ dragView.setDragVisualizeOffset(new Point(dragOffset));
+ }
+ if (dragRegion != null) {
+ dragView.setDragRegion(new Rect(dragRegion));
+ }
+
+ mActivity.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ dragView.show(mLastTouch.x, mLastTouch.y);
+ mDistanceSinceScroll = 0;
+
+ if (!mIsInPreDrag) {
+ callOnDragStart();
+ } else if (mOptions.preDragCondition != null) {
+ mOptions.preDragCondition.onPreDragStart(mDragObject);
+ }
+
+ handleMoveEvent(mLastTouch.x, mLastTouch.y);
+ return dragView;
+ }
+
+ @Override
+ protected void exitDrag() { }
+
+ @Override
+ protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
+ DropTarget target = new DropTarget() {
+ @Override
+ public boolean isDropEnabled() {
+ return true;
+ }
+
+ @Override
+ public void onDrop(DragObject dragObject, DragOptions options) {
+ ((SecondaryDragLayer) mActivity.getDragLayer()).getPinnedAppsAdapter().addPinnedApp(
+ dragObject.dragInfo);
+ dragObject.dragView.remove();
+ }
+
+ @Override
+ public void onDragEnter(DragObject dragObject) {
+ if (getDistanceDragged() > mActivity.getResources().getDimensionPixelSize(
+ R.dimen.drag_distanceThreshold)) {
+ mActivity.showAppDrawer(false);
+ AbstractFloatingView.closeAllOpenViews(mActivity);
+ }
+ }
+
+ @Override
+ public void onDragOver(DragObject dragObject) { }
+
+ @Override
+ public void onDragExit(DragObject dragObject) { }
+
+ @Override
+ public boolean acceptDrop(DragObject dragObject) {
+ return true;
+ }
+
+ @Override
+ public void prepareAccessibilityDrop() { }
+
+ @Override
+ public void getHitRectRelativeToDragLayer(Rect outRect) { }
+ };
+ return target;
+ }
+}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index c79d70d..5eac01e 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -29,8 +29,12 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DropTarget;
import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
@@ -59,7 +63,8 @@
@Override
public void recreateControllers() {
- mControllers = new TouchController[] {new CloseAllAppsTouchController()};
+ mControllers = new TouchController[]{new CloseAllAppsTouchController(),
+ mActivity.getDragController()};
}
/**
@@ -72,7 +77,8 @@
mAppsView = findViewById(R.id.apps_view);
mAppsView.setOnIconLongClickListener(this::onIconLongClicked);
-
+ mActivity.getSecondaryDisplayPredictions()
+ .setLongClickListener(mAppsView, this::onIconLongClicked);
// Setup workspace
mWorkspace = findViewById(R.id.workspace_grid);
mPinnedAppsAdapter = new PinnedAppsAdapter(mActivity, mAppsView.getAppsStore(),
@@ -166,6 +172,10 @@
}
}
+ public PinnedAppsAdapter getPinnedAppsAdapter() {
+ return mPinnedAppsAdapter;
+ }
+
private boolean onIconLongClicked(View v) {
if (!(v instanceof BubbleTextView)) {
return false;
@@ -183,6 +193,7 @@
if (popupDataProvider == null) {
return false;
}
+
final PopupContainerWithArrow container =
(PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
R.layout.popup_container, mActivity.getDragLayer(), false);
@@ -192,7 +203,42 @@
Collections.emptyList(),
Arrays.asList(mPinnedAppsAdapter.getSystemShortcut(item, v),
APP_INFO.getShortcut(mActivity, item, v)));
- v.getParent().requestDisallowInterceptTouchEvent(true);
+ container.requestFocus();
+
+ if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
+ return true;
+ }
+
+ DragOptions options = new DragOptions();
+ DeviceProfile grid = mActivity.getDeviceProfile();
+ options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
+ options.preDragCondition = container.createPreDragCondition(false);
+ if (options.preDragCondition == null) {
+ options.preDragCondition = new DragOptions.PreDragCondition() {
+ private DragView<SecondaryDisplayLauncher> mDragView;
+
+ @Override
+ public boolean shouldStartDrag(double distanceDragged) {
+ return mDragView != null && mDragView.isAnimationFinished();
+ }
+
+ @Override
+ public void onPreDragStart(DropTarget.DragObject dragObject) {
+ mDragView = dragObject.dragView;
+ if (!shouldStartDrag(0)) {
+ mDragView.setOnAnimationEndCallback(() -> {
+ mActivity.beginDragShared(v, mActivity.getAppsView(), options);
+ });
+ }
+ }
+
+ @Override
+ public void onPreDragEnd(DropTarget.DragObject dragObject, boolean dragStarted) {
+ mDragView = null;
+ }
+ };
+ }
+ mActivity.beginDragShared(v, mActivity.getAppsView(), options);
return true;
}
}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragView.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragView.java
new file mode 100644
index 0000000..0168b8f
--- /dev/null
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragView.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 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.secondarydisplay;
+
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import com.android.launcher3.R;
+import com.android.launcher3.dragndrop.DragView;
+
+/**
+ * A DragView drawn/used by the Secondary Launcher activity.
+ */
+public class SecondaryDragView extends DragView<SecondaryDisplayLauncher> {
+
+ public SecondaryDragView(SecondaryDisplayLauncher launcher,
+ Drawable drawable,
+ int registrationX, int registrationY, float initialScale, float scaleOnDrop,
+ float finalScaleDps) {
+ super(launcher, drawable, registrationX, registrationY, initialScale, scaleOnDrop,
+ finalScaleDps);
+ }
+
+ public SecondaryDragView(SecondaryDisplayLauncher 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
+ public void animateTo(int toTouchX, int toTouchY, Runnable onCompleteRunnable, int duration) {
+ Runnable onAnimationEnd = () -> {
+ if (onCompleteRunnable != null) {
+ onCompleteRunnable.run();
+ }
+ mActivity.getDragLayer().removeView(this);
+ };
+
+ duration = Math.max(duration,
+ getResources().getInteger(R.integer.config_dropAnimMinDuration));
+
+ animate()
+ .translationX(toTouchX - mRegistrationX)
+ .translationY(toTouchY - mRegistrationY)
+ .scaleX(mScaleOnDrop)
+ .scaleY(mScaleOnDrop)
+ .withEndAction(onAnimationEnd)
+ .setDuration(duration)
+ .start();
+ }
+}
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index ceebc2e..820162c 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -30,6 +30,7 @@
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
import android.content.res.Resources;
@@ -265,20 +266,32 @@
}
@Override
- public float getTaskMenuX(float x, View thumbnailView, int overScroll,
- DeviceProfile deviceProfile) {
- return thumbnailView.getMeasuredWidth() + x;
+ public float getTaskMenuX(float x, View thumbnailView,
+ DeviceProfile deviceProfile, float taskInsetMargin) {
+ return thumbnailView.getMeasuredWidth() + x - taskInsetMargin;
}
@Override
- public float getTaskMenuY(float y, View thumbnailView, int overScroll) {
- return y + overScroll +
- (thumbnailView.getMeasuredHeight() - thumbnailView.getMeasuredWidth()) / 2f;
+ public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
+ View taskMenuView, float taskInsetMargin) {
+ BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
+ int taskMenuWidth = lp.width;
+ if (stagePosition == STAGE_POSITION_UNDEFINED) {
+ return y + taskInsetMargin
+ + (thumbnailView.getMeasuredHeight() - taskMenuWidth) / 2f;
+ } else {
+ return y + taskInsetMargin;
+ }
}
@Override
- public int getTaskMenuWidth(View view, DeviceProfile deviceProfile) {
- return view.getMeasuredWidth();
+ public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
+ @StagePosition int stagePosition) {
+ if (stagePosition == SplitConfigurationOptions.STAGE_POSITION_UNDEFINED) {
+ return thumbnailView.getMeasuredWidth();
+ } else {
+ return thumbnailView.getMeasuredHeight();
+ }
}
@Override
@@ -300,17 +313,6 @@
}
@Override
- public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) {
- BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams();
- lp.topMargin += margin;
- }
-
- @Override
- public PointF getAdditionalInsetForTaskMenu(float margin) {
- return new PointF(margin, 0);
- }
-
- @Override
public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
View[] thumbnailViews, int desiredTaskId, View banner) {
@@ -376,19 +378,6 @@
return isRtl ? 1 : -1;
}
- @Override
- public void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView,
- DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView) {
- float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically
- ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent)
- : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent);
- FrameLayout.LayoutParams snapshotParams =
- (FrameLayout.LayoutParams) primarySnaphotView.getLayoutParams();
- float additionalOffset = (taskView.getHeight() - snapshotParams.topMargin)
- * topLeftTaskPlusDividerPercent;
- taskMenuView.setY(taskMenuView.getY() + additionalOffset);
- }
-
/* -------------------- */
@Override
@@ -424,8 +413,8 @@
// In fake land/seascape, the placeholder always needs to go to the "top" of the device,
// which is the same bounds as 0 rotation.
int width = dp.widthPx;
- int insetThickness = dp.getInsets().top;
- out.set(0, 0, width, placeholderHeight + insetThickness);
+ int insetSizeAdjustment = getPlaceholderSizeAdjustment(dp);
+ out.set(0, 0, width, placeholderHeight + insetSizeAdjustment);
out.inset(placeholderInset, 0);
// Adjust the top to account for content off screen. This will help to animate the view in
@@ -442,13 +431,21 @@
float onScreenRectCenterY, float fullscreenScaleX, float fullscreenScaleY,
int drawableWidth, int drawableHeight, DeviceProfile dp,
@StagePosition int stagePosition) {
- float inset = dp.getInsets().top;
+ float insetAdjustment = getPlaceholderSizeAdjustment(dp) / 2f;
out.setX(Math.round(onScreenRectCenterX / fullscreenScaleX
- 1.0f * drawableWidth / 2));
- out.setY(Math.round((onScreenRectCenterY + (inset / 2f)) / fullscreenScaleY
+ out.setY(Math.round((onScreenRectCenterY + insetAdjustment) / fullscreenScaleY
- 1.0f * drawableHeight / 2));
}
+ /**
+ * The split placeholder comes with a default inset to buffer the icon from the top of the
+ * screen. But if the device already has a large inset (from cutouts etc), use that instead.
+ */
+ private int getPlaceholderSizeAdjustment(DeviceProfile dp) {
+ return Math.max(dp.getInsets().top - dp.splitPlaceholderInset, 0);
+ }
+
@Override
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
int splitInstructionsWidth, int threeButtonNavShift) {
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index cbcb700..6234462 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -184,9 +184,12 @@
* taskMenu width is the same size as the thumbnail width (what got set below in
* getTaskMenuWidth()), so we directly use that in the calculations.
*/
- float getTaskMenuX(float x, View thumbnailView, int overScroll, DeviceProfile deviceProfile);
- float getTaskMenuY(float y, View thumbnailView, int overScroll);
- int getTaskMenuWidth(View view, DeviceProfile deviceProfile);
+ float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile,
+ float taskInsetMargin);
+ float getTaskMenuY(float y, View thumbnailView, int stagePosition,
+ View taskMenuView, float taskInsetMargin);
+ int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
+ @StagePosition int stagePosition);
/**
* Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items
* inside task menu view.
@@ -200,16 +203,6 @@
*/
void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
LinearLayout viewGroup, DeviceProfile deviceProfile);
- /**
- * Adjusts margins for the entire task menu view itself, which comprises of both app title and
- * shortcut options.
- */
- void setTaskMenuAroundTaskView(LinearLayout taskView, float margin);
- /**
- * Since the task menu layout is manually positioned on top of recents view, this method returns
- * additional adjustments to the positioning based on fake land/seascape
- */
- PointF getAdditionalInsetForTaskMenu(float margin);
/**
* Calculates the position where a Digital Wellbeing Banner should be placed on its parent
@@ -231,14 +224,6 @@
int getTaskDragDisplacementFactor(boolean isRtl);
/**
- * Calls the corresponding {@link View#setX(float)} or {@link View#setY(float)}
- * on {@param taskMenuView} by taking the space needed by {@param primarySnapshotView} into
- * account.
- * This is expected to only be called for secondary (bottom/right) tasks.
- */
- void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView,
- DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView);
- /**
* Maps the velocity from the coordinate plane of the foreground app to that
* of Launcher's (which now will always be portrait)
*/
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 5efebaa..af689dc 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -56,7 +56,6 @@
import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import com.android.launcher3.views.BaseDragLayer;
import java.util.List;
@@ -265,26 +264,28 @@
}
@Override
- public float getTaskMenuX(float x, View thumbnailView, int overScroll,
- DeviceProfile deviceProfile) {
+ public float getTaskMenuX(float x, View thumbnailView,
+ DeviceProfile deviceProfile, float taskInsetMargin) {
if (deviceProfile.isLandscape) {
- return x + overScroll
+ return x + taskInsetMargin
+ (thumbnailView.getMeasuredWidth() - thumbnailView.getMeasuredHeight()) / 2f;
} else {
- return x + overScroll;
+ return x + taskInsetMargin;
}
}
@Override
- public float getTaskMenuY(float y, View thumbnailView, int overScroll) {
- return y;
+ public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
+ View taskMenuView, float taskInsetMargin) {
+ return y + taskInsetMargin;
}
@Override
- public int getTaskMenuWidth(View view, DeviceProfile deviceProfile) {
+ public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
+ @StagePosition int stagePosition) {
return deviceProfile.isLandscape && !deviceProfile.isTablet
- ? view.getMeasuredHeight()
- : view.getMeasuredWidth();
+ ? thumbnailView.getMeasuredHeight()
+ : thumbnailView.getMeasuredWidth();
}
@Override
@@ -305,38 +306,6 @@
}
@Override
- public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) {
- BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams();
- lp.topMargin += margin;
- lp.leftMargin += margin;
- }
-
- @Override
- public PointF getAdditionalInsetForTaskMenu(float margin) {
- return new PointF(0, 0);
- }
-
- @Override
- public void setSecondaryTaskMenuPosition(SplitBounds splitBounds, View taskView,
- DeviceProfile deviceProfile, View primarySnaphotView, View taskMenuView) {
- float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically
- ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent)
- : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent);
- FrameLayout.LayoutParams snapshotParams =
- (FrameLayout.LayoutParams) primarySnaphotView.getLayoutParams();
- float additionalOffset;
- if (deviceProfile.isLandscape) {
- additionalOffset = (taskView.getWidth() - snapshotParams.leftMargin)
- * topLeftTaskPlusDividerPercent;
- taskMenuView.setX(taskMenuView.getX() + additionalOffset);
- } else {
- additionalOffset = (taskView.getHeight() - snapshotParams.topMargin)
- * topLeftTaskPlusDividerPercent;
- taskMenuView.setY(taskMenuView.getY() + additionalOffset);
- }
- }
-
- @Override
public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
View[] thumbnailViews, int desiredTaskId, View banner) {
@@ -445,13 +414,9 @@
int screenWidth = dp.widthPx;
int screenHeight = dp.heightPx;
boolean pinToRight = stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT;
- int insetThickness;
- if (!dp.isLandscape) {
- insetThickness = dp.getInsets().top;
- } else {
- insetThickness = pinToRight ? dp.getInsets().right : dp.getInsets().left;
- }
- out.set(0, 0, screenWidth, placeholderHeight + insetThickness);
+ int insetSizeAdjustment = getPlaceholderSizeAdjustment(dp, pinToRight);
+
+ out.set(0, 0, screenWidth, placeholderHeight + insetSizeAdjustment);
if (!dp.isLandscape) {
// portrait, phone or tablet - spans width of screen, nothing else to do
out.inset(placeholderInset, 0);
@@ -496,20 +461,18 @@
int drawableWidth, int drawableHeight, DeviceProfile dp,
@StagePosition int stagePosition) {
boolean pinToRight = stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT;
+ float insetAdjustment = getPlaceholderSizeAdjustment(dp, pinToRight) / 2f;
if (!dp.isLandscape) {
- float inset = dp.getInsets().top;
out.setX(Math.round(onScreenRectCenterX / fullscreenScaleX
- 1.0f * drawableWidth / 2));
- out.setY(Math.round((onScreenRectCenterY + (inset / 2f)) / fullscreenScaleY
+ out.setY(Math.round((onScreenRectCenterY + insetAdjustment) / fullscreenScaleY
- 1.0f * drawableHeight / 2));
} else {
if (pinToRight) {
- float inset = dp.getInsets().right;
- out.setX(Math.round((onScreenRectCenterX - (inset / 2f)) / fullscreenScaleX
+ out.setX(Math.round((onScreenRectCenterX - insetAdjustment) / fullscreenScaleX
- 1.0f * drawableWidth / 2));
} else {
- float inset = dp.getInsets().left;
- out.setX(Math.round((onScreenRectCenterX + (inset / 2f)) / fullscreenScaleX
+ out.setX(Math.round((onScreenRectCenterX + insetAdjustment) / fullscreenScaleX
- 1.0f * drawableWidth / 2));
}
out.setY(Math.round(onScreenRectCenterY / fullscreenScaleY
@@ -517,6 +480,20 @@
}
}
+ /**
+ * The split placeholder comes with a default inset to buffer the icon from the top of the
+ * screen. But if the device already has a large inset (from cutouts etc), use that instead.
+ */
+ private int getPlaceholderSizeAdjustment(DeviceProfile dp, boolean pinToRight) {
+ int insetThickness;
+ if (!dp.isLandscape) {
+ insetThickness = dp.getInsets().top;
+ } else {
+ insetThickness = pinToRight ? dp.getInsets().right : dp.getInsets().left;
+ }
+ return Math.max(insetThickness - dp.splitPlaceholderInset, 0);
+ }
+
@Override
public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
int splitInstructionsWidth, int threeButtonNavShift) {
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index a616a8b..05683bd 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
import android.content.res.Resources;
@@ -33,7 +34,6 @@
import android.view.Surface;
import android.view.View;
import android.widget.FrameLayout;
-import android.widget.LinearLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
@@ -85,26 +85,22 @@
}
@Override
- public float getTaskMenuX(float x, View thumbnailView, int overScroll,
- DeviceProfile deviceProfile) {
- return x;
+ public float getTaskMenuX(float x, View thumbnailView,
+ DeviceProfile deviceProfile, float taskInsetMargin) {
+ return x + taskInsetMargin;
}
@Override
- public float getTaskMenuY(float y, View thumbnailView, int overScroll) {
- return y + overScroll +
- (thumbnailView.getMeasuredHeight() + thumbnailView.getMeasuredWidth()) / 2f;
- }
-
- @Override
- public void setTaskMenuAroundTaskView(LinearLayout taskView, float margin) {
- BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskView.getLayoutParams();
- lp.bottomMargin += margin;
- }
-
- @Override
- public PointF getAdditionalInsetForTaskMenu(float margin) {
- return new PointF(-margin, margin);
+ public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
+ View taskMenuView, float taskInsetMargin) {
+ BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
+ int taskMenuWidth = lp.width;
+ if (stagePosition == STAGE_POSITION_UNDEFINED) {
+ return y + taskInsetMargin
+ + (thumbnailView.getMeasuredHeight() + taskMenuWidth) / 2f;
+ } else {
+ return y + taskMenuWidth + taskInsetMargin;
+ }
}
@Override
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 88e1b22..3eff783 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -100,6 +100,7 @@
* with the same name/functionality in wm.shell.util (which launcher3 cannot be built against)
*
* If you make changes here, consider making the same changes there
+ * TODO(b/254378592): We really need to consolidate this
*/
public static class SplitBounds {
public final Rect leftTopBounds;