diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index 91a8ab5f692f1..bfc646bf6f8f5 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -113,6 +113,7 @@ android_library { "androidx.lifecycle_lifecycle-extensions", "androidx.dynamicanimation_dynamicanimation", "androidx-constraintlayout_constraintlayout", + "iconloader_base", "SystemUI-tags", "SystemUI-proto", "metrics-helper-lib", diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 47b9e9e27ae69..919844e387265 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1110,7 +1110,9 @@ 16dp - 52dp + 60dp + + 52dp 56dp @@ -1142,9 +1144,9 @@ 5dp - 5dp + 9dp - 100dp + 96dp 48dp diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.java index c91ba34f6dbff..f0f351fa25fea 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgeRenderer.java @@ -55,9 +55,9 @@ public class BadgeRenderer { /** Space between the center of the dot and the top or left of the bubble stack. */ static float getDotCenterOffset(Context context) { - final int iconSizePx = - context.getResources().getDimensionPixelSize(R.dimen.individual_bubble_size); - return SIZE_PERCENTAGE * iconSizePx; + final int iconBitmapSize = + context.getResources().getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size); + return SIZE_PERCENTAGE * iconBitmapSize; } static float getDotRadius(float dotCenterOffset) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java index 783780f8819c6..d2fd13e3ad00a 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BadgedImageView.java @@ -32,7 +32,8 @@ import com.android.systemui.R; public class BadgedImageView extends ImageView { private BadgeRenderer mDotRenderer; - private int mIconSize; + private int mIconBitmapSize; + private Rect mTempBounds = new Rect(); private Point mTempPoint = new Point(); @@ -56,7 +57,7 @@ public class BadgedImageView extends ImageView { public BadgedImageView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - mIconSize = getResources().getDimensionPixelSize(R.dimen.individual_bubble_size); + mIconBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size); mDotRenderer = new BadgeRenderer(getContext()); TypedArray ta = context.obtainStyledAttributes( @@ -69,7 +70,7 @@ public class BadgedImageView extends ImageView { super.onDraw(canvas); if (mShowUpdateDot) { getDrawingRect(mTempBounds); - mTempPoint.set((getWidth() - mIconSize) / 2, getPaddingTop()); + mTempPoint.set((getWidth() - mIconBitmapSize) / 2, getPaddingTop()); mDotRenderer.draw(canvas, mUpdateDotColor, mTempBounds, mDotScale, mTempPoint, mOnLeft); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java index 71f68c16bd8d0..1cf52813632a7 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java @@ -57,6 +57,7 @@ public class BubbleFlyoutView extends FrameLayout { private final int mFlyoutSpaceFromBubble; private final int mPointerSize; private final int mBubbleSize; + private final int mBubbleIconBitmapSize; private final int mFlyoutElevation; private final int mBubbleElevation; private final int mFloatingBackgroundColor; @@ -143,7 +144,9 @@ public class BubbleFlyoutView extends FrameLayout { mFlyoutPadding = res.getDimensionPixelSize(R.dimen.bubble_flyout_padding_x); mFlyoutSpaceFromBubble = res.getDimensionPixelSize(R.dimen.bubble_flyout_space_from_bubble); mPointerSize = res.getDimensionPixelSize(R.dimen.bubble_flyout_pointer_size); + mBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size); + mBubbleIconBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size); mBubbleElevation = res.getDimensionPixelSize(R.dimen.bubble_elevation); mFlyoutElevation = res.getDimensionPixelSize(R.dimen.bubble_flyout_elevation); mNewDotOffsetFromBubbleBounds = BadgeRenderer.getDotCenterOffset(context); @@ -216,7 +219,8 @@ public class BubbleFlyoutView extends FrameLayout { post(() -> { // Multi line flyouts get top-aligned to the bubble. if (mFlyoutText.getLineCount() > 1) { - setTranslationY(stackPos.y); + float bubbleIconTopPadding = (mBubbleSize - mBubbleIconBitmapSize) / 2f; + setTranslationY(stackPos.y + bubbleIconTopPadding); } else { // Single line flyouts are vertically centered with respect to the bubble. setTranslationY( diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java new file mode 100644 index 0000000000000..dc38d59f8753f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleIconFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 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 com.android.launcher3.icons.BaseIconFactory; + +/** + * Factory for creating normalized bubble icons. + * We are not using Launcher's IconFactory because bubbles only runs on the UI thread, + * so there is no need to manage a pool across multiple threads. + */ +public class BubbleIconFactory extends BaseIconFactory { + protected BubbleIconFactory(Context context, int iconBitmapSize) { + super(context, context.getResources().getConfiguration().densityDpi, iconBitmapSize); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 4e41dced7cab5..6487e422e7d87 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -32,7 +32,6 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; -import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Point; import android.graphics.PointF; @@ -49,7 +48,6 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewOutlineProvider; import android.view.ViewTreeObserver; import android.view.WindowInsets; import android.view.WindowManager; @@ -183,7 +181,7 @@ public class BubbleStackView extends FrameLayout { private int mStatusBarHeight; private int mPipDismissHeight; private int mImeOffset; - + private BubbleIconFactory mBubbleIconFactory; private Bubble mExpandedBubble; private boolean mIsExpanded; private boolean mImeVisible; @@ -284,7 +282,8 @@ public class BubbleStackView extends FrameLayout { } }; - @NonNull private final SurfaceSynchronizer mSurfaceSynchronizer; + @NonNull + private final SurfaceSynchronizer mSurfaceSynchronizer; private BubbleDismissView mDismissContainer; private Runnable mAfterMagnet; @@ -337,6 +336,9 @@ public class BubbleStackView extends FrameLayout { mBubbleContainer.setClipChildren(false); addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); + int iconBitmapSize = getResources().getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size); + mBubbleIconFactory = new BubbleIconFactory(context, iconBitmapSize); + mExpandedViewContainer = new FrameLayout(context); mExpandedViewContainer.setElevation(elevation); mExpandedViewContainer.setPadding(mExpandedViewPadding, mExpandedViewPadding, @@ -455,7 +457,7 @@ public class BubbleStackView extends FrameLayout { * Handle theme changes. */ public void onThemeChanged() { - for (Bubble b: mBubbleData.getBubbles()) { + for (Bubble b : mBubbleData.getBubbles()) { b.iconView.updateViews(); b.expandedView.applyThemeAttrs(); } @@ -618,6 +620,7 @@ public class BubbleStackView extends FrameLayout { /** * Updates the visibility of the 'dot' indicating an update on the bubble. + * * @param key the {@link NotificationEntry#key} associated with the bubble. */ public void updateDotVisibility(String key) { @@ -690,6 +693,9 @@ public class BubbleStackView extends FrameLayout { Log.d(TAG, "addBubble: " + bubble); } bubble.inflate(mInflater, this); + bubble.iconView.setBubbleIconFactory(mBubbleIconFactory); + bubble.iconView.updateViews(); + mBubbleContainer.addView(bubble.iconView, 0, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); ViewClippingUtil.setClippingDeactivated(bubble.iconView, true, mClippingParameters); @@ -796,6 +802,7 @@ public class BubbleStackView extends FrameLayout { /** * Dismiss the stack of bubbles. + * * @deprecated */ @Deprecated @@ -1518,24 +1525,12 @@ public class BubbleStackView extends FrameLayout { /** Sets the appropriate Z-order and dot position for each bubble in the stack. */ private void updateBubbleShadowsAndDotPosition(boolean animate) { - int bubbsCount = mBubbleContainer.getChildCount(); - for (int i = 0; i < bubbsCount; i++) { + int bubbleCount = mBubbleContainer.getChildCount(); + for (int i = 0; i < bubbleCount; i++) { BubbleView bv = (BubbleView) mBubbleContainer.getChildAt(i); bv.updateDotVisibility(true /* animate */); bv.setZ((BubbleController.MAX_BUBBLES * getResources().getDimensionPixelSize(R.dimen.bubble_elevation)) - i); - - // Draw the shadow around the circle inscribed within the bubble's bounds. This - // (intentionally) does not draw a shadow behind the update dot, which should be drawing - // its own shadow since it's on a different (higher) plane. - bv.setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setOval(0, 0, mBubbleSize, mBubbleSize); - } - }); - bv.setClipToOutline(false); - // If the dot is on the left, and so is the stack, we need to change the dot position. if (bv.getDotPositionOnLeft() == mStackOnLeftOrWillBe) { bv.setDotPosition(!mStackOnLeftOrWillBe, animate); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java index 3442245f4f609..697d381162eb3 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java @@ -29,6 +29,7 @@ import android.util.AttributeSet; import android.widget.FrameLayout; import com.android.internal.graphics.ColorUtils; +import com.android.launcher3.icons.BitmapInfo; import com.android.systemui.Interpolators; import com.android.systemui.R; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -41,7 +42,7 @@ public class BubbleView extends FrameLayout { private static final int DARK_ICON_ALPHA = 180; private static final double ICON_MIN_CONTRAST = 4.1; - private static final int DEFAULT_BACKGROUND_COLOR = Color.LTGRAY; + private static final int DEFAULT_BACKGROUND_COLOR = Color.LTGRAY; // Same value as Launcher3 badge code private static final float WHITE_SCRIM_ALPHA = 0.54f; private Context mContext; @@ -50,6 +51,9 @@ public class BubbleView extends FrameLayout { private int mBadgeColor; private int mIconInset; + // mBubbleIconFactory cannot be static because it depends on Context. + private BubbleIconFactory mBubbleIconFactory; + private boolean mSuppressDot = false; private NotificationEntry mEntry; @@ -93,7 +97,6 @@ public class BubbleView extends FrameLayout { */ public void setNotif(NotificationEntry entry) { mEntry = entry; - updateViews(); } /** @@ -120,6 +123,13 @@ public class BubbleView extends FrameLayout { updateViews(); } + /** + * @param factory Factory for creating normalized bubble icons. + */ + public void setBubbleIconFactory(BubbleIconFactory factory) { + mBubbleIconFactory = factory; + } + /** * @return the {@link ExpandableNotificationRow} view to display notification content when the * bubble is expanded. @@ -203,7 +213,7 @@ public class BubbleView extends FrameLayout { } void updateViews() { - if (mEntry == null) { + if (mEntry == null || mBubbleIconFactory == null) { return; } Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata(); @@ -219,10 +229,13 @@ public class BubbleView extends FrameLayout { } Drawable iconDrawable = ic.loadDrawable(mContext); if (needsTint) { - mBadgedImageView.setImageDrawable(buildIconWithTint(iconDrawable, n.color)); - } else { - mBadgedImageView.setImageDrawable(iconDrawable); + iconDrawable = buildIconWithTint(iconDrawable, n.color); } + BitmapInfo bitmapInfo = mBubbleIconFactory.createBadgedIconBitmap(iconDrawable, + null /* user */, + true /* shrinkNonAdaptiveIcons */); + mBadgedImageView.setImageBitmap(bitmapInfo.icon); + int badgeColor = determineDominateColor(iconDrawable, n.color); mBadgeColor = badgeColor; mBadgedImageView.setDotColor(badgeColor); diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java index f111f04cd4f91..b69b94c6d00a9 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java @@ -86,10 +86,12 @@ public class ExpandedAnimationController private boolean mSpringingBubbleToTouch = false; private int mExpandedViewPadding; + private float mLauncherGridDiff; public ExpandedAnimationController(Point displaySize, int expandedViewPadding) { mDisplaySize = displaySize; mExpandedViewPadding = expandedViewPadding; + mLauncherGridDiff = 30f; } /** @@ -438,8 +440,7 @@ public class ExpandedAnimationController * [launcherGridDiff] --- arbitrary value until launcher exports widths * Launcher's app icon grid edge that we must match */ - final float launcherGridDiff = mBubbleSizePx / 2f; - final float rowMargins = (mExpandedViewPadding + launcherGridDiff) * 2; + final float rowMargins = (mExpandedViewPadding + mLauncherGridDiff) * 2; final float maxRowWidth = mDisplaySize.x - rowMargins; final float totalBubbleWidth = mBubblesMaxRendered * mBubbleSizePx; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index 356efc9da12ba..0d9e3b679611b 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -140,7 +140,7 @@ public class StackAnimationController extends /** Horizontal offset of bubbles in the stack. */ private float mStackOffset; /** Diameter of the bubbles themselves. */ - private int mIndividualBubbleSize; + private int mBubbleIconBitmapSize; /** * The amount of space to add between the bubbles and certain UI elements, such as the top of * the screen or the IME. This does not apply to the left/right sides of the screen since the @@ -185,7 +185,7 @@ public class StackAnimationController extends return false; } - float stackCenter = mStackPosition.x + mIndividualBubbleSize / 2; + float stackCenter = mStackPosition.x + mBubbleIconBitmapSize / 2; float screenCenter = mLayout.getWidth() / 2; return stackCenter < screenCenter; } @@ -218,7 +218,7 @@ public class StackAnimationController extends * @return The X value that the stack will end up at after the fling/spring. */ public float flingStackThenSpringToEdge(float x, float velX, float velY) { - final boolean stackOnLeftSide = x - mIndividualBubbleSize / 2 < mLayout.getWidth() / 2; + final boolean stackOnLeftSide = x - mBubbleIconBitmapSize / 2 < mLayout.getWidth() / 2; final boolean stackShouldFlingLeft = stackOnLeftSide ? velX < ESCAPE_VELOCITY @@ -427,7 +427,7 @@ public class StackAnimationController extends : 0); allowableRegion.right = mLayout.getWidth() - - mIndividualBubbleSize + - mBubbleIconBitmapSize + mBubbleOffscreen - Math.max( insets.getSystemWindowInsetRight(), @@ -444,7 +444,7 @@ public class StackAnimationController extends : 0); allowableRegion.bottom = mLayout.getHeight() - - mIndividualBubbleSize + - mBubbleIconBitmapSize - mBubblePaddingTop - (mImeHeight > Float.MIN_VALUE ? mImeHeight + mBubblePaddingTop : 0f) - Math.max( @@ -517,7 +517,7 @@ public class StackAnimationController extends mFirstBubbleSpringingToTouch = false; animationForChildAtIndex(0) - .translationX(mLayout.getWidth() / 2f - mIndividualBubbleSize / 2f) + .translationX(mLayout.getWidth() / 2f - mBubbleIconBitmapSize / 2f) .translationY(destY, after) .withPositionStartVelocities(velX, velY) .withStiffness(SpringForce.STIFFNESS_MEDIUM) @@ -657,7 +657,7 @@ public class StackAnimationController extends void onActiveControllerForLayout(PhysicsAnimationLayout layout) { Resources res = layout.getResources(); mStackOffset = res.getDimensionPixelSize(R.dimen.bubble_stack_offset); - mIndividualBubbleSize = res.getDimensionPixelSize(R.dimen.individual_bubble_size); + mBubbleIconBitmapSize = res.getDimensionPixelSize(R.dimen.bubble_icon_bitmap_size); mBubblePaddingTop = res.getDimensionPixelSize(R.dimen.bubble_padding_top); mBubbleOffscreen = res.getDimensionPixelSize(R.dimen.bubble_stack_offscreen); mStackStartingVerticalOffset = diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java index 10b631d9b12c1..7a0bad28f0f14 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/ExpandedAnimationControllerTest.java @@ -46,6 +46,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC private int mDisplayWidth = 500; private int mDisplayHeight = 1000; private int mExpandedViewPadding = 10; + private float mLauncherGridDiff = 30f; @Spy private ExpandedAnimationController mExpandedController = @@ -281,8 +282,7 @@ public class ExpandedAnimationControllerTest extends PhysicsAnimationLayoutTestC * @return Space between bubbles in row above expanded view. */ private float getSpaceBetweenBubbles() { - final float launcherGridDiff = mBubbleSize / 2f; - final float rowMargins = (mExpandedViewPadding + launcherGridDiff) * 2; + final float rowMargins = (mExpandedViewPadding + mLauncherGridDiff) * 2; final float maxRowWidth = mDisplayWidth - rowMargins; final float totalBubbleWidth = mMaxBubbles * mBubbleSize;