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

Commit c7211bdd authored by Steven Ng's avatar Steven Ng Committed by Android (Google) Code Review
Browse files

Merge "Add multi-users support to app bubbles" into udc-dev

parents 0889fb51 3331b99f
Loading
Loading
Loading
Loading
+40 −5
Original line number Original line Diff line number Diff line
@@ -64,7 +64,11 @@ import java.util.concurrent.Executor;
public class Bubble implements BubbleViewProvider {
public class Bubble implements BubbleViewProvider {
    private static final String TAG = "Bubble";
    private static final String TAG = "Bubble";


    public static final String KEY_APP_BUBBLE = "key_app_bubble";
    /** A string suffix used in app bubbles' {@link #mKey}. */
    private static final String KEY_APP_BUBBLE = "key_app_bubble";

    /** Whether the bubble is an app bubble. */
    private final boolean mIsAppBubble;


    private final String mKey;
    private final String mKey;
    @Nullable
    @Nullable
@@ -181,7 +185,7 @@ public class Bubble implements BubbleViewProvider {
    private PendingIntent mDeleteIntent;
    private PendingIntent mDeleteIntent;


    /**
    /**
     * Used only for a special bubble in the stack that has the key {@link #KEY_APP_BUBBLE}.
     * Used only for a special bubble in the stack that has {@link #mIsAppBubble} set to true.
     * There can only be one of these bubbles in the stack and this intent will be populated for
     * There can only be one of these bubbles in the stack and this intent will be populated for
     * that bubble.
     * that bubble.
     */
     */
@@ -216,24 +220,54 @@ public class Bubble implements BubbleViewProvider {
        mMainExecutor = mainExecutor;
        mMainExecutor = mainExecutor;
        mTaskId = taskId;
        mTaskId = taskId;
        mBubbleMetadataFlagListener = listener;
        mBubbleMetadataFlagListener = listener;
        mIsAppBubble = false;
    }
    }


    public Bubble(Intent intent,
    private Bubble(
            Intent intent,
            UserHandle user,
            UserHandle user,
            @Nullable Icon icon,
            @Nullable Icon icon,
            boolean isAppBubble,
            String key,
            Executor mainExecutor) {
            Executor mainExecutor) {
        mKey = KEY_APP_BUBBLE;
        mGroupKey = null;
        mGroupKey = null;
        mLocusId = null;
        mLocusId = null;
        mFlags = 0;
        mFlags = 0;
        mUser = user;
        mUser = user;
        mIcon = icon;
        mIcon = icon;
        mIsAppBubble = isAppBubble;
        mKey = key;
        mShowBubbleUpdateDot = false;
        mShowBubbleUpdateDot = false;
        mMainExecutor = mainExecutor;
        mMainExecutor = mainExecutor;
        mTaskId = INVALID_TASK_ID;
        mTaskId = INVALID_TASK_ID;
        mAppIntent = intent;
        mAppIntent = intent;
        mDesiredHeight = Integer.MAX_VALUE;
        mDesiredHeight = Integer.MAX_VALUE;
        mPackageName = intent.getPackage();
        mPackageName = intent.getPackage();

    }

    /** Creates an app bubble. */
    public static Bubble createAppBubble(
            Intent intent,
            UserHandle user,
            @Nullable Icon icon,
            Executor mainExecutor) {
        return new Bubble(intent,
                user,
                icon,
                /* isAppBubble= */ true,
                /* key= */ getAppBubbleKeyForApp(intent.getPackage(), user),
                mainExecutor);
    }

    /**
     * Returns the key for an app bubble from an app with package name, {@code packageName} on an
     * Android user, {@code user}.
     */
    public static String getAppBubbleKeyForApp(String packageName, UserHandle user) {
        Objects.requireNonNull(packageName);
        Objects.requireNonNull(user);
        return KEY_APP_BUBBLE + ":" + user.getIdentifier()  + ":" + packageName;
    }
    }


    @VisibleForTesting(visibility = PRIVATE)
    @VisibleForTesting(visibility = PRIVATE)
@@ -241,6 +275,7 @@ public class Bubble implements BubbleViewProvider {
            final Bubbles.BubbleMetadataFlagListener listener,
            final Bubbles.BubbleMetadataFlagListener listener,
            final Bubbles.PendingIntentCanceledListener intentCancelListener,
            final Bubbles.PendingIntentCanceledListener intentCancelListener,
            Executor mainExecutor) {
            Executor mainExecutor) {
        mIsAppBubble = false;
        mKey = entry.getKey();
        mKey = entry.getKey();
        mGroupKey = entry.getGroupKey();
        mGroupKey = entry.getGroupKey();
        mLocusId = entry.getLocusId();
        mLocusId = entry.getLocusId();
@@ -815,7 +850,7 @@ public class Bubble implements BubbleViewProvider {
    }
    }


    boolean isAppBubble() {
    boolean isAppBubble() {
        return KEY_APP_BUBBLE.equals(mKey);
        return mIsAppBubble;
    }
    }


    Intent getSettingsIntent(final Context context) {
    Intent getSettingsIntent(final Context context) {
+16 −15
Original line number Original line Diff line number Diff line
@@ -24,7 +24,6 @@ import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;


import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
@@ -1193,14 +1192,15 @@ public class BubbleController implements ConfigurationChangeListener,
            return;
            return;
        }
        }


        String appBubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user);
        PackageManager packageManager = getPackageManagerForUser(mContext, user.getIdentifier());
        PackageManager packageManager = getPackageManagerForUser(mContext, user.getIdentifier());
        if (!isResizableActivity(intent, packageManager, KEY_APP_BUBBLE)) return;
        if (!isResizableActivity(intent, packageManager, appBubbleKey)) return;


        Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE);
        Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(appBubbleKey);
        if (existingAppBubble != null) {
        if (existingAppBubble != null) {
            BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
            BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
            if (isStackExpanded()) {
            if (isStackExpanded()) {
                if (selectedBubble != null && KEY_APP_BUBBLE.equals(selectedBubble.getKey())) {
                if (selectedBubble != null && appBubbleKey.equals(selectedBubble.getKey())) {
                    // App bubble is expanded, lets collapse
                    // App bubble is expanded, lets collapse
                    collapseStack();
                    collapseStack();
                } else {
                } else {
@@ -1214,7 +1214,7 @@ public class BubbleController implements ConfigurationChangeListener,
            }
            }
        } else {
        } else {
            // App bubble does not exist, lets add and expand it
            // App bubble does not exist, lets add and expand it
            Bubble b = new Bubble(intent, user, icon, mMainExecutor);
            Bubble b = Bubble.createAppBubble(intent, user, icon, mMainExecutor);
            b.setShouldAutoExpand(true);
            b.setShouldAutoExpand(true);
            inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
            inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
        }
        }
@@ -1247,8 +1247,8 @@ public class BubbleController implements ConfigurationChangeListener,
    }
    }


    /** Sets the app bubble's taskId which is cached for SysUI. */
    /** Sets the app bubble's taskId which is cached for SysUI. */
    public void setAppBubbleTaskId(int taskId) {
    public void setAppBubbleTaskId(String key, int taskId) {
        mImpl.mCachedState.setAppBubbleTaskId(taskId);
        mImpl.mCachedState.setAppBubbleTaskId(key, taskId);
    }
    }


    /**
    /**
@@ -2045,7 +2045,8 @@ public class BubbleController implements ConfigurationChangeListener,
            private HashSet<String> mSuppressedBubbleKeys = new HashSet<>();
            private HashSet<String> mSuppressedBubbleKeys = new HashSet<>();
            private HashMap<String, String> mSuppressedGroupToNotifKeys = new HashMap<>();
            private HashMap<String, String> mSuppressedGroupToNotifKeys = new HashMap<>();
            private HashMap<String, Bubble> mShortcutIdToBubble = new HashMap<>();
            private HashMap<String, Bubble> mShortcutIdToBubble = new HashMap<>();
            private int mAppBubbleTaskId = INVALID_TASK_ID;

            private HashMap<String, Integer> mAppBubbleTaskIds = new HashMap();


            private ArrayList<Bubble> mTmpBubbles = new ArrayList<>();
            private ArrayList<Bubble> mTmpBubbles = new ArrayList<>();


@@ -2077,20 +2078,20 @@ public class BubbleController implements ConfigurationChangeListener,


                mSuppressedBubbleKeys.clear();
                mSuppressedBubbleKeys.clear();
                mShortcutIdToBubble.clear();
                mShortcutIdToBubble.clear();
                mAppBubbleTaskId = INVALID_TASK_ID;
                mAppBubbleTaskIds.clear();
                for (Bubble b : mTmpBubbles) {
                for (Bubble b : mTmpBubbles) {
                    mShortcutIdToBubble.put(b.getShortcutId(), b);
                    mShortcutIdToBubble.put(b.getShortcutId(), b);
                    updateBubbleSuppressedState(b);
                    updateBubbleSuppressedState(b);


                    if (KEY_APP_BUBBLE.equals(b.getKey())) {
                    if (b.isAppBubble()) {
                        mAppBubbleTaskId = b.getTaskId();
                        mAppBubbleTaskIds.put(b.getKey(), b.getTaskId());
                    }
                    }
                }
                }
            }
            }


            /** Sets the app bubble's taskId which is cached for SysUI. */
            /** Sets the app bubble's taskId which is cached for SysUI. */
            synchronized void setAppBubbleTaskId(int taskId) {
            synchronized void setAppBubbleTaskId(String key, int taskId) {
                mAppBubbleTaskId = taskId;
                mAppBubbleTaskIds.put(key, taskId);
            }
            }


            /**
            /**
@@ -2143,7 +2144,7 @@ public class BubbleController implements ConfigurationChangeListener,
                    pw.println("   suppressing: " + key);
                    pw.println("   suppressing: " + key);
                }
                }


                pw.print("mAppBubbleTaskId: " + mAppBubbleTaskId);
                pw.print("mAppBubbleTaskIds: " + mAppBubbleTaskIds.values());
            }
            }
        }
        }


@@ -2205,7 +2206,7 @@ public class BubbleController implements ConfigurationChangeListener,


        @Override
        @Override
        public boolean isAppBubbleTaskId(int taskId) {
        public boolean isAppBubbleTaskId(int taskId) {
            return mCachedState.mAppBubbleTaskId == taskId;
            return mCachedState.mAppBubbleTaskIds.values().contains(taskId);
        }
        }


        @Override
        @Override
+1 −2
Original line number Original line Diff line number Diff line
@@ -17,7 +17,6 @@ package com.android.wm.shell.bubbles;


import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
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.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
@@ -780,7 +779,7 @@ public class BubbleData {
                || !(reason == Bubbles.DISMISS_AGED
                || !(reason == Bubbles.DISMISS_AGED
                || reason == Bubbles.DISMISS_USER_GESTURE
                || reason == Bubbles.DISMISS_USER_GESTURE
                || reason == Bubbles.DISMISS_RELOAD_FROM_DISK)
                || reason == Bubbles.DISMISS_RELOAD_FROM_DISK)
                || KEY_APP_BUBBLE.equals(bubble.getKey())) {
                || bubble.isAppBubble()) {
            return;
            return;
        }
        }
        if (DEBUG_BUBBLE_DATA) {
        if (DEBUG_BUBBLE_DATA) {
+2 −2
Original line number Original line Diff line number Diff line
@@ -287,9 +287,9 @@ public class BubbleExpandedView extends LinearLayout {
            // The taskId is saved to use for removeTask, preventing appearance in recent tasks.
            // The taskId is saved to use for removeTask, preventing appearance in recent tasks.
            mTaskId = taskId;
            mTaskId = taskId;


            if (Bubble.KEY_APP_BUBBLE.equals(getBubbleKey())) {
            if (mBubble != null && mBubble.isAppBubble()) {
                // Let the controller know sooner what the taskId is.
                // Let the controller know sooner what the taskId is.
                mController.setAppBubbleTaskId(mTaskId);
                mController.setAppBubbleTaskId(mBubble.getKey(), mTaskId);
            }
            }


            // With the task org, the taskAppeared callback will only happen once the task has
            // With the task org, the taskAppeared callback will only happen once the task has
+9 −7
Original line number Original line Diff line number Diff line
@@ -16,8 +16,6 @@


package com.android.wm.shell.bubbles;
package com.android.wm.shell.bubbles;


import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.Truth.assertWithMessage;


@@ -185,7 +183,10 @@ public class BubbleDataTest extends ShellTestCase {


        Intent appBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
        Intent appBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
        appBubbleIntent.setPackage(mContext.getPackageName());
        appBubbleIntent.setPackage(mContext.getPackageName());
        mAppBubble = new Bubble(appBubbleIntent, new UserHandle(1), mock(Icon.class),
        mAppBubble = Bubble.createAppBubble(
                appBubbleIntent,
                new UserHandle(1),
                mock(Icon.class),
                mMainExecutor);
                mMainExecutor);


        mPositioner = new TestableBubblePositioner(mContext,
        mPositioner = new TestableBubblePositioner(mContext,
@@ -1101,14 +1102,15 @@ public class BubbleDataTest extends ShellTestCase {


    @Test
    @Test
    public void test_removeAppBubble_skipsOverflow() {
    public void test_removeAppBubble_skipsOverflow() {
        String appBubbleKey = mAppBubble.getKey();
        mBubbleData.notificationEntryUpdated(mAppBubble, true /* suppressFlyout*/,
        mBubbleData.notificationEntryUpdated(mAppBubble, true /* suppressFlyout*/,
                false /* showInShade */);
                false /* showInShade */);
        assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isEqualTo(mAppBubble);
        assertThat(mBubbleData.getBubbleInStackWithKey(appBubbleKey)).isEqualTo(mAppBubble);


        mBubbleData.dismissBubbleWithKey(KEY_APP_BUBBLE, Bubbles.DISMISS_USER_GESTURE);
        mBubbleData.dismissBubbleWithKey(appBubbleKey, Bubbles.DISMISS_USER_GESTURE);


        assertThat(mBubbleData.getOverflowBubbleWithKey(KEY_APP_BUBBLE)).isNull();
        assertThat(mBubbleData.getOverflowBubbleWithKey(appBubbleKey)).isNull();
        assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull();
        assertThat(mBubbleData.getBubbleInStackWithKey(appBubbleKey)).isNull();
    }
    }


    private void verifyUpdateReceived() {
    private void verifyUpdateReceived() {
Loading