Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0e12cfe3 authored by Mady Mellor's avatar Mady Mellor
Browse files

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
parent 1e9f6dc4
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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;
+0 −120
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.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);
        }
    }
}
+24 −6
Original line number Diff line number Diff line
@@ -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) {
+0 −84
Original line number Diff line number Diff line
/*
 * 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);
    }
}
+3 −1
Original line number Diff line number Diff line
@@ -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)
Loading