From c9e1e1d340e794983916c9203f05fe3f20af4073 Mon Sep 17 00:00:00 2001 From: Lyn Han Date: Wed, 15 Jul 2020 17:08:12 -0500 Subject: [PATCH] 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 --- .../systemui/bubbles/BubbleOverflow.java | 179 ------------------ .../systemui/bubbles/BubbleOverflow.kt | 163 ++++++++++++++++ .../systemui/bubbles/BubbleStackView.java | 38 ++-- 3 files changed, 181 insertions(+), 199 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java create mode 100644 packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.kt 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 bb9d1095a37a5..0000000000000 --- 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 0000000000000..155b71b99ff92 --- /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 f02945ef843a7..75c6385c22a36 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 @@ public class BubbleStackView extends FrameLayout 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 @@ public class BubbleStackView extends FrameLayout (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 @@ public class BubbleStackView extends FrameLayout 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 @@ public class BubbleStackView extends FrameLayout /** 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);