Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +40 −5 Original line number Diff line number Diff line Loading @@ -64,7 +64,11 @@ import java.util.concurrent.Executor; public class Bubble implements BubbleViewProvider { 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; @Nullable Loading Loading @@ -181,7 +185,7 @@ public class Bubble implements BubbleViewProvider { 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 * that bubble. */ Loading Loading @@ -216,24 +220,54 @@ public class Bubble implements BubbleViewProvider { mMainExecutor = mainExecutor; mTaskId = taskId; mBubbleMetadataFlagListener = listener; mIsAppBubble = false; } public Bubble(Intent intent, private Bubble( Intent intent, UserHandle user, @Nullable Icon icon, boolean isAppBubble, String key, Executor mainExecutor) { mKey = KEY_APP_BUBBLE; mGroupKey = null; mLocusId = null; mFlags = 0; mUser = user; mIcon = icon; mIsAppBubble = isAppBubble; mKey = key; mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; mTaskId = INVALID_TASK_ID; mAppIntent = intent; mDesiredHeight = Integer.MAX_VALUE; 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) Loading @@ -241,6 +275,7 @@ public class Bubble implements BubbleViewProvider { final Bubbles.BubbleMetadataFlagListener listener, final Bubbles.PendingIntentCanceledListener intentCancelListener, Executor mainExecutor) { mIsAppBubble = false; mKey = entry.getKey(); mGroupKey = entry.getGroupKey(); mLocusId = entry.getLocusId(); Loading Loading @@ -815,7 +850,7 @@ public class Bubble implements BubbleViewProvider { } boolean isAppBubble() { return KEY_APP_BUBBLE.equals(mKey); return mIsAppBubble; } Intent getSettingsIntent(final Context context) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +16 −15 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; 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_GESTURE; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; Loading Loading @@ -1193,14 +1192,15 @@ public class BubbleController implements ConfigurationChangeListener, return; } String appBubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user); 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) { BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble(); if (isStackExpanded()) { if (selectedBubble != null && KEY_APP_BUBBLE.equals(selectedBubble.getKey())) { if (selectedBubble != null && appBubbleKey.equals(selectedBubble.getKey())) { // App bubble is expanded, lets collapse collapseStack(); } else { Loading @@ -1214,7 +1214,7 @@ public class BubbleController implements ConfigurationChangeListener, } } else { // 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); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); } Loading Loading @@ -1247,8 +1247,8 @@ public class BubbleController implements ConfigurationChangeListener, } /** Sets the app bubble's taskId which is cached for SysUI. */ public void setAppBubbleTaskId(int taskId) { mImpl.mCachedState.setAppBubbleTaskId(taskId); public void setAppBubbleTaskId(String key, int taskId) { mImpl.mCachedState.setAppBubbleTaskId(key, taskId); } /** Loading Loading @@ -2045,7 +2045,8 @@ public class BubbleController implements ConfigurationChangeListener, private HashSet<String> mSuppressedBubbleKeys = new HashSet<>(); private HashMap<String, String> mSuppressedGroupToNotifKeys = 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<>(); Loading Loading @@ -2077,20 +2078,20 @@ public class BubbleController implements ConfigurationChangeListener, mSuppressedBubbleKeys.clear(); mShortcutIdToBubble.clear(); mAppBubbleTaskId = INVALID_TASK_ID; mAppBubbleTaskIds.clear(); for (Bubble b : mTmpBubbles) { mShortcutIdToBubble.put(b.getShortcutId(), b); updateBubbleSuppressedState(b); if (KEY_APP_BUBBLE.equals(b.getKey())) { mAppBubbleTaskId = b.getTaskId(); if (b.isAppBubble()) { mAppBubbleTaskIds.put(b.getKey(), b.getTaskId()); } } } /** Sets the app bubble's taskId which is cached for SysUI. */ synchronized void setAppBubbleTaskId(int taskId) { mAppBubbleTaskId = taskId; synchronized void setAppBubbleTaskId(String key, int taskId) { mAppBubbleTaskIds.put(key, taskId); } /** Loading Loading @@ -2143,7 +2144,7 @@ public class BubbleController implements ConfigurationChangeListener, pw.println(" suppressing: " + key); } pw.print("mAppBubbleTaskId: " + mAppBubbleTaskId); pw.print("mAppBubbleTaskIds: " + mAppBubbleTaskIds.values()); } } Loading Loading @@ -2205,7 +2206,7 @@ public class BubbleController implements ConfigurationChangeListener, @Override public boolean isAppBubbleTaskId(int taskId) { return mCachedState.mAppBubbleTaskId == taskId; return mCachedState.mAppBubbleTaskIds.values().contains(taskId); } @Override Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +1 −2 Original line number Diff line number Diff line Loading @@ -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.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.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; Loading Loading @@ -780,7 +779,7 @@ public class BubbleData { || !(reason == Bubbles.DISMISS_AGED || reason == Bubbles.DISMISS_USER_GESTURE || reason == Bubbles.DISMISS_RELOAD_FROM_DISK) || KEY_APP_BUBBLE.equals(bubble.getKey())) { || bubble.isAppBubble()) { return; } if (DEBUG_BUBBLE_DATA) { Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +2 −2 Original line number Diff line number Diff line Loading @@ -287,9 +287,9 @@ public class BubbleExpandedView extends LinearLayout { // The taskId is saved to use for removeTask, preventing appearance in recent tasks. mTaskId = taskId; if (Bubble.KEY_APP_BUBBLE.equals(getBubbleKey())) { if (mBubble != null && mBubble.isAppBubble()) { // 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 Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +9 −7 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ 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.assertWithMessage; Loading Loading @@ -185,7 +183,10 @@ public class BubbleDataTest extends ShellTestCase { Intent appBubbleIntent = new Intent(mContext, BubblesTestActivity.class); 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); mPositioner = new TestableBubblePositioner(mContext, Loading Loading @@ -1101,14 +1102,15 @@ public class BubbleDataTest extends ShellTestCase { @Test public void test_removeAppBubble_skipsOverflow() { String appBubbleKey = mAppBubble.getKey(); mBubbleData.notificationEntryUpdated(mAppBubble, true /* suppressFlyout*/, 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.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull(); assertThat(mBubbleData.getOverflowBubbleWithKey(appBubbleKey)).isNull(); assertThat(mBubbleData.getBubbleInStackWithKey(appBubbleKey)).isNull(); } private void verifyUpdateReceived() { Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +40 −5 Original line number Diff line number Diff line Loading @@ -64,7 +64,11 @@ import java.util.concurrent.Executor; public class Bubble implements BubbleViewProvider { 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; @Nullable Loading Loading @@ -181,7 +185,7 @@ public class Bubble implements BubbleViewProvider { 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 * that bubble. */ Loading Loading @@ -216,24 +220,54 @@ public class Bubble implements BubbleViewProvider { mMainExecutor = mainExecutor; mTaskId = taskId; mBubbleMetadataFlagListener = listener; mIsAppBubble = false; } public Bubble(Intent intent, private Bubble( Intent intent, UserHandle user, @Nullable Icon icon, boolean isAppBubble, String key, Executor mainExecutor) { mKey = KEY_APP_BUBBLE; mGroupKey = null; mLocusId = null; mFlags = 0; mUser = user; mIcon = icon; mIsAppBubble = isAppBubble; mKey = key; mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; mTaskId = INVALID_TASK_ID; mAppIntent = intent; mDesiredHeight = Integer.MAX_VALUE; 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) Loading @@ -241,6 +275,7 @@ public class Bubble implements BubbleViewProvider { final Bubbles.BubbleMetadataFlagListener listener, final Bubbles.PendingIntentCanceledListener intentCancelListener, Executor mainExecutor) { mIsAppBubble = false; mKey = entry.getKey(); mGroupKey = entry.getGroupKey(); mLocusId = entry.getLocusId(); Loading Loading @@ -815,7 +850,7 @@ public class Bubble implements BubbleViewProvider { } boolean isAppBubble() { return KEY_APP_BUBBLE.equals(mKey); return mIsAppBubble; } Intent getSettingsIntent(final Context context) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +16 −15 Original line number Diff line number Diff line Loading @@ -24,7 +24,6 @@ import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; 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_GESTURE; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES; Loading Loading @@ -1193,14 +1192,15 @@ public class BubbleController implements ConfigurationChangeListener, return; } String appBubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user); 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) { BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble(); if (isStackExpanded()) { if (selectedBubble != null && KEY_APP_BUBBLE.equals(selectedBubble.getKey())) { if (selectedBubble != null && appBubbleKey.equals(selectedBubble.getKey())) { // App bubble is expanded, lets collapse collapseStack(); } else { Loading @@ -1214,7 +1214,7 @@ public class BubbleController implements ConfigurationChangeListener, } } else { // 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); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); } Loading Loading @@ -1247,8 +1247,8 @@ public class BubbleController implements ConfigurationChangeListener, } /** Sets the app bubble's taskId which is cached for SysUI. */ public void setAppBubbleTaskId(int taskId) { mImpl.mCachedState.setAppBubbleTaskId(taskId); public void setAppBubbleTaskId(String key, int taskId) { mImpl.mCachedState.setAppBubbleTaskId(key, taskId); } /** Loading Loading @@ -2045,7 +2045,8 @@ public class BubbleController implements ConfigurationChangeListener, private HashSet<String> mSuppressedBubbleKeys = new HashSet<>(); private HashMap<String, String> mSuppressedGroupToNotifKeys = 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<>(); Loading Loading @@ -2077,20 +2078,20 @@ public class BubbleController implements ConfigurationChangeListener, mSuppressedBubbleKeys.clear(); mShortcutIdToBubble.clear(); mAppBubbleTaskId = INVALID_TASK_ID; mAppBubbleTaskIds.clear(); for (Bubble b : mTmpBubbles) { mShortcutIdToBubble.put(b.getShortcutId(), b); updateBubbleSuppressedState(b); if (KEY_APP_BUBBLE.equals(b.getKey())) { mAppBubbleTaskId = b.getTaskId(); if (b.isAppBubble()) { mAppBubbleTaskIds.put(b.getKey(), b.getTaskId()); } } } /** Sets the app bubble's taskId which is cached for SysUI. */ synchronized void setAppBubbleTaskId(int taskId) { mAppBubbleTaskId = taskId; synchronized void setAppBubbleTaskId(String key, int taskId) { mAppBubbleTaskIds.put(key, taskId); } /** Loading Loading @@ -2143,7 +2144,7 @@ public class BubbleController implements ConfigurationChangeListener, pw.println(" suppressing: " + key); } pw.print("mAppBubbleTaskId: " + mAppBubbleTaskId); pw.print("mAppBubbleTaskIds: " + mAppBubbleTaskIds.values()); } } Loading Loading @@ -2205,7 +2206,7 @@ public class BubbleController implements ConfigurationChangeListener, @Override public boolean isAppBubbleTaskId(int taskId) { return mCachedState.mAppBubbleTaskId == taskId; return mCachedState.mAppBubbleTaskIds.values().contains(taskId); } @Override Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +1 −2 Original line number Diff line number Diff line Loading @@ -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.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.TAG_BUBBLES; import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; Loading Loading @@ -780,7 +779,7 @@ public class BubbleData { || !(reason == Bubbles.DISMISS_AGED || reason == Bubbles.DISMISS_USER_GESTURE || reason == Bubbles.DISMISS_RELOAD_FROM_DISK) || KEY_APP_BUBBLE.equals(bubble.getKey())) { || bubble.isAppBubble()) { return; } if (DEBUG_BUBBLE_DATA) { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +2 −2 Original line number Diff line number Diff line Loading @@ -287,9 +287,9 @@ public class BubbleExpandedView extends LinearLayout { // The taskId is saved to use for removeTask, preventing appearance in recent tasks. mTaskId = taskId; if (Bubble.KEY_APP_BUBBLE.equals(getBubbleKey())) { if (mBubble != null && mBubble.isAppBubble()) { // 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 Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleDataTest.java +9 −7 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ 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.assertWithMessage; Loading Loading @@ -185,7 +183,10 @@ public class BubbleDataTest extends ShellTestCase { Intent appBubbleIntent = new Intent(mContext, BubblesTestActivity.class); 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); mPositioner = new TestableBubblePositioner(mContext, Loading Loading @@ -1101,14 +1102,15 @@ public class BubbleDataTest extends ShellTestCase { @Test public void test_removeAppBubble_skipsOverflow() { String appBubbleKey = mAppBubble.getKey(); mBubbleData.notificationEntryUpdated(mAppBubble, true /* suppressFlyout*/, 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.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull(); assertThat(mBubbleData.getOverflowBubbleWithKey(appBubbleKey)).isNull(); assertThat(mBubbleData.getBubbleInStackWithKey(appBubbleKey)).isNull(); } private void verifyUpdateReceived() { Loading