diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 0926b19b70..e4f65554a4 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -363,6 +363,7 @@
50dp
24dp
12dp
+ 24dp
3dp
1dp
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 6d196924b3..2bd6fcbcd2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -38,11 +38,15 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
+import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Path;
+import android.graphics.drawable.AdaptiveIconDrawable;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.InsetDrawable;
import android.os.Bundle;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -51,6 +55,8 @@ import android.util.Log;
import android.util.PathParser;
import android.view.LayoutInflater;
+import androidx.appcompat.content.res.AppCompatResources;
+
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.R;
import com.android.launcher3.icons.BitmapInfo;
@@ -113,7 +119,8 @@ public class BubbleBarController extends IBubblesListener.Stub {
private final LauncherApps mLauncherApps;
private final BubbleIconFactory mIconFactory;
- private BubbleBarBubble mSelectedBubble;
+ private BubbleBarItem mSelectedBubble;
+ private BubbleBarOverflow mOverflowBubble;
private BubbleBarViewController mBubbleBarViewController;
private BubbleStashController mBubbleStashController;
@@ -178,6 +185,16 @@ public class BubbleBarController extends IBubblesListener.Stub {
mBubbleBarViewController.setHiddenForBubbles(!BUBBLE_BAR_ENABLED);
mBubbleStashedHandleViewController.setHiddenForBubbles(!BUBBLE_BAR_ENABLED);
});
+
+ BUBBLE_STATE_EXECUTOR.execute(() -> {
+ if (mOverflowBubble == null) {
+ BubbleBarOverflow overflow = createOverflow(mContext);
+ mMainExecutor.execute(() -> {
+ mBubbleBarViewController.addBubble(overflow);
+ mOverflowBubble = overflow;
+ });
+ }
+ });
}
/**
@@ -329,7 +346,7 @@ public class BubbleBarController extends IBubblesListener.Stub {
* WMShell that the selection has changed, that should go through
* {@link SystemUiProxy#showBubble}.
*/
- public void setSelectedBubble(BubbleBarBubble b) {
+ public void setSelectedBubble(BubbleBarItem b) {
if (!Objects.equals(b, mSelectedBubble)) {
if (DEBUG) Log.w(TAG, "selectingBubble: " + b.getKey());
mSelectedBubble = b;
@@ -424,7 +441,6 @@ public class BubbleBarController extends IBubblesListener.Stub {
dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
Color.WHITE, WHITE_SCRIM_ALPHA);
-
LayoutInflater inflater = LayoutInflater.from(context);
BubbleView bubbleView = (BubbleView) inflater.inflate(
R.layout.bubblebar_item_view, bbv, false /* attachToRoot */);
@@ -434,4 +450,37 @@ public class BubbleBarController extends IBubblesListener.Stub {
bubbleView.setBubble(bubble);
return bubble;
}
+
+ private BubbleBarOverflow createOverflow(Context context) {
+ Bitmap bitmap = createOverflowBitmap(context);
+ LayoutInflater inflater = LayoutInflater.from(context);
+ BubbleView bubbleView = (BubbleView) inflater.inflate(
+ R.layout.bubblebar_item_view, mBarView, false /* attachToRoot */);
+ BubbleBarOverflow overflow = new BubbleBarOverflow(bubbleView);
+ bubbleView.setOverflow(overflow, bitmap);
+ return overflow;
+ }
+
+ private Bitmap createOverflowBitmap(Context context) {
+ Drawable iconDrawable = AppCompatResources.getDrawable(mContext,
+ R.drawable.bubble_ic_overflow_button);
+
+ final TypedArray ta = mContext.obtainStyledAttributes(
+ new int[]{
+ com.android.internal.R.attr.materialColorOnPrimaryFixed,
+ com.android.internal.R.attr.materialColorPrimaryFixed
+ });
+ int overflowIconColor = ta.getColor(0, Color.WHITE);
+ int overflowBackgroundColor = ta.getColor(1, Color.BLACK);
+ ta.recycle();
+
+ iconDrawable.setTint(overflowIconColor);
+
+ int inset = context.getResources().getDimensionPixelSize(R.dimen.bubblebar_overflow_inset);
+ Drawable foreground = new InsetDrawable(iconDrawable, inset);
+ Drawable drawable = new AdaptiveIconDrawable(new ColorDrawable(overflowBackgroundColor),
+ foreground);
+
+ return mIconFactory.createBadgedIconBitmap(drawable).icon;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBubble.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
similarity index 75%
rename from quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBubble.kt
rename to quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
index 3cd5f75934..942a0a199a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBubble.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarItem.kt
@@ -19,16 +19,19 @@ import android.graphics.Bitmap
import android.graphics.Path
import com.android.wm.shell.common.bubbles.BubbleInfo
+/** An entity in the bubble bar. */
+sealed class BubbleBarItem(open val key: String, open val view: BubbleView)
+
/** Contains state info about a bubble in the bubble bar as well as presentation information. */
data class BubbleBarBubble(
val info: BubbleInfo,
- val view: BubbleView,
+ override val view: BubbleView,
val badge: Bitmap,
val icon: Bitmap,
val dotColor: Int,
val dotPath: Path,
val appName: String
-) {
+) : BubbleBarItem(info.key, view)
- val key: String = info.key
-}
+/** Represents the overflow bubble in the bubble bar. */
+data class BubbleBarOverflow(override val view: BubbleView) : BubbleBarItem("overflow", view)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 37861896e0..52c144ed4d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -101,7 +101,7 @@ public class BubbleBarViewController {
}
private void onBubbleClicked(View v) {
- BubbleBarBubble bubble = ((BubbleView) v).getBubble();
+ BubbleBarItem bubble = ((BubbleView) v).getBubble();
if (bubble == null) {
Log.e(TAG, "bubble click listener, bubble was null");
}
@@ -236,7 +236,7 @@ public class BubbleBarViewController {
/**
* Removes the provided bubble from the bubble bar.
*/
- public void removeBubble(BubbleBarBubble b) {
+ public void removeBubble(BubbleBarItem b) {
if (b != null) {
mBarView.removeView(b.getView());
} else {
@@ -247,7 +247,7 @@ public class BubbleBarViewController {
/**
* Adds the provided bubble to the bubble bar.
*/
- public void addBubble(BubbleBarBubble b) {
+ public void addBubble(BubbleBarItem b) {
if (b != null) {
mBarView.addView(b.getView(), 0, new FrameLayout.LayoutParams(mIconSize, mIconSize));
b.getView().setOnClickListener(mBubbleClickListener);
@@ -268,7 +268,7 @@ public class BubbleBarViewController {
/**
* Updates the selected bubble.
*/
- public void updateSelectedBubble(BubbleBarBubble newlySelected) {
+ public void updateSelectedBubble(BubbleBarItem newlySelected) {
mBarView.setSelectedBubble(newlySelected.getView());
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index e22e63aa36..92b76a6f85 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -32,6 +32,7 @@ import com.android.launcher3.icons.IconNormalizer;
// TODO: (b/276978250) This is will be similar to WMShell's BadgedImageView, it'd be nice to share.
// TODO: (b/269670235) currently this doesn't show the 'update dot'
+
/**
* View that displays a bubble icon, along with an app badge on either the left or
* right side of the view.
@@ -48,7 +49,7 @@ public class BubbleView extends ConstraintLayout {
// TODO: (b/273310265) handle RTL
private boolean mOnLeft = false;
- private BubbleBarBubble mBubble;
+ private BubbleBarItem mBubble;
public BubbleView(Context context) {
this(context, null);
@@ -97,15 +98,27 @@ public class BubbleView extends ConstraintLayout {
mAppIcon.setImageBitmap(bubble.getBadge());
}
+ void setOverflow(BubbleBarOverflow overflow, Bitmap bitmap) {
+ mBubble = overflow;
+ mBubbleIcon.setImageBitmap(bitmap);
+ hideBadge();
+ }
+
/** Returns the bubble being rendered in this view. */
@Nullable
- BubbleBarBubble getBubble() {
+ BubbleBarItem getBubble() {
return mBubble;
}
/** Shows the app badge on this bubble. */
void showBadge() {
- Bitmap appBadgeBitmap = mBubble.getBadge();
+ if (mBubble instanceof BubbleBarOverflow) {
+ // The overflow bubble does not have a badge, so just bail.
+ return;
+ }
+ BubbleBarBubble bubble = (BubbleBarBubble) mBubble;
+
+ Bitmap appBadgeBitmap = bubble.getBadge();
if (appBadgeBitmap == null) {
mAppIcon.setVisibility(GONE);
return;
@@ -113,7 +126,7 @@ public class BubbleView extends ConstraintLayout {
int translationX;
if (mOnLeft) {
- translationX = -(mBubble.getIcon().getWidth() - appBadgeBitmap.getWidth());
+ translationX = -(bubble.getIcon().getWidth() - appBadgeBitmap.getWidth());
} else {
translationX = 0;
}
diff --git a/res/drawable/bubble_ic_overflow_button.xml b/res/drawable/bubble_ic_overflow_button.xml
new file mode 100644
index 0000000000..475639e2e2
--- /dev/null
+++ b/res/drawable/bubble_ic_overflow_button.xml
@@ -0,0 +1,24 @@
+
+
+
+