Update bubbles to use icon factory in the lib

Test: manual - create a normal bubble and a VIP bubble and check that
               the badges look correct
Bug: 276778786
Change-Id: If1f249c9198ddd6057e7a2cbabe6d1082980002f
This commit is contained in:
Mady Mellor
2023-04-03 13:19:24 -07:00
parent 1e9f6dc40e
commit 0e12cfe342
7 changed files with 41 additions and 215 deletions

View File

@@ -47,6 +47,8 @@ import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.launcher3.icons.BubbleBadgeIconFactory;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
import com.android.wm.shell.common.bubbles.BubbleInfo;

View File

@@ -1,120 +0,0 @@
/*
* Copyright (C) 2022 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.wm.shell.bubbles;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.Drawable;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.launcher3.icons.BitmapInfo;
import com.android.wm.shell.R;
/**
* Factory for creating app badge icons that are shown on bubbles.
*/
public class BubbleBadgeIconFactory extends BaseIconFactory {
public BubbleBadgeIconFactory(Context context) {
super(context, context.getResources().getConfiguration().densityDpi,
context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size));
}
/**
* Returns a {@link BitmapInfo} for the app-badge that is shown on top of each bubble. This
* will include the workprofile indicator on the badge if appropriate.
*/
BitmapInfo getBadgeBitmap(Drawable userBadgedAppIcon, boolean isImportantConversation) {
if (userBadgedAppIcon instanceof AdaptiveIconDrawable) {
AdaptiveIconDrawable ad = (AdaptiveIconDrawable) userBadgedAppIcon;
userBadgedAppIcon = new CircularAdaptiveIcon(ad.getBackground(), ad.getForeground());
}
if (isImportantConversation) {
userBadgedAppIcon = new CircularRingDrawable(userBadgedAppIcon);
}
Bitmap userBadgedBitmap = createIconBitmap(
userBadgedAppIcon, 1, MODE_WITH_SHADOW);
return createIconBitmap(userBadgedBitmap);
}
private class CircularRingDrawable extends CircularAdaptiveIcon {
final int mImportantConversationColor;
final int mRingWidth;
final Rect mInnerBounds = new Rect();
final Drawable mDr;
CircularRingDrawable(Drawable dr) {
super(null, null);
mDr = dr;
mImportantConversationColor = mContext.getResources().getColor(
R.color.important_conversation, null);
mRingWidth = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width);
}
@Override
public void draw(Canvas canvas) {
int save = canvas.save();
canvas.clipPath(getIconMask());
canvas.drawColor(mImportantConversationColor);
mInnerBounds.set(getBounds());
mInnerBounds.inset(mRingWidth, mRingWidth);
canvas.translate(mInnerBounds.left, mInnerBounds.top);
mDr.setBounds(0, 0, mInnerBounds.width(), mInnerBounds.height());
mDr.draw(canvas);
canvas.restoreToCount(save);
}
}
private static class CircularAdaptiveIcon extends AdaptiveIconDrawable {
final Path mPath = new Path();
CircularAdaptiveIcon(Drawable bg, Drawable fg) {
super(bg, fg);
}
@Override
public Path getIconMask() {
mPath.reset();
Rect bounds = getBounds();
mPath.addOval(bounds.left, bounds.top, bounds.right, bounds.bottom, Path.Direction.CW);
return mPath;
}
@Override
public void draw(Canvas canvas) {
int save = canvas.save();
canvas.clipPath(getIconMask());
Drawable d;
if ((d = getBackground()) != null) {
d.draw(canvas);
}
if ((d = getForeground()) != null) {
d.draw(canvas);
}
canvas.restoreToCount(save);
}
}
}

View File

@@ -89,6 +89,9 @@ import androidx.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.BubbleBadgeIconFactory;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
@@ -317,8 +320,13 @@ public class BubbleController implements ConfigurationChangeListener,
mBubblePositioner = positioner;
mBubbleData = data;
mSavedUserBubbleData = new SparseArray<>();
mBubbleIconFactory = new BubbleIconFactory(context);
mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(context);
mBubbleIconFactory = new BubbleIconFactory(context,
context.getResources().getDimensionPixelSize(R.dimen.bubble_size));
mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(context,
context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
context.getResources().getColor(R.color.important_conversation),
context.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width));
mDisplayController = displayController;
mTaskViewTransitions = taskViewTransitions;
mOneHandedOptional = oneHandedOptional;
@@ -927,8 +935,13 @@ public class BubbleController implements ConfigurationChangeListener,
if (mStackView != null) {
mStackView.onThemeChanged();
}
mBubbleIconFactory = new BubbleIconFactory(mContext);
mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext);
mBubbleIconFactory = new BubbleIconFactory(mContext,
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size));
mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext,
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
mContext.getResources().getColor(R.color.important_conversation),
mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width));
// Reload each bubble
for (Bubble b : mBubbleData.getBubbles()) {
@@ -964,8 +977,13 @@ public class BubbleController implements ConfigurationChangeListener,
mDensityDpi = newConfig.densityDpi;
mScreenBounds.set(newConfig.windowConfiguration.getBounds());
mBubbleData.onMaxBubblesChanged();
mBubbleIconFactory = new BubbleIconFactory(mContext);
mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext);
mBubbleIconFactory = new BubbleIconFactory(mContext,
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size));
mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext,
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
mContext.getResources().getColor(R.color.important_conversation),
mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width));
mStackView.onDisplaySizeChanged();
}
if (newConfig.fontScale != mFontScale) {

View File

@@ -1,84 +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.wm.shell.bubbles;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.icons.BaseIconFactory;
import com.android.wm.shell.R;
/**
* 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.
*/
@VisibleForTesting
public class BubbleIconFactory extends BaseIconFactory {
public BubbleIconFactory(Context context) {
super(context, context.getResources().getConfiguration().densityDpi,
context.getResources().getDimensionPixelSize(R.dimen.bubble_size));
}
/**
* Returns the drawable that the developer has provided to display in the bubble.
*/
Drawable getBubbleDrawable(@NonNull final Context context,
@Nullable final ShortcutInfo shortcutInfo, @Nullable final Icon ic) {
if (shortcutInfo != null) {
LauncherApps launcherApps =
(LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
int density = context.getResources().getConfiguration().densityDpi;
return launcherApps.getShortcutIconDrawable(shortcutInfo, density);
} else {
if (ic != null) {
if (ic.getType() == Icon.TYPE_URI
|| ic.getType() == Icon.TYPE_URI_ADAPTIVE_BITMAP) {
context.grantUriPermission(context.getPackageName(),
ic.getUri(),
Intent.FLAG_GRANT_READ_URI_PERMISSION);
}
return ic.loadDrawable(context);
}
return null;
}
}
/**
* Creates the bitmap for the provided drawable and returns the scale used for
* drawing the actual drawable.
*/
public Bitmap createIconBitmap(@NonNull Drawable icon, float[] outScale) {
if (outScale == null) {
outScale = new float[1];
}
icon = normalizeAndWrapToAdaptiveIcon(icon,
true /* shrinkNonAdaptiveIcons */,
null /* outscale */,
outScale);
return createIconBitmap(icon, outScale[0], MODE_WITH_SHADOW);
}
}

View File

@@ -28,6 +28,7 @@ import android.util.PathParser
import android.util.TypedValue
import android.view.LayoutInflater
import android.widget.FrameLayout
import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.R
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView
@@ -93,7 +94,8 @@ class BubbleOverflow(
val shapeColor = res.getColor(android.R.color.system_accent1_1000)
overflowBtn?.iconDrawable?.setTint(shapeColor)
val iconFactory = BubbleIconFactory(context)
val iconFactory = BubbleIconFactory(context,
context.getResources().getDimensionPixelSize(R.dimen.bubble_size))
// Update bitmap
val fg = InsetDrawable(overflowBtn?.iconDrawable, overflowIconInset)

View File

@@ -42,6 +42,8 @@ import android.view.LayoutInflater;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.BubbleBadgeIconFactory;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.R;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;

View File

@@ -85,6 +85,9 @@ import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.launcher3.icons.BubbleBadgeIconFactory;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.biometrics.AuthController;
import com.android.systemui.colorextraction.SysuiColorExtractor;
@@ -127,11 +130,9 @@ import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleBadgeIconFactory;
import com.android.wm.shell.bubbles.BubbleData;
import com.android.wm.shell.bubbles.BubbleDataRepository;
import com.android.wm.shell.bubbles.BubbleEntry;
import com.android.wm.shell.bubbles.BubbleIconFactory;
import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubbleStackView;
import com.android.wm.shell.bubbles.BubbleViewInfoTask;
@@ -1225,8 +1226,13 @@ public class BubblesTest extends SysuiTestCase {
BubbleViewInfoTask.BubbleViewInfo info = BubbleViewInfoTask.BubbleViewInfo.populate(context,
mBubbleController,
mBubbleController.getStackView(),
new BubbleIconFactory(mContext),
new BubbleBadgeIconFactory(mContext),
new BubbleIconFactory(mContext,
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size)),
new BubbleBadgeIconFactory(mContext,
mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
mContext.getResources().getColor(R.color.important_conversation),
mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width)),
bubble,
true /* skipInflation */);
verify(userContext, times(1)).getPackageManager();