Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +3 −1 Original line number Diff line number Diff line Loading @@ -357,7 +357,9 @@ public class BadgedImageView extends ConstraintLayout { void showBadge() { Bitmap appBadgeBitmap = mBubble.getAppBadge(); if (appBadgeBitmap == null) { final boolean isAppLaunchIntent = (mBubble instanceof Bubble) && ((Bubble) mBubble).isAppLaunchIntent(); if (appBadgeBitmap == null || isAppLaunchIntent) { mAppIcon.setVisibility(GONE); return; } Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +43 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ 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.bar.BubbleBarExpandedView; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; import com.android.wm.shell.common.bubbles.BubbleInfo; Loading Loading @@ -246,7 +247,23 @@ public class Bubble implements BubbleViewProvider { mAppIntent = intent; mDesiredHeight = Integer.MAX_VALUE; mPackageName = intent.getPackage(); } private Bubble(ShortcutInfo info, Executor mainExecutor) { mGroupKey = null; mLocusId = null; mFlags = 0; mUser = info.getUserHandle(); mIcon = info.getIcon(); mIsAppBubble = false; mKey = getBubbleKeyForShortcut(info); mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; mTaskId = INVALID_TASK_ID; mAppIntent = null; mDesiredHeight = Integer.MAX_VALUE; mPackageName = info.getPackage(); mShortcutInfo = info; } /** Creates an app bubble. */ Loading @@ -263,6 +280,13 @@ public class Bubble implements BubbleViewProvider { mainExecutor); } /** Creates a shortcut bubble. */ public static Bubble createShortcutBubble( ShortcutInfo info, Executor mainExecutor) { return new Bubble(info, mainExecutor); } /** * Returns the key for an app bubble from an app with package name, {@code packageName} on an * Android user, {@code user}. Loading @@ -273,6 +297,14 @@ public class Bubble implements BubbleViewProvider { return KEY_APP_BUBBLE + ":" + user.getIdentifier() + ":" + packageName; } /** * Returns the key for a shortcut bubble using {@code packageName}, {@code user}, and the * {@code shortcutInfo} id. */ public static String getBubbleKeyForShortcut(ShortcutInfo info) { return info.getPackage() + ":" + info.getUserId() + ":" + info.getId(); } @VisibleForTesting(visibility = PRIVATE) public Bubble(@NonNull final BubbleEntry entry, final Bubbles.BubbleMetadataFlagListener listener, Loading Loading @@ -888,6 +920,17 @@ public class Bubble implements BubbleViewProvider { return mIntent; } /** * Whether this bubble represents the full app, i.e. the intent used is the launch * intent for an app. In this case we don't show a badge on the icon. */ public boolean isAppLaunchIntent() { if (Flags.enableBubbleAnything() && mAppIntent != null) { return mAppIntent.hasCategory("android.intent.category.LAUNCHER"); } return false; } @Nullable PendingIntent getDeleteIntent() { return mDeleteIntent; Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +52 −0 Original line number Diff line number Diff line Loading @@ -1334,6 +1334,40 @@ public class BubbleController implements ConfigurationChangeListener, } } /** * Expands and selects a bubble created or found via the provided shortcut info. * * @param info the shortcut info for the bubble. */ public void expandStackAndSelectBubble(ShortcutInfo info) { if (!Flags.enableBubbleAnything()) return; Bubble b = mBubbleData.getOrCreateBubble(info); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - shortcut=%s", info); if (b.isInflated()) { mBubbleData.setSelectedBubbleAndExpandStack(b); } else { b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); } } /** * Expands and selects a bubble created or found for this app. * * @param intent the intent for the bubble. */ public void expandStackAndSelectBubble(Intent intent) { if (!Flags.enableBubbleAnything()) return; Bubble b = mBubbleData.getOrCreateBubble(intent); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", intent); if (b.isInflated()) { mBubbleData.setSelectedBubbleAndExpandStack(b); } else { b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); } } /** * Expands and selects a bubble based on the provided {@link BubbleEntry}. If no bubble * exists for this entry, and it is able to bubble, a new bubble will be created. Loading Loading @@ -2323,6 +2357,7 @@ public class BubbleController implements ConfigurationChangeListener, * @param entry the entry to bubble. */ static boolean canLaunchInTaskView(Context context, BubbleEntry entry) { if (Flags.enableBubbleAnything()) return true; PendingIntent intent = entry.getBubbleMetadata() != null ? entry.getBubbleMetadata().getIntent() : null; Loading Loading @@ -2438,6 +2473,16 @@ public class BubbleController implements ConfigurationChangeListener, mMainExecutor.execute(mListener::unregister); } @Override public void showShortcutBubble(ShortcutInfo info) { mMainExecutor.execute(() -> mController.expandStackAndSelectBubble(info)); } @Override public void showAppBubble(Intent intent) { mMainExecutor.execute(() -> mController.expandStackAndSelectBubble(intent)); } @Override public void showBubble(String key, int topOnScreen) { mMainExecutor.execute( Loading Loading @@ -2633,6 +2678,13 @@ public class BubbleController implements ConfigurationChangeListener, }); } @Override public void expandStackAndSelectBubble(ShortcutInfo info) { mMainExecutor.execute(() -> { BubbleController.this.expandStackAndSelectBubble(info); }); } @Override public void expandStackAndSelectBubble(Bubble bubble) { mMainExecutor.execute(() -> { Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +54 −16 Original line number Diff line number Diff line Loading @@ -23,8 +23,10 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES; import android.annotation.NonNull; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.LocusId; import android.content.pm.ShortcutInfo; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; Loading Loading @@ -421,25 +423,21 @@ public class BubbleData { Bubble bubbleToReturn = getBubbleInStackWithKey(key); if (bubbleToReturn == null) { bubbleToReturn = getOverflowBubbleWithKey(key); if (bubbleToReturn != null) { // Promoting from overflow mOverflowBubbles.remove(bubbleToReturn); if (mOverflowBubbles.isEmpty()) { mStateChange.showOverflowChanged = true; } } else if (mPendingBubbles.containsKey(key)) { // Update while it was pending bubbleToReturn = mPendingBubbles.get(key); } else if (entry != null) { // New bubble bubbleToReturn = new Bubble(entry, mBubbleMetadataFlagListener, mCancelledListener, // Check if it's in the overflow bubbleToReturn = findAndRemoveBubbleFromOverflow(key); if (bubbleToReturn == null) { if (entry != null) { // Not in the overflow, have an entry, so it's a new bubble bubbleToReturn = new Bubble(entry, mBubbleMetadataFlagListener, mCancelledListener, mMainExecutor); } else { // Persisted bubble being promoted // If there's no entry it must be a persisted bubble bubbleToReturn = persistedBubble; } } } if (entry != null) { bubbleToReturn.setEntry(entry); Loading @@ -448,6 +446,46 @@ public class BubbleData { return bubbleToReturn; } Bubble getOrCreateBubble(ShortcutInfo info) { String bubbleKey = Bubble.getBubbleKeyForShortcut(info); Bubble bubbleToReturn = findAndRemoveBubbleFromOverflow(bubbleKey); if (bubbleToReturn == null) { bubbleToReturn = Bubble.createShortcutBubble(info, mMainExecutor); } return bubbleToReturn; } Bubble getOrCreateBubble(Intent intent) { UserHandle user = UserHandle.of(mCurrentUserId); String bubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user); Bubble bubbleToReturn = findAndRemoveBubbleFromOverflow(bubbleKey); if (bubbleToReturn == null) { bubbleToReturn = Bubble.createAppBubble(intent, user, null, mMainExecutor); } return bubbleToReturn; } @Nullable private Bubble findAndRemoveBubbleFromOverflow(String key) { Bubble bubbleToReturn = getBubbleInStackWithKey(key); if (bubbleToReturn != null) { return bubbleToReturn; } bubbleToReturn = getOverflowBubbleWithKey(key); if (bubbleToReturn != null) { mOverflowBubbles.remove(bubbleToReturn); // Promoting from overflow mOverflowBubbles.remove(bubbleToReturn); if (mOverflowBubbles.isEmpty()) { mStateChange.showOverflowChanged = true; } } else if (mPendingBubbles.containsKey(key)) { bubbleToReturn = mPendingBubbles.get(key); } return bubbleToReturn; } /** * When this method is called it is expected that all info in the bubble has completed loading. * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context, BubbleExpandedViewManager, Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +5 −1 Original line number Diff line number Diff line Loading @@ -232,6 +232,9 @@ public class BubbleExpandedView extends LinearLayout { fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId() || (mBubble.getShortcutInfo() != null && Flags.enableBubbleAnything())); if (mBubble.isAppBubble()) { Context context = mContext.createContextAsUser( Loading @@ -246,7 +249,8 @@ public class BubbleExpandedView extends LinearLayout { /* options= */ null); mTaskView.startActivity(pi, /* fillInIntent= */ null, options, launchBounds); } else if (!mIsOverflow && mBubble.hasMetadataShortcutId()) { } else if (!mIsOverflow && isShortcutBubble) { ProtoLog.v(WM_SHELL_BUBBLES, "startingShortcutBubble=%s", getBubbleKey()); options.setApplyActivityFlagsForBubbles(true); mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), options, launchBounds); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +3 −1 Original line number Diff line number Diff line Loading @@ -357,7 +357,9 @@ public class BadgedImageView extends ConstraintLayout { void showBadge() { Bitmap appBadgeBitmap = mBubble.getAppBadge(); if (appBadgeBitmap == null) { final boolean isAppLaunchIntent = (mBubble instanceof Bubble) && ((Bubble) mBubble).isAppLaunchIntent(); if (appBadgeBitmap == null || isAppLaunchIntent) { mAppIcon.setVisibility(GONE); return; } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +43 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ 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.bar.BubbleBarExpandedView; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; import com.android.wm.shell.common.bubbles.BubbleInfo; Loading Loading @@ -246,7 +247,23 @@ public class Bubble implements BubbleViewProvider { mAppIntent = intent; mDesiredHeight = Integer.MAX_VALUE; mPackageName = intent.getPackage(); } private Bubble(ShortcutInfo info, Executor mainExecutor) { mGroupKey = null; mLocusId = null; mFlags = 0; mUser = info.getUserHandle(); mIcon = info.getIcon(); mIsAppBubble = false; mKey = getBubbleKeyForShortcut(info); mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; mTaskId = INVALID_TASK_ID; mAppIntent = null; mDesiredHeight = Integer.MAX_VALUE; mPackageName = info.getPackage(); mShortcutInfo = info; } /** Creates an app bubble. */ Loading @@ -263,6 +280,13 @@ public class Bubble implements BubbleViewProvider { mainExecutor); } /** Creates a shortcut bubble. */ public static Bubble createShortcutBubble( ShortcutInfo info, Executor mainExecutor) { return new Bubble(info, mainExecutor); } /** * Returns the key for an app bubble from an app with package name, {@code packageName} on an * Android user, {@code user}. Loading @@ -273,6 +297,14 @@ public class Bubble implements BubbleViewProvider { return KEY_APP_BUBBLE + ":" + user.getIdentifier() + ":" + packageName; } /** * Returns the key for a shortcut bubble using {@code packageName}, {@code user}, and the * {@code shortcutInfo} id. */ public static String getBubbleKeyForShortcut(ShortcutInfo info) { return info.getPackage() + ":" + info.getUserId() + ":" + info.getId(); } @VisibleForTesting(visibility = PRIVATE) public Bubble(@NonNull final BubbleEntry entry, final Bubbles.BubbleMetadataFlagListener listener, Loading Loading @@ -888,6 +920,17 @@ public class Bubble implements BubbleViewProvider { return mIntent; } /** * Whether this bubble represents the full app, i.e. the intent used is the launch * intent for an app. In this case we don't show a badge on the icon. */ public boolean isAppLaunchIntent() { if (Flags.enableBubbleAnything() && mAppIntent != null) { return mAppIntent.hasCategory("android.intent.category.LAUNCHER"); } return false; } @Nullable PendingIntent getDeleteIntent() { return mDeleteIntent; Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +52 −0 Original line number Diff line number Diff line Loading @@ -1334,6 +1334,40 @@ public class BubbleController implements ConfigurationChangeListener, } } /** * Expands and selects a bubble created or found via the provided shortcut info. * * @param info the shortcut info for the bubble. */ public void expandStackAndSelectBubble(ShortcutInfo info) { if (!Flags.enableBubbleAnything()) return; Bubble b = mBubbleData.getOrCreateBubble(info); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - shortcut=%s", info); if (b.isInflated()) { mBubbleData.setSelectedBubbleAndExpandStack(b); } else { b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); } } /** * Expands and selects a bubble created or found for this app. * * @param intent the intent for the bubble. */ public void expandStackAndSelectBubble(Intent intent) { if (!Flags.enableBubbleAnything()) return; Bubble b = mBubbleData.getOrCreateBubble(intent); // Removes from overflow ProtoLog.v(WM_SHELL_BUBBLES, "expandStackAndSelectBubble - intent=%s", intent); if (b.isInflated()) { mBubbleData.setSelectedBubbleAndExpandStack(b); } else { b.enable(Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); } } /** * Expands and selects a bubble based on the provided {@link BubbleEntry}. If no bubble * exists for this entry, and it is able to bubble, a new bubble will be created. Loading Loading @@ -2323,6 +2357,7 @@ public class BubbleController implements ConfigurationChangeListener, * @param entry the entry to bubble. */ static boolean canLaunchInTaskView(Context context, BubbleEntry entry) { if (Flags.enableBubbleAnything()) return true; PendingIntent intent = entry.getBubbleMetadata() != null ? entry.getBubbleMetadata().getIntent() : null; Loading Loading @@ -2438,6 +2473,16 @@ public class BubbleController implements ConfigurationChangeListener, mMainExecutor.execute(mListener::unregister); } @Override public void showShortcutBubble(ShortcutInfo info) { mMainExecutor.execute(() -> mController.expandStackAndSelectBubble(info)); } @Override public void showAppBubble(Intent intent) { mMainExecutor.execute(() -> mController.expandStackAndSelectBubble(intent)); } @Override public void showBubble(String key, int topOnScreen) { mMainExecutor.execute( Loading Loading @@ -2633,6 +2678,13 @@ public class BubbleController implements ConfigurationChangeListener, }); } @Override public void expandStackAndSelectBubble(ShortcutInfo info) { mMainExecutor.execute(() -> { BubbleController.this.expandStackAndSelectBubble(info); }); } @Override public void expandStackAndSelectBubble(Bubble bubble) { mMainExecutor.execute(() -> { Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java +54 −16 Original line number Diff line number Diff line Loading @@ -23,8 +23,10 @@ import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES; import android.annotation.NonNull; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.LocusId; import android.content.pm.ShortcutInfo; import android.os.UserHandle; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; Loading Loading @@ -421,25 +423,21 @@ public class BubbleData { Bubble bubbleToReturn = getBubbleInStackWithKey(key); if (bubbleToReturn == null) { bubbleToReturn = getOverflowBubbleWithKey(key); if (bubbleToReturn != null) { // Promoting from overflow mOverflowBubbles.remove(bubbleToReturn); if (mOverflowBubbles.isEmpty()) { mStateChange.showOverflowChanged = true; } } else if (mPendingBubbles.containsKey(key)) { // Update while it was pending bubbleToReturn = mPendingBubbles.get(key); } else if (entry != null) { // New bubble bubbleToReturn = new Bubble(entry, mBubbleMetadataFlagListener, mCancelledListener, // Check if it's in the overflow bubbleToReturn = findAndRemoveBubbleFromOverflow(key); if (bubbleToReturn == null) { if (entry != null) { // Not in the overflow, have an entry, so it's a new bubble bubbleToReturn = new Bubble(entry, mBubbleMetadataFlagListener, mCancelledListener, mMainExecutor); } else { // Persisted bubble being promoted // If there's no entry it must be a persisted bubble bubbleToReturn = persistedBubble; } } } if (entry != null) { bubbleToReturn.setEntry(entry); Loading @@ -448,6 +446,46 @@ public class BubbleData { return bubbleToReturn; } Bubble getOrCreateBubble(ShortcutInfo info) { String bubbleKey = Bubble.getBubbleKeyForShortcut(info); Bubble bubbleToReturn = findAndRemoveBubbleFromOverflow(bubbleKey); if (bubbleToReturn == null) { bubbleToReturn = Bubble.createShortcutBubble(info, mMainExecutor); } return bubbleToReturn; } Bubble getOrCreateBubble(Intent intent) { UserHandle user = UserHandle.of(mCurrentUserId); String bubbleKey = Bubble.getAppBubbleKeyForApp(intent.getPackage(), user); Bubble bubbleToReturn = findAndRemoveBubbleFromOverflow(bubbleKey); if (bubbleToReturn == null) { bubbleToReturn = Bubble.createAppBubble(intent, user, null, mMainExecutor); } return bubbleToReturn; } @Nullable private Bubble findAndRemoveBubbleFromOverflow(String key) { Bubble bubbleToReturn = getBubbleInStackWithKey(key); if (bubbleToReturn != null) { return bubbleToReturn; } bubbleToReturn = getOverflowBubbleWithKey(key); if (bubbleToReturn != null) { mOverflowBubbles.remove(bubbleToReturn); // Promoting from overflow mOverflowBubbles.remove(bubbleToReturn); if (mOverflowBubbles.isEmpty()) { mStateChange.showOverflowChanged = true; } } else if (mPendingBubbles.containsKey(key)) { bubbleToReturn = mPendingBubbles.get(key); } return bubbleToReturn; } /** * When this method is called it is expected that all info in the bubble has completed loading. * @see Bubble#inflate(BubbleViewInfoTask.Callback, Context, BubbleExpandedViewManager, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +5 −1 Original line number Diff line number Diff line Loading @@ -232,6 +232,9 @@ public class BubbleExpandedView extends LinearLayout { fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId() || (mBubble.getShortcutInfo() != null && Flags.enableBubbleAnything())); if (mBubble.isAppBubble()) { Context context = mContext.createContextAsUser( Loading @@ -246,7 +249,8 @@ public class BubbleExpandedView extends LinearLayout { /* options= */ null); mTaskView.startActivity(pi, /* fillInIntent= */ null, options, launchBounds); } else if (!mIsOverflow && mBubble.hasMetadataShortcutId()) { } else if (!mIsOverflow && isShortcutBubble) { ProtoLog.v(WM_SHELL_BUBBLES, "startingShortcutBubble=%s", getBubbleKey()); options.setApplyActivityFlagsForBubbles(true); mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), options, launchBounds); Loading