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

Commit e31afe42 authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Remove flag bubble_view_info_executors" into main

parents 7d56e93c 889659fd
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -140,16 +140,6 @@ flag {
    }
}

flag {
    name: "bubble_view_info_executors"
    namespace: "multitasking"
    description: "Use executors to inflate bubble views"
    bug: "353894869"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
   name: "enable_bubble_to_fullscreen"
   namespace: "multitasking"
+22 −96
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
package com.android.wm.shell.bubbles;

import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.os.AsyncTask.Status.FINISHED;

import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
@@ -53,7 +52,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.InstanceId;
import com.android.internal.protolog.ProtoLog;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.Flags;
import com.android.wm.shell.bubbles.appinfo.BubbleAppInfoProvider;
import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
@@ -139,8 +137,6 @@ public class Bubble implements BubbleViewProvider {

    @Nullable
    private BubbleViewInfoTask mInflationTask;
    @Nullable
    private BubbleViewInfoTaskLegacy mInflationTaskLegacy;
    private boolean mInflateSynchronously;
    private boolean mPendingIntentCanceled;
    private boolean mIsImportantConversation;
@@ -758,7 +754,6 @@ public class Bubble implements BubbleViewProvider {
            BubbleAppInfoProvider appInfoProvider,
            boolean skipInflation) {
        ProtoLog.v(WM_SHELL_BUBBLES, "Inflate bubble key=%s", getKey());
        if (Flags.bubbleViewInfoExecutors()) {
        if (mInflationTask != null && !mInflationTask.isFinished()) {
            mInflationTask.cancel();
        }
@@ -780,32 +775,6 @@ public class Bubble implements BubbleViewProvider {
        } else {
            mInflationTask.start();
        }
        } else {
            if (mInflationTaskLegacy != null && mInflationTaskLegacy.getStatus() != FINISHED) {
                mInflationTaskLegacy.cancel(true /* mayInterruptIfRunning */);
            }
            mInflationTaskLegacy = new BubbleViewInfoTaskLegacy(this,
                    context,
                    expandedViewManager,
                    taskViewFactory,
                    positioner,
                    stackView,
                    layerView,
                    iconFactory,
                    skipInflation,
                    bubble -> {
                        if (callback != null) {
                            callback.onBubbleViewsReady(bubble);
                        }
                    },
                    mMainExecutor,
                    mBgExecutor);
            if (mInflateSynchronously) {
                mInflationTaskLegacy.onPostExecute(mInflationTaskLegacy.doInBackground());
            } else {
                mInflationTaskLegacy.execute();
            }
        }
    }

    boolean isInflated() {
@@ -813,17 +782,10 @@ public class Bubble implements BubbleViewProvider {
    }

    void stopInflation() {
        if (Flags.bubbleViewInfoExecutors()) {
        if (mInflationTask == null) {
            return;
        }
        mInflationTask.cancel();
        } else {
            if (mInflationTaskLegacy == null) {
                return;
            }
            mInflationTaskLegacy.cancel(true /* mayInterruptIfRunning */);
        }
    }

    void setViewInfo(BubbleViewInfoTask.BubbleViewInfo info) {
@@ -858,42 +820,6 @@ public class Bubble implements BubbleViewProvider {
        }
    }

    /**
     * @deprecated {@link BubbleViewInfoTaskLegacy} is deprecated.
     */
    @Deprecated
    void setViewInfoLegacy(BubbleViewInfoTaskLegacy.BubbleViewInfo info) {
        if (!isInflated()) {
            mIconView = info.imageView;
            mExpandedView = info.expandedView;
            mBubbleBarExpandedView = info.bubbleBarExpandedView;
        }

        mShortcutInfo = info.shortcutInfo;
        mAppName = info.appName;
        if (mTitle == null) {
            mTitle = mAppName;
        }
        mFlyoutMessage = info.flyoutMessage;

        mBadgeBitmap = info.badgeBitmap;
        mRawBadgeBitmap = info.rawBadgeBitmap;
        mBubbleBitmap = info.bubbleBitmap;

        mDotColor = info.dotColor;
        mDotPath = info.dotPath;

        if (mExpandedView != null) {
            mExpandedView.update(this /* bubble */);
        }
        if (mBubbleBarExpandedView != null) {
            mBubbleBarExpandedView.update(this /* bubble */);
        }
        if (mIconView != null) {
            mIconView.setRenderedBubble(this /* bubble */);
        }
    }

    /**
     * Set visibility of bubble in the expanded state.
     *
+0 −346
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 static com.android.wm.shell.bubbles.BadgedImageView.DEFAULT_PATH_SIZE;
import static com.android.wm.shell.bubbles.BadgedImageView.WHITE_SCRIM_ALPHA;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.shared.bubbles.FlyoutDrawableLoader.loadFlyoutDrawable;

import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Path;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.util.Log;
import android.util.PathParser;
import android.view.LayoutInflater;
import android.view.View;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.icons.BitmapInfo;
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;
import com.android.wm.shell.shared.handles.RegionSamplingHelper;

import java.lang.ref.WeakReference;
import java.util.concurrent.Executor;

/**
 * Simple task to inflate views & load necessary info to display a bubble.
 *
 * @deprecated Deprecated since this is using an AsyncTask. Use {@link BubbleViewInfoTask} instead.
 */
@Deprecated
// TODO(b/353894869): remove once flag for loading view info with executors rolls out
public class BubbleViewInfoTaskLegacy extends
        AsyncTask<Void, Void, BubbleViewInfoTaskLegacy.BubbleViewInfo> {
    private static final String TAG =
            TAG_WITH_CLASS_NAME ? "BubbleViewInfoTaskLegacy" : TAG_BUBBLES;


    /**
     * Callback to find out when the bubble has been inflated & necessary data loaded.
     */
    public interface Callback {
        /**
         * Called when data has been loaded for the bubble.
         */
        void onBubbleViewsReady(Bubble bubble);
    }

    private Bubble mBubble;
    private WeakReference<Context> mContext;
    private WeakReference<BubbleExpandedViewManager> mExpandedViewManager;
    private WeakReference<BubbleTaskViewFactory> mTaskViewFactory;
    private WeakReference<BubblePositioner> mPositioner;
    private WeakReference<BubbleStackView> mStackView;
    private WeakReference<BubbleBarLayerView> mLayerView;
    private BubbleIconFactory mIconFactory;
    private boolean mSkipInflation;
    private Callback mCallback;
    private Executor mMainExecutor;
    private Executor mBackgroundExecutor;

    /**
     * Creates a task to load information for the provided {@link Bubble}. Once all info
     * is loaded, {@link Callback} is notified.
     */
    BubbleViewInfoTaskLegacy(Bubble b,
            Context context,
            BubbleExpandedViewManager expandedViewManager,
            BubbleTaskViewFactory taskViewFactory,
            BubblePositioner positioner,
            @Nullable BubbleStackView stackView,
            @Nullable BubbleBarLayerView layerView,
            BubbleIconFactory factory,
            boolean skipInflation,
            Callback c,
            Executor mainExecutor,
            Executor backgroundExecutor) {
        mBubble = b;
        mContext = new WeakReference<>(context);
        mExpandedViewManager = new WeakReference<>(expandedViewManager);
        mTaskViewFactory = new WeakReference<>(taskViewFactory);
        mPositioner = new WeakReference<>(positioner);
        mStackView = new WeakReference<>(stackView);
        mLayerView = new WeakReference<>(layerView);
        mIconFactory = factory;
        mSkipInflation = skipInflation;
        mCallback = c;
        mMainExecutor = mainExecutor;
        mBackgroundExecutor = backgroundExecutor;
    }

    @Override
    protected BubbleViewInfo doInBackground(Void... voids) {
        if (!verifyState()) {
            // If we're in an inconsistent state, then switched modes and should just bail now.
            return null;
        }
        if (mLayerView.get() != null) {
            return BubbleViewInfo.populateForBubbleBar(mContext.get(), mExpandedViewManager.get(),
                    mTaskViewFactory.get(), mPositioner.get(), mLayerView.get(), mIconFactory,
                    mBubble, mSkipInflation, mMainExecutor, mBackgroundExecutor);
        } else {
            return BubbleViewInfo.populate(mContext.get(), mExpandedViewManager.get(),
                    mTaskViewFactory.get(), mPositioner.get(), mStackView.get(), mIconFactory,
                    mBubble, mSkipInflation);
        }
    }

    @Override
    protected void onPostExecute(BubbleViewInfo viewInfo) {
        if (isCancelled() || viewInfo == null) {
            return;
        }

        mMainExecutor.execute(() -> {
            if (!verifyState()) {
                return;
            }
            mBubble.setViewInfoLegacy(viewInfo);
            if (mCallback != null) {
                mCallback.onBubbleViewsReady(mBubble);
            }
        });
    }

    private boolean verifyState() {
        if (mExpandedViewManager.get().isShowingAsBubbleBar()) {
            return mLayerView.get() != null;
        } else {
            return mStackView.get() != null;
        }
    }

    /**
     * Info necessary to render a bubble.
     */
    @VisibleForTesting
    public static class BubbleViewInfo {
        // TODO(b/273312602): for foldables it might make sense to populate all of the views

        // Always populated
        ShortcutInfo shortcutInfo;
        String appName;
        Bitmap rawBadgeBitmap;

        // Only populated when showing in taskbar
        @Nullable BubbleBarExpandedView bubbleBarExpandedView;

        // These are only populated when not showing in taskbar
        @Nullable BadgedImageView imageView;
        @Nullable BubbleExpandedView expandedView;
        int dotColor;
        Path dotPath;
        Bubble.FlyoutMessage flyoutMessage;
        Bitmap bubbleBitmap;
        Bitmap badgeBitmap;

        @Nullable
        public static BubbleViewInfo populateForBubbleBar(Context c,
                BubbleExpandedViewManager expandedViewManager,
                BubbleTaskViewFactory taskViewFactory,
                BubblePositioner positioner,
                BubbleBarLayerView layerView,
                BubbleIconFactory iconFactory,
                Bubble b,
                boolean skipInflation,
                Executor mainExecutor,
                Executor backgroundExecutor) {
            BubbleViewInfo info = new BubbleViewInfo();

            if (!skipInflation && !b.isInflated()) {
                BubbleTaskView bubbleTaskView = b.getOrCreateBubbleTaskView(taskViewFactory);
                LayoutInflater inflater = LayoutInflater.from(c);
                info.bubbleBarExpandedView = (BubbleBarExpandedView) inflater.inflate(
                        R.layout.bubble_bar_expanded_view, layerView, false /* attachToRoot */);
                info.bubbleBarExpandedView.initialize(expandedViewManager, positioner,
                        false /* isOverflow */, b, bubbleTaskView, mainExecutor, backgroundExecutor,
                        new RegionSamplingProvider() {
                            @Override
                            public RegionSamplingHelper createHelper(View sampledView,
                                    RegionSamplingHelper.SamplingCallback callback,
                                    Executor backgroundExecutor, Executor mainExecutor) {
                                return RegionSamplingProvider.super.createHelper(sampledView,
                                        callback, backgroundExecutor, mainExecutor);
                            }
                        });
            }

            if (!populateCommonInfo(info, c, b, iconFactory)) {
                // if we failed to update common fields return null
                return null;
            }

            // set the flyout message but don't load the avatar because we can't pass it on the
            // binder to launcher
            info.flyoutMessage = b.getFlyoutMessage();

            return info;
        }

        @VisibleForTesting
        @Nullable
        public static BubbleViewInfo populate(Context c,
                BubbleExpandedViewManager expandedViewManager,
                BubbleTaskViewFactory taskViewFactory,
                BubblePositioner positioner,
                BubbleStackView stackView,
                BubbleIconFactory iconFactory,
                Bubble b,
                boolean skipInflation) {
            BubbleViewInfo info = new BubbleViewInfo();

            // View inflation: only should do this once per bubble
            if (!skipInflation && !b.isInflated()) {
                LayoutInflater inflater = LayoutInflater.from(c);
                info.imageView = (BadgedImageView) inflater.inflate(
                        R.layout.bubble_view, stackView, false /* attachToRoot */);
                info.imageView.initialize(positioner);

                BubbleTaskView bubbleTaskView = b.getOrCreateBubbleTaskView(taskViewFactory);
                info.expandedView = (BubbleExpandedView) inflater.inflate(
                        R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
                info.expandedView.initialize(
                        expandedViewManager, stackView, positioner, false /* isOverflow */,
                        bubbleTaskView);
            }

            if (!populateCommonInfo(info, c, b, iconFactory)) {
                // if we failed to update common fields return null
                return null;
            }

            // Flyout
            info.flyoutMessage = b.getFlyoutMessage();
            if (info.flyoutMessage != null) {
                info.flyoutMessage.senderAvatar =
                        loadFlyoutDrawable(info.flyoutMessage.senderIcon, c);
            }
            return info;
        }
    }

    /**
     * Modifies the given {@code info} object and populates common fields in it.
     *
     * <p>This method returns {@code true} if the update was successful and {@code false} otherwise.
     * Callers should assume that the info object is unusable if the update was unsuccessful.
     */
    private static boolean populateCommonInfo(
            BubbleViewInfo info, Context c, Bubble b, BubbleIconFactory iconFactory) {
        if (b.getShortcutInfo() != null) {
            info.shortcutInfo = b.getShortcutInfo();
        }

        // App name & app icon
        PackageManager pm = BubbleController.getPackageManagerForUser(c,
                b.getUser().getIdentifier());
        ApplicationInfo appInfo;
        Drawable badgedIcon;
        Drawable appIcon;
        try {
            appInfo = pm.getApplicationInfo(
                    b.getPackageName(),
                    PackageManager.MATCH_UNINSTALLED_PACKAGES
                            | PackageManager.MATCH_DISABLED_COMPONENTS
                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                            | PackageManager.MATCH_DIRECT_BOOT_AWARE);
            if (appInfo != null) {
                info.appName = String.valueOf(pm.getApplicationLabel(appInfo));
            }
            appIcon = pm.getApplicationIcon(b.getPackageName());
            badgedIcon = pm.getUserBadgedIcon(appIcon, b.getUser());
        } catch (PackageManager.NameNotFoundException exception) {
            // If we can't find package... don't think we should show the bubble.
            Log.w(TAG, "Unable to find package: " + b.getPackageName());
            return false;
        }

        Drawable bubbleDrawable = null;
        try {
            // Badged bubble image
            bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo,
                    b.getIcon());
        } catch (Exception e) {
            // If we can't create the icon we'll default to the app icon
            Log.w(TAG, "Exception creating icon for the bubble: " + b.getKey());
        }

        if (bubbleDrawable == null) {
            // Default to app icon
            bubbleDrawable = appIcon;
        }

        BitmapInfo badgeBitmapInfo = iconFactory.getBadgeBitmap(badgedIcon,
                b.isImportantConversation());
        info.badgeBitmap = badgeBitmapInfo.icon;
        // Raw badge bitmap never includes the important conversation ring
        info.rawBadgeBitmap = b.isImportantConversation()
                ? iconFactory.getBadgeBitmap(badgedIcon, false).icon
                : badgeBitmapInfo.icon;

        float[] bubbleBitmapScale = new float[1];
        info.bubbleBitmap = iconFactory.getBubbleBitmap(bubbleDrawable, bubbleBitmapScale);

        // Dot color & placement
        Path iconPath = PathParser.createPathFromPathData(
                c.getResources().getString(com.android.internal.R.string.config_icon_mask));
        Matrix matrix = new Matrix();
        float scale = bubbleBitmapScale[0];
        float radius = DEFAULT_PATH_SIZE / 2f;
        matrix.setScale(scale /* x scale */, scale /* y scale */, radius /* pivot x */,
                radius /* pivot y */);
        iconPath.transform(matrix);
        info.dotPath = iconPath;
        info.dotColor = ColorUtils.blendARGB(badgeBitmapInfo.color,
                Color.WHITE, WHITE_SCRIM_ALPHA);
        return true;
    }
}