Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +4 −1 Original line number Diff line number Diff line Loading @@ -364,13 +364,15 @@ public class Bubble implements BubbleViewProvider { * @param context the context for the bubble. * @param controller the bubble controller. * @param stackView the stackView the bubble is eventually added to. * @param iconFactory the iconfactory use to create badged images for the bubble. * @param iconFactory the icon factory use to create images for the bubble. * @param badgeIconFactory the icon factory to create app badges for the bubble. */ void inflate(BubbleViewInfoTask.Callback callback, Context context, BubbleController controller, BubbleStackView stackView, BubbleIconFactory iconFactory, BubbleBadgeIconFactory badgeIconFactory, boolean skipInflation) { if (isBubbleLoading()) { mInflationTask.cancel(true /* mayInterruptIfRunning */); Loading @@ -380,6 +382,7 @@ public class Bubble implements BubbleViewProvider { controller, stackView, iconFactory, badgeIconFactory, skipInflation, callback, mMainExecutor); Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleBadgeIconFactory.java 0 → 100644 +121 −0 Original line number Diff line number Diff line /* * 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.Paint; import android.graphics.Path; 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.launcher3.icons.ShadowGenerator; 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) { ShadowGenerator shadowGenerator = new ShadowGenerator(mIconBitmapSize); Bitmap userBadgedBitmap = createIconBitmap(userBadgedAppIcon, 1f, mIconBitmapSize); if (userBadgedAppIcon instanceof AdaptiveIconDrawable) { userBadgedBitmap = Bitmap.createScaledBitmap( getCircleBitmap((AdaptiveIconDrawable) userBadgedAppIcon, /* size */ userBadgedAppIcon.getIntrinsicWidth()), mIconBitmapSize, mIconBitmapSize, /* filter */ true); } if (isImportantConversation) { final float ringStrokeWidth = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.importance_ring_stroke_width); final int importantConversationColor = mContext.getResources().getColor( R.color.important_conversation, null); Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(), userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig()); Canvas c = new Canvas(badgeAndRing); Paint ringPaint = new Paint(); ringPaint.setStyle(Paint.Style.FILL); ringPaint.setColor(importantConversationColor); ringPaint.setAntiAlias(true); c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2, ringPaint); final int bitmapTop = (int) ringStrokeWidth; final int bitmapLeft = (int) ringStrokeWidth; final int bitmapWidth = c.getWidth() - 2 * (int) ringStrokeWidth; final int bitmapHeight = c.getHeight() - 2 * (int) ringStrokeWidth; Bitmap scaledBitmap = Bitmap.createScaledBitmap(userBadgedBitmap, bitmapWidth, bitmapHeight, /* filter */ true); c.drawBitmap(scaledBitmap, bitmapTop, bitmapLeft, /* paint */null); shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c); return createIconBitmap(badgeAndRing); } else { Canvas c = new Canvas(); c.setBitmap(userBadgedBitmap); shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); return createIconBitmap(userBadgedBitmap); } } private Bitmap getCircleBitmap(AdaptiveIconDrawable icon, int size) { Drawable foreground = icon.getForeground(); Drawable background = icon.getBackground(); Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(); canvas.setBitmap(bitmap); // Clip canvas to circle. Path circlePath = new Path(); circlePath.addCircle(/* x */ size / 2f, /* y */ size / 2f, /* radius */ size / 2f, Path.Direction.CW); canvas.clipPath(circlePath); // Draw background. background.setBounds(0, 0, size, size); background.draw(canvas); // Draw foreground. The foreground and background drawables are derived from adaptive icons // Some icon shapes fill more space than others, so adaptive icons are normalized to about // the same size. This size is smaller than the original bounds, so we estimate // the difference in this offset. int offset = size / 5; foreground.setBounds(-offset, -offset, size + offset, size + offset); foreground.draw(canvas); canvas.setBitmap(null); return bitmap; } } libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +14 −4 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ public class BubbleController { private BubbleData mBubbleData; @Nullable private BubbleStackView mStackView; private BubbleIconFactory mBubbleIconFactory; private BubbleBadgeIconFactory mBubbleBadgeIconFactory; private BubblePositioner mBubblePositioner; private Bubbles.SysuiProxy mSysuiProxy; Loading Loading @@ -278,6 +279,7 @@ public class BubbleController { mBubbleData = data; mSavedBubbleKeysPerUser = new SparseSetArray<>(); mBubbleIconFactory = new BubbleIconFactory(context); mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(context); mDisplayController = displayController; mTaskViewTransitions = taskViewTransitions; mOneHandedOptional = oneHandedOptional; Loading Loading @@ -500,6 +502,7 @@ public class BubbleController { } mStackView.updateStackPosition(); mBubbleIconFactory = new BubbleIconFactory(mContext); mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext); mStackView.onDisplaySizeChanged(); } if (b.getBoolean(EXTRA_BUBBLE_OVERFLOW_OPENED, false)) { Loading Loading @@ -778,13 +781,17 @@ public class BubbleController { mStackView.onThemeChanged(); } mBubbleIconFactory = new BubbleIconFactory(mContext); mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext); // Reload each bubble for (Bubble b : mBubbleData.getBubbles()) { b.inflate(null /* callback */, mContext, this, mStackView, mBubbleIconFactory, mBubbleBadgeIconFactory, false /* skipInflation */); } for (Bubble b : mBubbleData.getOverflowBubbles()) { b.inflate(null /* callback */, mContext, this, mStackView, mBubbleIconFactory, mBubbleBadgeIconFactory, false /* skipInflation */); } } Loading @@ -800,6 +807,7 @@ public class BubbleController { mScreenBounds.set(newConfig.windowConfiguration.getBounds()); mBubbleData.onMaxBubblesChanged(); mBubbleIconFactory = new BubbleIconFactory(mContext); mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext); mStackView.onDisplaySizeChanged(); } if (newConfig.fontScale != mFontScale) { Loading Loading @@ -961,7 +969,8 @@ public class BubbleController { } bubble.inflate( (b) -> mBubbleData.overflowBubble(Bubbles.DISMISS_RELOAD_FROM_DISK, bubble), mContext, this, mStackView, mBubbleIconFactory, true /* skipInflation */); mContext, this, mStackView, mBubbleIconFactory, mBubbleBadgeIconFactory, true /* skipInflation */); }); return null; }); Loading Loading @@ -996,7 +1005,8 @@ public class BubbleController { ensureStackViewCreated(); bubble.setInflateSynchronously(mInflateSynchronously); bubble.inflate(b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade), mContext, this, mStackView, mBubbleIconFactory, false /* skipInflation */); mContext, this, mStackView, mBubbleIconFactory, mBubbleBadgeIconFactory, false /* skipInflation */); } /** Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java +0 −90 Original line number Diff line number Diff line Loading @@ -21,19 +21,12 @@ 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.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import androidx.annotation.VisibleForTesting; import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.ShadowGenerator; import com.android.wm.shell.R; /** Loading @@ -44,12 +37,9 @@ import com.android.wm.shell.R; @VisibleForTesting public class BubbleIconFactory extends BaseIconFactory { private int mBadgeSize; public BubbleIconFactory(Context context) { super(context, context.getResources().getConfiguration().densityDpi, context.getResources().getDimensionPixelSize(R.dimen.bubble_size)); mBadgeSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size); } /** Loading @@ -75,84 +65,4 @@ public class BubbleIconFactory extends BaseIconFactory { return null; } } /** * 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) { ShadowGenerator shadowGenerator = new ShadowGenerator(mBadgeSize); Bitmap userBadgedBitmap = createIconBitmap(userBadgedAppIcon, 1f, mBadgeSize); if (userBadgedAppIcon instanceof AdaptiveIconDrawable) { userBadgedBitmap = Bitmap.createScaledBitmap( getCircleBitmap((AdaptiveIconDrawable) userBadgedAppIcon, /* size */ userBadgedAppIcon.getIntrinsicWidth()), mBadgeSize, mBadgeSize, /* filter */ true); } if (isImportantConversation) { final float ringStrokeWidth = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.importance_ring_stroke_width); final int importantConversationColor = mContext.getResources().getColor( R.color.important_conversation, null); Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(), userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig()); Canvas c = new Canvas(badgeAndRing); Paint ringPaint = new Paint(); ringPaint.setStyle(Paint.Style.FILL); ringPaint.setColor(importantConversationColor); ringPaint.setAntiAlias(true); c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2, ringPaint); final int bitmapTop = (int) ringStrokeWidth; final int bitmapLeft = (int) ringStrokeWidth; final int bitmapWidth = c.getWidth() - 2 * (int) ringStrokeWidth; final int bitmapHeight = c.getHeight() - 2 * (int) ringStrokeWidth; Bitmap scaledBitmap = Bitmap.createScaledBitmap(userBadgedBitmap, bitmapWidth, bitmapHeight, /* filter */ true); c.drawBitmap(scaledBitmap, bitmapTop, bitmapLeft, /* paint */null); shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c); return createIconBitmap(badgeAndRing); } else { Canvas c = new Canvas(); c.setBitmap(userBadgedBitmap); shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); return createIconBitmap(userBadgedBitmap); } } public Bitmap getCircleBitmap(AdaptiveIconDrawable icon, int size) { Drawable foreground = icon.getForeground(); Drawable background = icon.getBackground(); Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(); canvas.setBitmap(bitmap); // Clip canvas to circle. Path circlePath = new Path(); circlePath.addCircle(/* x */ size / 2f, /* y */ size / 2f, /* radius */ size / 2f, Path.Direction.CW); canvas.clipPath(circlePath); // Draw background. background.setBounds(0, 0, size, size); background.draw(canvas); // Draw foreground. The foreground and background drawables are derived from adaptive icons // Some icon shapes fill more space than others, so adaptive icons are normalized to about // the same size. This size is smaller than the original bounds, so we estimate // the difference in this offset. int offset = size / 5; foreground.setBounds(-offset, -offset, size + offset, size + offset); foreground.draw(canvas); canvas.setBitmap(null); return bitmap; } } libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java +8 −4 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask private WeakReference<BubbleController> mController; private WeakReference<BubbleStackView> mStackView; private BubbleIconFactory mIconFactory; private BubbleBadgeIconFactory mBadgeIconFactory; private boolean mSkipInflation; private Callback mCallback; private Executor mMainExecutor; Loading @@ -84,6 +85,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask BubbleController controller, BubbleStackView stackView, BubbleIconFactory factory, BubbleBadgeIconFactory badgeFactory, boolean skipInflation, Callback c, Executor mainExecutor) { Loading @@ -92,6 +94,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask mController = new WeakReference<>(controller); mStackView = new WeakReference<>(stackView); mIconFactory = factory; mBadgeIconFactory = badgeFactory; mSkipInflation = skipInflation; mCallback = c; mMainExecutor = mainExecutor; Loading @@ -100,7 +103,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask @Override protected BubbleViewInfo doInBackground(Void... voids) { return BubbleViewInfo.populate(mContext.get(), mController.get(), mStackView.get(), mIconFactory, mBubble, mSkipInflation); mIconFactory, mBadgeIconFactory, mBubble, mSkipInflation); } @Override Loading Loading @@ -135,7 +138,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask @VisibleForTesting @Nullable public static BubbleViewInfo populate(Context c, BubbleController controller, BubbleStackView stackView, BubbleIconFactory iconFactory, Bubble b, BubbleStackView stackView, BubbleIconFactory iconFactory, BubbleBadgeIconFactory badgeIconFactory, Bubble b, boolean skipInflation) { BubbleViewInfo info = new BubbleViewInfo(); Loading Loading @@ -187,11 +191,11 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask bubbleDrawable = appIcon; } BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon, BitmapInfo badgeBitmapInfo = badgeIconFactory.getBadgeBitmap(badgedIcon, b.isImportantConversation()); info.badgeBitmap = badgeBitmapInfo.icon; // Raw badge bitmap never includes the important conversation ring info.mRawBadgeBitmap = iconFactory.getBadgeBitmap(badgedIcon, false).icon; info.mRawBadgeBitmap = badgeIconFactory.getBadgeBitmap(badgedIcon, false).icon; info.bubbleBitmap = iconFactory.createBadgedIconBitmap(bubbleDrawable).icon; // Dot color & placement Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +4 −1 Original line number Diff line number Diff line Loading @@ -364,13 +364,15 @@ public class Bubble implements BubbleViewProvider { * @param context the context for the bubble. * @param controller the bubble controller. * @param stackView the stackView the bubble is eventually added to. * @param iconFactory the iconfactory use to create badged images for the bubble. * @param iconFactory the icon factory use to create images for the bubble. * @param badgeIconFactory the icon factory to create app badges for the bubble. */ void inflate(BubbleViewInfoTask.Callback callback, Context context, BubbleController controller, BubbleStackView stackView, BubbleIconFactory iconFactory, BubbleBadgeIconFactory badgeIconFactory, boolean skipInflation) { if (isBubbleLoading()) { mInflationTask.cancel(true /* mayInterruptIfRunning */); Loading @@ -380,6 +382,7 @@ public class Bubble implements BubbleViewProvider { controller, stackView, iconFactory, badgeIconFactory, skipInflation, callback, mMainExecutor); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleBadgeIconFactory.java 0 → 100644 +121 −0 Original line number Diff line number Diff line /* * 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.Paint; import android.graphics.Path; 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.launcher3.icons.ShadowGenerator; 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) { ShadowGenerator shadowGenerator = new ShadowGenerator(mIconBitmapSize); Bitmap userBadgedBitmap = createIconBitmap(userBadgedAppIcon, 1f, mIconBitmapSize); if (userBadgedAppIcon instanceof AdaptiveIconDrawable) { userBadgedBitmap = Bitmap.createScaledBitmap( getCircleBitmap((AdaptiveIconDrawable) userBadgedAppIcon, /* size */ userBadgedAppIcon.getIntrinsicWidth()), mIconBitmapSize, mIconBitmapSize, /* filter */ true); } if (isImportantConversation) { final float ringStrokeWidth = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.importance_ring_stroke_width); final int importantConversationColor = mContext.getResources().getColor( R.color.important_conversation, null); Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(), userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig()); Canvas c = new Canvas(badgeAndRing); Paint ringPaint = new Paint(); ringPaint.setStyle(Paint.Style.FILL); ringPaint.setColor(importantConversationColor); ringPaint.setAntiAlias(true); c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2, ringPaint); final int bitmapTop = (int) ringStrokeWidth; final int bitmapLeft = (int) ringStrokeWidth; final int bitmapWidth = c.getWidth() - 2 * (int) ringStrokeWidth; final int bitmapHeight = c.getHeight() - 2 * (int) ringStrokeWidth; Bitmap scaledBitmap = Bitmap.createScaledBitmap(userBadgedBitmap, bitmapWidth, bitmapHeight, /* filter */ true); c.drawBitmap(scaledBitmap, bitmapTop, bitmapLeft, /* paint */null); shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c); return createIconBitmap(badgeAndRing); } else { Canvas c = new Canvas(); c.setBitmap(userBadgedBitmap); shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); return createIconBitmap(userBadgedBitmap); } } private Bitmap getCircleBitmap(AdaptiveIconDrawable icon, int size) { Drawable foreground = icon.getForeground(); Drawable background = icon.getBackground(); Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(); canvas.setBitmap(bitmap); // Clip canvas to circle. Path circlePath = new Path(); circlePath.addCircle(/* x */ size / 2f, /* y */ size / 2f, /* radius */ size / 2f, Path.Direction.CW); canvas.clipPath(circlePath); // Draw background. background.setBounds(0, 0, size, size); background.draw(canvas); // Draw foreground. The foreground and background drawables are derived from adaptive icons // Some icon shapes fill more space than others, so adaptive icons are normalized to about // the same size. This size is smaller than the original bounds, so we estimate // the difference in this offset. int offset = size / 5; foreground.setBounds(-offset, -offset, size + offset, size + offset); foreground.draw(canvas); canvas.setBitmap(null); return bitmap; } }
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +14 −4 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ public class BubbleController { private BubbleData mBubbleData; @Nullable private BubbleStackView mStackView; private BubbleIconFactory mBubbleIconFactory; private BubbleBadgeIconFactory mBubbleBadgeIconFactory; private BubblePositioner mBubblePositioner; private Bubbles.SysuiProxy mSysuiProxy; Loading Loading @@ -278,6 +279,7 @@ public class BubbleController { mBubbleData = data; mSavedBubbleKeysPerUser = new SparseSetArray<>(); mBubbleIconFactory = new BubbleIconFactory(context); mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(context); mDisplayController = displayController; mTaskViewTransitions = taskViewTransitions; mOneHandedOptional = oneHandedOptional; Loading Loading @@ -500,6 +502,7 @@ public class BubbleController { } mStackView.updateStackPosition(); mBubbleIconFactory = new BubbleIconFactory(mContext); mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext); mStackView.onDisplaySizeChanged(); } if (b.getBoolean(EXTRA_BUBBLE_OVERFLOW_OPENED, false)) { Loading Loading @@ -778,13 +781,17 @@ public class BubbleController { mStackView.onThemeChanged(); } mBubbleIconFactory = new BubbleIconFactory(mContext); mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext); // Reload each bubble for (Bubble b : mBubbleData.getBubbles()) { b.inflate(null /* callback */, mContext, this, mStackView, mBubbleIconFactory, mBubbleBadgeIconFactory, false /* skipInflation */); } for (Bubble b : mBubbleData.getOverflowBubbles()) { b.inflate(null /* callback */, mContext, this, mStackView, mBubbleIconFactory, mBubbleBadgeIconFactory, false /* skipInflation */); } } Loading @@ -800,6 +807,7 @@ public class BubbleController { mScreenBounds.set(newConfig.windowConfiguration.getBounds()); mBubbleData.onMaxBubblesChanged(); mBubbleIconFactory = new BubbleIconFactory(mContext); mBubbleBadgeIconFactory = new BubbleBadgeIconFactory(mContext); mStackView.onDisplaySizeChanged(); } if (newConfig.fontScale != mFontScale) { Loading Loading @@ -961,7 +969,8 @@ public class BubbleController { } bubble.inflate( (b) -> mBubbleData.overflowBubble(Bubbles.DISMISS_RELOAD_FROM_DISK, bubble), mContext, this, mStackView, mBubbleIconFactory, true /* skipInflation */); mContext, this, mStackView, mBubbleIconFactory, mBubbleBadgeIconFactory, true /* skipInflation */); }); return null; }); Loading Loading @@ -996,7 +1005,8 @@ public class BubbleController { ensureStackViewCreated(); bubble.setInflateSynchronously(mInflateSynchronously); bubble.inflate(b -> mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade), mContext, this, mStackView, mBubbleIconFactory, false /* skipInflation */); mContext, this, mStackView, mBubbleIconFactory, mBubbleBadgeIconFactory, false /* skipInflation */); } /** Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleIconFactory.java +0 −90 Original line number Diff line number Diff line Loading @@ -21,19 +21,12 @@ 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.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import androidx.annotation.VisibleForTesting; import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.ShadowGenerator; import com.android.wm.shell.R; /** Loading @@ -44,12 +37,9 @@ import com.android.wm.shell.R; @VisibleForTesting public class BubbleIconFactory extends BaseIconFactory { private int mBadgeSize; public BubbleIconFactory(Context context) { super(context, context.getResources().getConfiguration().densityDpi, context.getResources().getDimensionPixelSize(R.dimen.bubble_size)); mBadgeSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size); } /** Loading @@ -75,84 +65,4 @@ public class BubbleIconFactory extends BaseIconFactory { return null; } } /** * 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) { ShadowGenerator shadowGenerator = new ShadowGenerator(mBadgeSize); Bitmap userBadgedBitmap = createIconBitmap(userBadgedAppIcon, 1f, mBadgeSize); if (userBadgedAppIcon instanceof AdaptiveIconDrawable) { userBadgedBitmap = Bitmap.createScaledBitmap( getCircleBitmap((AdaptiveIconDrawable) userBadgedAppIcon, /* size */ userBadgedAppIcon.getIntrinsicWidth()), mBadgeSize, mBadgeSize, /* filter */ true); } if (isImportantConversation) { final float ringStrokeWidth = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.importance_ring_stroke_width); final int importantConversationColor = mContext.getResources().getColor( R.color.important_conversation, null); Bitmap badgeAndRing = Bitmap.createBitmap(userBadgedBitmap.getWidth(), userBadgedBitmap.getHeight(), userBadgedBitmap.getConfig()); Canvas c = new Canvas(badgeAndRing); Paint ringPaint = new Paint(); ringPaint.setStyle(Paint.Style.FILL); ringPaint.setColor(importantConversationColor); ringPaint.setAntiAlias(true); c.drawCircle(c.getWidth() / 2, c.getHeight() / 2, c.getWidth() / 2, ringPaint); final int bitmapTop = (int) ringStrokeWidth; final int bitmapLeft = (int) ringStrokeWidth; final int bitmapWidth = c.getWidth() - 2 * (int) ringStrokeWidth; final int bitmapHeight = c.getHeight() - 2 * (int) ringStrokeWidth; Bitmap scaledBitmap = Bitmap.createScaledBitmap(userBadgedBitmap, bitmapWidth, bitmapHeight, /* filter */ true); c.drawBitmap(scaledBitmap, bitmapTop, bitmapLeft, /* paint */null); shadowGenerator.recreateIcon(Bitmap.createBitmap(badgeAndRing), c); return createIconBitmap(badgeAndRing); } else { Canvas c = new Canvas(); c.setBitmap(userBadgedBitmap); shadowGenerator.recreateIcon(Bitmap.createBitmap(userBadgedBitmap), c); return createIconBitmap(userBadgedBitmap); } } public Bitmap getCircleBitmap(AdaptiveIconDrawable icon, int size) { Drawable foreground = icon.getForeground(); Drawable background = icon.getBackground(); Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(); canvas.setBitmap(bitmap); // Clip canvas to circle. Path circlePath = new Path(); circlePath.addCircle(/* x */ size / 2f, /* y */ size / 2f, /* radius */ size / 2f, Path.Direction.CW); canvas.clipPath(circlePath); // Draw background. background.setBounds(0, 0, size, size); background.draw(canvas); // Draw foreground. The foreground and background drawables are derived from adaptive icons // Some icon shapes fill more space than others, so adaptive icons are normalized to about // the same size. This size is smaller than the original bounds, so we estimate // the difference in this offset. int offset = size / 5; foreground.setBounds(-offset, -offset, size + offset, size + offset); foreground.draw(canvas); canvas.setBitmap(null); return bitmap; } }
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleViewInfoTask.java +8 −4 Original line number Diff line number Diff line Loading @@ -71,6 +71,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask private WeakReference<BubbleController> mController; private WeakReference<BubbleStackView> mStackView; private BubbleIconFactory mIconFactory; private BubbleBadgeIconFactory mBadgeIconFactory; private boolean mSkipInflation; private Callback mCallback; private Executor mMainExecutor; Loading @@ -84,6 +85,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask BubbleController controller, BubbleStackView stackView, BubbleIconFactory factory, BubbleBadgeIconFactory badgeFactory, boolean skipInflation, Callback c, Executor mainExecutor) { Loading @@ -92,6 +94,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask mController = new WeakReference<>(controller); mStackView = new WeakReference<>(stackView); mIconFactory = factory; mBadgeIconFactory = badgeFactory; mSkipInflation = skipInflation; mCallback = c; mMainExecutor = mainExecutor; Loading @@ -100,7 +103,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask @Override protected BubbleViewInfo doInBackground(Void... voids) { return BubbleViewInfo.populate(mContext.get(), mController.get(), mStackView.get(), mIconFactory, mBubble, mSkipInflation); mIconFactory, mBadgeIconFactory, mBubble, mSkipInflation); } @Override Loading Loading @@ -135,7 +138,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask @VisibleForTesting @Nullable public static BubbleViewInfo populate(Context c, BubbleController controller, BubbleStackView stackView, BubbleIconFactory iconFactory, Bubble b, BubbleStackView stackView, BubbleIconFactory iconFactory, BubbleBadgeIconFactory badgeIconFactory, Bubble b, boolean skipInflation) { BubbleViewInfo info = new BubbleViewInfo(); Loading Loading @@ -187,11 +191,11 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask bubbleDrawable = appIcon; } BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon, BitmapInfo badgeBitmapInfo = badgeIconFactory.getBadgeBitmap(badgedIcon, b.isImportantConversation()); info.badgeBitmap = badgeBitmapInfo.icon; // Raw badge bitmap never includes the important conversation ring info.mRawBadgeBitmap = iconFactory.getBadgeBitmap(badgedIcon, false).icon; info.mRawBadgeBitmap = badgeIconFactory.getBadgeBitmap(badgedIcon, false).icon; info.bubbleBitmap = iconFactory.createBadgedIconBitmap(bubbleDrawable).icon; // Dot color & placement Loading