Draw leave-behind circle after pressing taskbar overflow button
This CL does not include animating app icons / leave behind circle.
Bug: 376281549
Flag: com.android.launcher3.taskbar_overflow
Test: press the oveflow button, dismiss KQS in different ways
Change-Id: I1f830c6859a5be4fb5947ec38e6d30da79138b7f
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index 711a49a..23a5a27 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -54,6 +54,8 @@
public static final int MAX_TASKS = 6;
@NonNull private final ControllerCallbacks mControllerCallbacks = new ControllerCallbacks();
+ // Callback used to notify when the KQS view is closed.
+ @Nullable private Runnable mOnClosed;
// Initialized on init
@Nullable private RecentsModel mModel;
@@ -112,8 +114,12 @@
* Opens or closes the view in response to taskbar action. The view shows a filtered list of
* tasks.
* @param taskIdsToExclude A list of tasks to exclude in the opened view.
+ * @param onClosed A callback used to notify when the KQS view is closed.
*/
- void toggleQuickSwitchViewForTaskbar(@NonNull Set<Integer> taskIdsToExclude) {
+ void toggleQuickSwitchViewForTaskbar(@NonNull Set<Integer> taskIdsToExclude,
+ @NonNull Runnable onClosed) {
+ mOnClosed = onClosed;
+
// Close the view if its shown, and was opened from the taskbar.
if (mQuickSwitchViewController != null
&& !mQuickSwitchViewController.isCloseAnimationRunning()
@@ -264,6 +270,10 @@
return;
}
mQuickSwitchViewController.closeQuickSwitchView(animate);
+ if (mOnClosed != null) {
+ mOnClosed.run();
+ mOnClosed = null;
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
index fad5ca3..126e9bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
@@ -25,10 +25,13 @@
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.R;
import com.android.launcher3.Reorderable;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.MultiTranslateDelegate;
+import com.android.launcher3.util.Themes;
import com.android.systemui.shared.recents.model.Task;
import java.util.ArrayList;
@@ -42,12 +45,22 @@
* each other in counter clockwise manner (icons of tasks partially overlapping with each other).
*/
public class TaskbarOverflowView extends FrameLayout implements Reorderable {
+ private static final int MAX_ITEMS_IN_PREVIEW = 4;
+
+ private boolean mIsRtlLayout;
private final List<Task> mItems = new ArrayList<Task>();
private int mIconSize;
private int mPadding;
private Paint mItemBackgroundPaint;
private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
private float mScaleForReorderBounce = 1f;
+ private int mItemBackgroundColor;
+ private int mLeaveBehindColor;
+ private float mItemPreviewStrokeWidth;
+
+ // Active means the overflow icon has been pressed, which replaces the app icons with the
+ // leave-behind circle and shows the KQS UI.
+ private boolean mIsActive = false;
public TaskbarOverflowView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -78,22 +91,32 @@
}
private void init() {
+ mIsRtlLayout = Utilities.isRtl(getResources());
mItemBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
- mItemBackgroundPaint.setColor(getContext().getColor(R.color.taskbar_background));
+ mItemBackgroundColor = getContext().getColor(R.color.taskbar_background);
+ mLeaveBehindColor = Themes.getAttrColor(getContext(), android.R.attr.textColorTertiary);
+ mItemPreviewStrokeWidth = getResources().getDimension(
+ R.dimen.taskbar_overflow_button_preview_stroke);
setWillNotDraw(false);
}
@Override
- protected void onDraw(Canvas canvas) {
+ protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
- boolean isRtlLayout = Utilities.isRtl(getResources());
- float radius = mIconSize / 2.0f - mPadding;
- float itemPreviewStrokeWidth =
- getResources().getDimension(R.dimen.taskbar_overflow_button_preview_stroke);
+ if (mIsActive) {
+ drawLeaveBehindCircle(canvas);
+ } else {
+ drawAppIcons(canvas);
+ }
+ }
- int itemsToShow = Math.min(mItems.size(), 4);
+ private void drawAppIcons(@NonNull Canvas canvas) {
+ mItemBackgroundPaint.setColor(mItemBackgroundColor);
+ float radius = mIconSize / 2f - mPadding;
+
+ int itemsToShow = Math.min(mItems.size(), MAX_ITEMS_IN_PREVIEW);
for (int i = itemsToShow - 1; i >= 0; --i) {
Drawable icon = mItems.get(mItems.size() - i - 1).icon;
if (icon == null) {
@@ -103,11 +126,11 @@
// Set the item icon size so two items fit within the overflow icon with stroke width
// included, and overlap of 4 stroke width sizes between base item preview items.
// 2 * strokeWidth + 2 * itemIconSize - 4 * strokeWidth = iconSize = 2 * radius.
- float itemIconSize = radius + itemPreviewStrokeWidth;
- // Offset item icon from center so item icon stroke edge mateches the parent icon edge.
- float itemCenterOffset = radius - itemIconSize / 2 - itemPreviewStrokeWidth;
+ float itemIconSize = radius + mItemPreviewStrokeWidth;
+ // Offset item icon from center so item icon stroke edge matches the parent icon edge.
+ float itemCenterOffset = radius - itemIconSize / 2 - mItemPreviewStrokeWidth;
- float itemCenterX = getItemXOffset(itemCenterOffset, isRtlLayout, i, itemsToShow);
+ float itemCenterX = getItemXOffset(itemCenterOffset, mIsRtlLayout, i, itemsToShow);
float itemCenterY = getItemYOffset(itemCenterOffset, i, itemsToShow);
Drawable iconCopy = icon.getConstantState().newDrawable().mutate();
@@ -119,12 +142,19 @@
mPadding + itemCenterX + radius - itemIconRadius,
mPadding + itemCenterY + radius - itemIconRadius);
canvas.drawCircle(itemIconRadius, itemIconRadius,
- itemIconRadius + itemPreviewStrokeWidth, mItemBackgroundPaint);
+ itemIconRadius + mItemPreviewStrokeWidth, mItemBackgroundPaint);
iconCopy.draw(canvas);
canvas.restore();
}
}
+ private void drawLeaveBehindCircle(@NonNull Canvas canvas) {
+ mItemBackgroundPaint.setColor(mLeaveBehindColor);
+
+ final var xyCenter = mIconSize / 2f;
+ canvas.drawCircle(xyCenter, xyCenter, mIconSize / 4f, mItemBackgroundPaint);
+ }
+
/**
* Clears the list of tasks tracked by the view.
*/
@@ -153,7 +183,7 @@
for (int i = 0; i < mItems.size(); ++i) {
if (mItems.get(i).key.id == task.key.id) {
mItems.set(i, task);
- if (i >= mItems.size() - 4) {
+ if (i >= mItems.size() - MAX_ITEMS_IN_PREVIEW) {
invalidate();
}
break;
@@ -161,6 +191,24 @@
}
}
+ /**
+ * Returns the view's state (whether it shows a set of app icons or a leave-behind circle).
+ */
+ public boolean getIsActive() {
+ return mIsActive;
+ }
+
+ /**
+ * Updates the view's state to draw either a set of app icons or a leave-behind circle.
+ * @param isActive The next state of the view.
+ */
+ public void setIsActive(boolean isActive) {
+ if (mIsActive != isActive) {
+ mIsActive = isActive;
+ invalidate();
+ }
+ }
+
@Override
public MultiTranslateDelegate getTranslateDelegate() {
return mTranslateDelegate;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index 5d769d2..834f92e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -148,8 +148,7 @@
return new View.OnClickListener() {
@Override
public void onClick(View v) {
- mControllers.keyboardQuickSwitchController.toggleQuickSwitchViewForTaskbar(
- mControllers.taskbarViewController.getTaskIdsForPinnedApps());
+ toggleKeyboardQuickSwitchView();
}
};
}
@@ -159,13 +158,28 @@
return new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
- mControllers.keyboardQuickSwitchController.toggleQuickSwitchViewForTaskbar(
- mControllers.taskbarViewController.getTaskIdsForPinnedApps());
+ toggleKeyboardQuickSwitchView();
return true;
}
};
}
+ private void toggleKeyboardQuickSwitchView() {
+ if (mTaskbarView.getTaskbarOverflowView() != null) {
+ mTaskbarView.getTaskbarOverflowView().setIsActive(
+ !mTaskbarView.getTaskbarOverflowView().getIsActive());
+ }
+ mControllers.keyboardQuickSwitchController.toggleQuickSwitchViewForTaskbar(
+ mControllers.taskbarViewController.getTaskIdsForPinnedApps(),
+ this::onKeyboardQuickSwitchViewClosed);
+ }
+
+ private void onKeyboardQuickSwitchViewClosed() {
+ if (mTaskbarView.getTaskbarOverflowView() != null) {
+ mTaskbarView.getTaskbarOverflowView().setIsActive(false);
+ }
+ }
+
private float getDividerCenterX() {
View divider = mTaskbarView.getTaskbarDividerViewContainer();
if (divider == null) {