Reorder overflow button with kotlin refactor
Add overflow button when overflow is created
Reorder overflow button instead of remove+add
Convert overflow view provider to kotlin
Bug: 161396059
Test: toggle all themes, display size; dismiss single bubble /
entire stack; promote bubble from overflow: no regressions
Change-Id: Iee68c982d1591de4f010aac6c620c7353737bc11
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
deleted file mode 100644
index bb9d109..0000000
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2020 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.systemui.bubbles;
-
-import static android.view.Display.INVALID_DISPLAY;
-import static android.view.View.GONE;
-
-import static com.android.systemui.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
-
-import android.content.Context;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Matrix;
-import android.graphics.Path;
-import android.graphics.drawable.AdaptiveIconDrawable;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.InsetDrawable;
-import android.util.PathParser;
-import android.util.TypedValue;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-
-import com.android.systemui.R;
-
-/**
- * Class for showing aged out bubbles.
- */
-public class BubbleOverflow implements BubbleViewProvider {
- public static final String KEY = "Overflow";
-
- private BadgedImageView mOverflowBtn;
- private BubbleExpandedView mExpandedView;
- private LayoutInflater mInflater;
- private Context mContext;
- private Bitmap mIcon;
- private Path mPath;
- private int mBitmapSize;
- private int mIconBitmapSize;
- private int mDotColor;
-
- public BubbleOverflow(Context context) {
- mContext = context;
- mInflater = LayoutInflater.from(context);
- }
-
- void setUpOverflow(ViewGroup parentViewGroup, BubbleStackView stackView) {
- updateDimensions();
- mExpandedView = (BubbleExpandedView) mInflater.inflate(
- R.layout.bubble_expanded_view, parentViewGroup /* root */,
- false /* attachToRoot */);
- mExpandedView.setOverflow(true);
- mExpandedView.setStackView(stackView);
- mExpandedView.applyThemeAttrs();
- updateIcon(mContext, parentViewGroup);
- }
-
- void updateDimensions() {
- mBitmapSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size);
- mIconBitmapSize = mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_overflow_icon_bitmap_size);
- if (mExpandedView != null) {
- mExpandedView.updateDimensions();
- }
- }
-
- void updateIcon(Context context, ViewGroup parentViewGroup) {
- mContext = context;
- mInflater = LayoutInflater.from(context);
- mOverflowBtn = (BadgedImageView) mInflater.inflate(R.layout.bubble_overflow_button,
- parentViewGroup /* root */,
- false /* attachToRoot */);
- mOverflowBtn.setContentDescription(mContext.getResources().getString(
- R.string.bubble_overflow_button_content_description));
- Resources res = mContext.getResources();
-
- // Set color for button icon and dot
- TypedValue typedValue = new TypedValue();
- mContext.getTheme().resolveAttribute(android.R.attr.colorAccent, typedValue, true);
- int colorAccent = mContext.getColor(typedValue.resourceId);
- mOverflowBtn.getDrawable().setTint(colorAccent);
- mDotColor = colorAccent;
-
- // Set color for button and activity background
- ColorDrawable bg = new ColorDrawable(res.getColor(R.color.bubbles_light));
- final int mode = res.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
- if (mode == Configuration.UI_MODE_NIGHT_YES) {
- bg = new ColorDrawable(res.getColor(R.color.bubbles_dark));
- }
-
- // Apply icon inset
- InsetDrawable fg = new InsetDrawable(mOverflowBtn.getDrawable(),
- mBitmapSize - mIconBitmapSize /* inset */);
- AdaptiveIconDrawable adaptiveIconDrawable = new AdaptiveIconDrawable(bg, fg);
-
- BubbleIconFactory iconFactory = new BubbleIconFactory(mContext);
- mIcon = iconFactory.createBadgedIconBitmap(adaptiveIconDrawable,
- null /* user */,
- true /* shrinkNonAdaptiveIcons */).icon;
-
- // Get path with dot location
- float scale = iconFactory.getNormalizer().getScale(mOverflowBtn.getDrawable(),
- null /* outBounds */, null /* path */, null /* outMaskShape */);
- float radius = DEFAULT_PATH_SIZE / 2f;
- mPath = PathParser.createPathFromPathData(
- mContext.getResources().getString(com.android.internal.R.string.config_icon_mask));
- Matrix matrix = new Matrix();
- matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
- radius /* pivot y */);
- mPath.transform(matrix);
-
- mOverflowBtn.setRenderedBubble(this);
- }
-
- void setVisible(int visible) {
- mOverflowBtn.setVisibility(visible);
- }
-
- @Override
- public BubbleExpandedView getExpandedView() {
- return mExpandedView;
- }
-
- @Override
- public int getDotColor() {
- return mDotColor;
- }
-
- @Override
- public Bitmap getBadgedImage() {
- return mIcon;
- }
-
- @Override
- public boolean showDot() {
- return false;
- }
-
- @Override
- public Path getDotPath() {
- return mPath;
- }
-
- @Override
- public void setContentVisibility(boolean visible) {
- mExpandedView.setContentVisibility(visible);
- }
-
- @Override
- public View getIconView() {
- return mOverflowBtn;
- }
-
- @Override
- public String getKey() {
- return BubbleOverflow.KEY;
- }
-
- @Override
- public int getDisplayId() {
- return mExpandedView != null ? mExpandedView.getVirtualDisplayId() : INVALID_DISPLAY;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
new file mode 100644
index 0000000..155b71b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2020 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.systemui.bubbles
+
+import android.content.Context
+import android.content.res.Configuration
+import android.graphics.Bitmap
+import android.graphics.Matrix
+import android.graphics.Path
+import android.graphics.drawable.AdaptiveIconDrawable
+import android.graphics.drawable.ColorDrawable
+import android.graphics.drawable.InsetDrawable
+import android.util.PathParser
+import android.util.TypedValue
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import com.android.systemui.R
+
+class BubbleOverflow(
+ private val context: Context,
+ private val stack: BubbleStackView
+) : BubbleViewProvider {
+
+ private var bitmap: Bitmap? = null
+ private var dotPath: Path? = null
+ private var bitmapSize = 0
+ private var iconBitmapSize = 0
+ private var dotColor = 0
+
+ private val inflater: LayoutInflater = LayoutInflater.from(context)
+ private val expandedView: BubbleExpandedView = inflater
+ .inflate(R.layout.bubble_expanded_view, null /* root */, false /* attachToRoot */)
+ as BubbleExpandedView
+ private val overflowBtn: BadgedImageView = inflater
+ .inflate(R.layout.bubble_overflow_button, null /* root */, false /* attachToRoot */)
+ as BadgedImageView
+ init {
+ updateResources()
+ with(expandedView) {
+ setOverflow(true)
+ setStackView(stack)
+ applyThemeAttrs()
+ }
+ with(overflowBtn) {
+ setContentDescription(context.resources.getString(
+ R.string.bubble_overflow_button_content_description))
+ updateBtnTheme()
+ }
+ }
+
+ fun update() {
+ updateResources()
+ expandedView.applyThemeAttrs()
+ // Apply inset and new style to fresh icon drawable.
+ overflowBtn.setImageResource(R.drawable.ic_bubble_overflow_button)
+ updateBtnTheme()
+ }
+
+ fun updateResources() {
+ bitmapSize = context.resources.getDimensionPixelSize(R.dimen.bubble_bitmap_size)
+ iconBitmapSize = context.resources.getDimensionPixelSize(
+ R.dimen.bubble_overflow_icon_bitmap_size)
+ val bubbleSize = context.resources.getDimensionPixelSize(R.dimen.individual_bubble_size)
+ overflowBtn.setLayoutParams(FrameLayout.LayoutParams(bubbleSize, bubbleSize))
+ expandedView.updateDimensions()
+ }
+
+ fun updateBtnTheme() {
+ val res = context.resources
+
+ // Set overflow button accent color, dot color
+ val typedValue = TypedValue()
+ context.theme.resolveAttribute(android.R.attr.colorAccent, typedValue, true)
+
+ val colorAccent = res.getColor(typedValue.resourceId)
+ overflowBtn.getDrawable()?.setTint(colorAccent)
+ dotColor = colorAccent
+
+ // Set button and activity background color
+ val nightMode = (res.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+ == Configuration.UI_MODE_NIGHT_YES)
+ val bg = ColorDrawable(res.getColor(
+ if (nightMode) R.color.bubbles_dark else R.color.bubbles_light))
+
+ // Set button icon
+ val iconFactory = BubbleIconFactory(context)
+ val fg = InsetDrawable(overflowBtn.getDrawable(),
+ bitmapSize - iconBitmapSize /* inset */)
+ bitmap = iconFactory.createBadgedIconBitmap(AdaptiveIconDrawable(bg, fg),
+ null /* user */, true /* shrinkNonAdaptiveIcons */).icon
+
+ // Set dot path
+ dotPath = PathParser.createPathFromPathData(
+ res.getString(com.android.internal.R.string.config_icon_mask))
+ val scale = iconFactory.normalizer.getScale(overflowBtn.getDrawable(),
+ null /* outBounds */, null /* path */, null /* outMaskShape */)
+ val radius = BadgedImageView.DEFAULT_PATH_SIZE / 2f
+ val matrix = Matrix()
+ matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
+ radius /* pivot y */)
+ dotPath?.transform(matrix)
+ overflowBtn.setRenderedBubble(this)
+ }
+
+ fun setVisible(visible: Int) {
+ overflowBtn.visibility = visible
+ }
+
+ override fun getExpandedView(): BubbleExpandedView? {
+ return expandedView
+ }
+
+ override fun getDotColor(): Int {
+ return dotColor
+ }
+
+ override fun getBadgedImage(): Bitmap? {
+ return bitmap
+ }
+
+ override fun showDot(): Boolean {
+ return false
+ }
+
+ override fun getDotPath(): Path? {
+ return dotPath
+ }
+
+ override fun setContentVisibility(visible: Boolean) {
+ expandedView.setContentVisibility(visible)
+ }
+
+ override fun getIconView(): View? {
+ return overflowBtn
+ }
+
+ override fun getKey(): String {
+ return KEY
+ }
+
+ override fun getDisplayId(): Int {
+ return expandedView.virtualDisplayId
+ }
+
+ companion object {
+ @JvmField val KEY = "Overflow"
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index f02945e..75c6385 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -907,7 +907,16 @@
setFocusable(true);
mBubbleContainer.bringToFront();
- setUpOverflow();
+ mBubbleOverflow = new BubbleOverflow(getContext(), this);
+ mBubbleContainer.addView(mBubbleOverflow.getIconView(),
+ mBubbleContainer.getChildCount() /* index */,
+ new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ updateOverflow();
+ mBubbleOverflow.getIconView().setOnClickListener((View v) -> {
+ setSelectedBubble(mBubbleOverflow);
+ showManageMenu(false);
+ });
mOnImeVisibilityChanged = onImeVisibilityChanged;
mHideCurrentInputMethodCallback = hideCurrentInputMethodCallback;
@@ -933,7 +942,7 @@
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
mExpandedAnimationController.updateResources(mOrientation, mDisplaySize);
mStackAnimationController.updateResources(mOrientation);
- mBubbleOverflow.updateDimensions();
+ mBubbleOverflow.updateResources();
// Need to update the padding around the view
WindowInsets insets = getRootWindowInsets();
@@ -1187,32 +1196,21 @@
addView(mFlyout, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
}
- private void setUpOverflow() {
- int overflowBtnIndex = 0;
- if (mBubbleOverflow == null) {
- mBubbleOverflow = new BubbleOverflow(getContext());
- mBubbleOverflow.setUpOverflow(mBubbleContainer, this);
- } else {
- mBubbleContainer.removeView(mBubbleOverflow.getIconView());
- mBubbleOverflow.setUpOverflow(mBubbleContainer, this);
- overflowBtnIndex = mBubbleContainer.getChildCount();
- }
- mBubbleContainer.addView(mBubbleOverflow.getIconView(), overflowBtnIndex,
- new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
- mBubbleOverflow.getIconView().setOnClickListener(v -> {
- setSelectedBubble(mBubbleOverflow);
- showManageMenu(false);
- });
+ private void updateOverflow() {
+ mBubbleOverflow.update();
+ mBubbleContainer.reorderView(mBubbleOverflow.getIconView(),
+ mBubbleContainer.getChildCount() - 1 /* index */);
updateOverflowVisibility();
}
+
/**
* Handle theme changes.
*/
public void onThemeChanged() {
setUpFlyout();
- setUpOverflow();
setUpUserEducation();
setUpManageMenu();
+ updateOverflow();
updateExpandedViewTheme();
}
@@ -1261,7 +1259,7 @@
/** Respond to the display size change by recalculating view size and location. */
public void onDisplaySizeChanged() {
- setUpOverflow();
+ updateOverflow();
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getRealSize(mDisplaySize);