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:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user