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 @@ + + + +