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

Commit 1d97e2e9 authored by Mady Mellor's avatar Mady Mellor Committed by Android (Google) Code Review
Browse files

Merge "Cleaning up flag com.android.wm.shell.enable_bubble_task_view_listener" into main

parents 09b43cb8 cbd5c0d6
Loading
Loading
Loading
Loading
+0 −10
Original line number Diff line number Diff line
@@ -162,16 +162,6 @@ flag {
    bug: "394869612"
}

flag {
    name: "enable_bubble_task_view_listener"
    namespace: "multitasking"
    description: "Use the same taskview listener for bubble bar and floating"
    bug: "272102927"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "enable_gsf"
    namespace: "multitasking"
+4 −19
Original line number Diff line number Diff line
@@ -19,15 +19,13 @@ package com.android.wm.shell.bubbles
import android.content.ComponentName
import android.content.Context
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.platform.test.flag.junit.SetFlagsRule
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_ANYTHING
import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_TASK_VIEW_LISTENER
import com.android.wm.shell.MockToken
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.bubbles.util.BubbleTestUtils.verifyEnterBubbleTransaction
@@ -37,15 +35,13 @@ import com.android.wm.shell.taskview.TaskViewTaskController
import com.google.common.truth.Truth.assertThat
import com.google.common.util.concurrent.MoreExecutors.directExecutor
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.argumentCaptor
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters


/**
 * Tests for [BubbleExpandedView].
@@ -55,11 +51,8 @@ import platform.test.runner.parameterized.Parameters
 *  atest WMShellMultivalentTestsOnDevice:BubbleExpandedViewTest (on device)
 */
@SmallTest
@RunWith(ParameterizedAndroidJunit4::class)
class BubbleExpandedViewTest(flags: FlagsParameterization) {

    @get:Rule
    val setFlagsRule = SetFlagsRule(flags)
@RunWith(AndroidJUnit4::class)
class BubbleExpandedViewTest {

    private val context = ApplicationProvider.getApplicationContext<Context>()
    private val componentName = ComponentName(context, "TestClass")
@@ -117,12 +110,4 @@ class BubbleExpandedViewTest(flags: FlagsParameterization) {
            isAppBubble = false,
        )
    }

    companion object {
        @JvmStatic
        @Parameters(name = "{0}")
        fun getParams() = FlagsParameterization.allCombinationsOf(
            FLAG_ENABLE_BUBBLE_TASK_VIEW_LISTENER,
        )
    }
}
+39 −237
Original line number Diff line number Diff line
@@ -16,28 +16,21 @@

package com.android.wm.shell.bubbles;

import static android.app.ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;

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.bubbles.BubblePositioner.MAX_HEIGHT;
import static com.android.wm.shell.bubbles.util.BubbleUtils.getEnterBubbleTransaction;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;
import static com.android.wm.shell.shared.TypefaceUtils.setTypeface;

import android.annotation.NonNull;
import android.annotation.SuppressLint;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@@ -64,8 +57,6 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.window.ScreenCaptureInternal;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

import androidx.annotation.Nullable;

@@ -77,9 +68,7 @@ import com.android.wm.shell.R;
import com.android.wm.shell.common.AlphaOptimizedButton;
import com.android.wm.shell.shared.TriangleShape;
import com.android.wm.shell.shared.TypefaceUtils;
import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
import com.android.wm.shell.taskview.TaskView;
import com.android.wm.shell.taskview.TaskViewTaskController;

import java.io.PrintWriter;

@@ -204,160 +193,7 @@ public class BubbleExpandedView extends LinearLayout {
     */
    private final FrameLayout mExpandedViewContainer = new FrameLayout(getContext());

    private TaskView.Listener mCurrentTaskViewListener;

    private final TaskView.Listener mTaskViewListener = new TaskView.Listener() {
        private boolean mInitialized = false;
        private boolean mDestroyed = false;

        @Override
        public void onInitialized() {
            if (mDestroyed || mInitialized) {
                ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: destroyed=%b initialized=%b bubble=%s",
                        mDestroyed, mInitialized, getBubbleKey());
                return;
            }

            // Custom options so there is no activity transition animation
            ActivityOptions options = ActivityOptions.makeCustomAnimation(getContext(),
                    0 /* enterResId */, 0 /* exitResId */);

            // TODO: I notice inconsistencies in lifecycle
            // Post to keep the lifecycle normal
            post(() -> {
                ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s",
                        getBubbleKey());
                try {
                    Rect launchBounds = new Rect();
                    mTaskView.getBoundsOnScreen(launchBounds);

                    final WindowContainerToken rootToken = mManager.getAppBubbleRootTaskToken();
                    if (rootToken == null) {
                        options.setTaskAlwaysOnTop(true /* alwaysOnTop */);
                    }
                    options.setPendingIntentBackgroundActivityStartMode(
                            MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);

                    final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId()
                            || (mBubble.isShortcut()
                            && BubbleAnythingFlagHelper.enableCreateAnyBubble()));

                    // TODO - currently based on type, really it's what the "launch item" is.
                    if (mBubble.isApp() || mBubble.isNote()) {
                        Context context =
                                mContext.createContextAsUser(
                                        mBubble.getUser(), Context.CONTEXT_RESTRICTED);
                        Intent fillInIntent = new Intent();
                        PendingIntent pi = PendingIntent.getActivity(
                                context,
                                /* requestCode= */ 0,
                                mBubble.getIntent(),
                                // Needs to be mutable for the fillInIntent
                                PendingIntent.FLAG_MUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
                                /* options= */ null);
                        if (rootToken != null) {
                            options.setLaunchRootTask(rootToken);
                        } else {
                            options.setLaunchNextToBubble(true /* launchNextToBubble */);
                        }
                        mTaskView.startActivity(pi, fillInIntent, options, launchBounds);
                    } else if (!mIsOverflow && isShortcutBubble) {
                        ProtoLog.v(WM_SHELL_BUBBLES, "startingShortcutBubble=%s", getBubbleKey());
                        if (mBubble.isChat()) {
                            options.setLaunchedFromBubble(true);
                            options.setApplyActivityFlagsForBubbles(true);
                        } else {
                            if (rootToken != null) {
                                options.setLaunchRootTask(rootToken);
                            } else {
                                options.setLaunchNextToBubble(true /* launchNextToBubble */);
                            }
                            options.setApplyMultipleTaskFlagForShortcut(true);
                        }
                        mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
                                options, launchBounds);
                    } else {
                        options.setLaunchedFromBubble(true);
                        if (mBubble != null) {
                            mBubble.setPendingIntentActive();
                        }
                        final Intent fillInIntent = new Intent();
                        // Apply flags to make behaviour match documentLaunchMode=always.
                        fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
                        fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
                        mTaskView.startActivity(mPendingIntent, fillInIntent, options,
                                launchBounds);
                    }
                } catch (RuntimeException e) {
                    // If there's a runtime exception here then there's something
                    // wrong with the intent, we can't really recover / try to populate
                    // the bubble again so we'll just remove it.
                    Log.e(TAG, "Exception while displaying bubble: " + getBubbleKey()
                            + "; removing bubble", e);
                    mManager.removeBubble(getBubbleKey(), Bubbles.DISMISS_INVALID_INTENT);
                }
            });
            mInitialized = true;
        }

        @Override
        public void onReleased() {
            mDestroyed = true;
        }

        @Override
        public void onTaskCreated(int taskId, ComponentName name) {
            ProtoLog.d(WM_SHELL_BUBBLES, "onTaskCreated: taskId=%d bubble=%s",
                    taskId, getBubbleKey());
            // The taskId is saved to use for removeTask, preventing appearance in recent tasks.
            mTaskId = taskId;

            if (mBubble != null && mBubble.isNote()) {
                // Let the controller know sooner what the taskId is.
                mManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId);
            }

            final TaskViewTaskController tvc = mTaskView.getController();
            final boolean isAppBubble = mBubble != null
                    && (mBubble.isApp() || mBubble.isShortcut());
            final WindowContainerTransaction wct = getEnterBubbleTransaction(
                    tvc.getTaskToken(), mManager.getAppBubbleRootTaskToken(), isAppBubble);
            tvc.getTaskOrganizer().applyTransaction(wct);

            // With the task org, the taskAppeared callback will only happen once the task has
            // already drawn
            setContentVisibility(true);
        }

        @Override
        public void onTaskVisibilityChanged(int taskId, boolean visible) {
            ProtoLog.d(WM_SHELL_BUBBLES, "onTaskVisibilityChanged=%b bubble=%s taskId=%d",
                    visible, getBubbleKey(), taskId);
            setContentVisibility(visible);
        }

        @Override
        public void onTaskRemovalStarted(int taskId) {
            ProtoLog.d(WM_SHELL_BUBBLES, "onTaskRemovalStarted: taskId=%d bubble=%s",
                    taskId, getBubbleKey());
            if (mBubble != null) {
                mManager.removeBubble(mBubble.getKey(), Bubbles.DISMISS_TASK_FINISHED);
            }
            if (mTaskView != null) {
                // Release the surface
                mTaskView.release();
                removeView(mTaskView);
                mTaskView = null;
            }
        }

        @Override
        public void onBackPressedOnTaskRoot(int taskId) {
            if (mTaskId == taskId && mStackView.isExpanded()) {
                mStackView.onBackPressed();
            }
        }
    };
    private BubbleTaskViewListener mTaskViewListener;

    public BubbleExpandedView(Context context) {
        this(context, null);
@@ -488,16 +324,15 @@ public class BubbleExpandedView extends LinearLayout {
            mTaskView = bubbleTaskView.getTaskView();
            // reset the insets that might left after TaskView is shown in BubbleBarExpandedView
            mTaskView.setCaptionInsets(null);
            if (Flags.enableBubbleTaskViewListener()) {
                mCurrentTaskViewListener = new BubbleTaskViewListener(mContext, bubbleTaskView,
            mTaskViewListener = new BubbleTaskViewListener(mContext, bubbleTaskView,
                    /* viewParent= */ this, expandedViewManager,
                    new BubbleTaskViewListener.Callback() {
                        @Override
                        public void onTaskCreated() {
                            // The taskId is saved to use for removeTask,
                            // preventing appearance in recent tasks.
                                BubbleTaskViewListener listener = mCurrentTaskViewListener != null
                                        ? ((BubbleTaskViewListener) mCurrentTaskViewListener)
                            BubbleTaskViewListener listener = mTaskViewListener != null
                                    ? mTaskViewListener
                                    : null;
                            mTaskId = listener != null
                                    ? listener.getTaskId()
@@ -525,10 +360,6 @@ public class BubbleExpandedView extends LinearLayout {
                            // nothing to do / handled in listener.
                        }
                    });
            } else {
                mCurrentTaskViewListener = mTaskViewListener;
                bubbleTaskView.setDelegateListener(mCurrentTaskViewListener);
            }

            // set a fixed width so it is not recalculated as part of a rotation. the width will be
            // updated manually after the rotation.
@@ -539,13 +370,6 @@ public class BubbleExpandedView extends LinearLayout {
            }
            mExpandedViewContainer.addView(mTaskView, lp);
            bringChildToFront(mTaskView);

            if (!Flags.enableBubbleTaskViewListener()) {
                if (bubbleTaskView.isCreated()) {
                    mCurrentTaskViewListener.onTaskCreated(
                            bubbleTaskView.getTaskId(), bubbleTaskView.getComponentName());
                }
            }
        }
    }

@@ -981,13 +805,8 @@ public class BubbleExpandedView extends LinearLayout {
            Log.w(TAG, "Stack is null for bubble: " + bubble);
            return;
        }
        boolean isNew;
        if (mCurrentTaskViewListener instanceof BubbleTaskViewListener) {
            isNew = ((BubbleTaskViewListener) mCurrentTaskViewListener).setBubble(bubble);
        } else {
            isNew = mBubble == null || didBackingContentChange(bubble);
        }
        boolean isUpdate = bubble != null && mBubble != null
        final boolean isNew = mTaskViewListener.setBubble(bubble);
        final boolean isUpdate = bubble != null && mBubble != null
                && bubble.getKey().equals(mBubble.getKey());
        ProtoLog.d(WM_SHELL_BUBBLES, "BubbleExpandedView - update bubble=%s; isNew=%b; isUpdate=%b",
                bubble.getKey(), isNew, isUpdate);
@@ -1023,23 +842,6 @@ public class BubbleExpandedView extends LinearLayout {
        }
    }

    /**
     * Bubbles are backed by a pending intent or a shortcut, once the activity is
     * started we never change it / restart it on notification updates -- unless the bubbles'
     * backing data switches.
     *
     * This indicates if the new bubble is backed by a different data source than what was
     * previously shown here (e.g. previously a pending intent & now a shortcut).
     *
     * @param newBubble the bubble this view is being updated with.
     * @return true if the backing content has changed.
     */
    private boolean didBackingContentChange(Bubble newBubble) {
        boolean prevWasIntentBased = mBubble != null && mPendingIntent != null;
        boolean newIsIntentBased = newBubble.getPendingIntent() != null;
        return prevWasIntentBased != newIsIntentBased;
    }

    /**
     * Whether the bubble is using all available height to display or not.
     */