Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +39 −1 Original line number Diff line number Diff line Loading @@ -59,6 +59,8 @@ 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"; private final String mKey; @Nullable private final String mGroupKey; Loading Loading @@ -163,6 +165,14 @@ public class Bubble implements BubbleViewProvider { @Nullable private PendingIntent mDeleteIntent; /** * Used only for a special bubble in the stack that has the key {@link #KEY_APP_BUBBLE}. * There can only be one of these bubbles in the stack and this intent will be populated for * that bubble. */ @Nullable private Intent mAppIntent; /** * Create a bubble with limited information based on given {@link ShortcutInfo}. * Note: Currently this is only being used when the bubble is persisted to disk. Loading Loading @@ -192,6 +202,22 @@ public class Bubble implements BubbleViewProvider { mBubbleMetadataFlagListener = listener; } public Bubble(Intent intent, UserHandle user, Executor mainExecutor) { mKey = KEY_APP_BUBBLE; mGroupKey = null; mLocusId = null; mFlags = 0; mUser = user; mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; mTaskId = INVALID_TASK_ID; mAppIntent = intent; mDesiredHeight = Integer.MAX_VALUE; mPackageName = intent.getPackage(); } @VisibleForTesting(visibility = PRIVATE) public Bubble(@NonNull final BubbleEntry entry, final Bubbles.BubbleMetadataFlagListener listener, Loading Loading @@ -417,6 +443,9 @@ public class Bubble implements BubbleViewProvider { mShortcutInfo = info.shortcutInfo; mAppName = info.appName; if (mTitle == null) { mTitle = mAppName; } mFlyoutMessage = info.flyoutMessage; mBadgeBitmap = info.badgeBitmap; Loading Loading @@ -520,7 +549,7 @@ public class Bubble implements BubbleViewProvider { * @return the last time this bubble was updated or accessed, whichever is most recent. */ long getLastActivity() { return Math.max(mLastUpdated, mLastAccessed); return isAppBubble() ? Long.MAX_VALUE : Math.max(mLastUpdated, mLastAccessed); } /** Loading Loading @@ -719,6 +748,15 @@ public class Bubble implements BubbleViewProvider { return mDeleteIntent; } @Nullable Intent getAppBubbleIntent() { return mAppIntent; } boolean isAppBubble() { return KEY_APP_BUBBLE.equals(mKey); } Intent getSettingsIntent(final Context context) { final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +14 −0 Original line number Diff line number Diff line Loading @@ -1016,6 +1016,20 @@ public class BubbleController implements ConfigurationChangeListener { } } /** * Adds a bubble for a specific intent. These bubbles are <b>not</b> backed by a notification * and remain until the user dismisses the bubble or bubble stack. Only one intent bubble * is supported at a time. * * @param intent the intent to display in the bubble expanded view. */ public void addAppBubble(Intent intent) { if (intent == null || intent.getPackage() == null) return; Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor); b.setShouldAutoExpand(true); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); } /** * Fills the overflow bubbles by loading them from disk. */ Loading libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +13 −5 Original line number Diff line number Diff line Loading @@ -224,15 +224,23 @@ public class BubbleExpandedView extends LinearLayout { try { options.setTaskAlwaysOnTop(true); options.setLaunchedFromBubble(true); if (!mIsOverflow && mBubble.hasMetadataShortcutId()) { options.setApplyActivityFlagsForBubbles(true); mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), options, launchBounds); } else { Intent fillInIntent = new Intent(); // Apply flags to make behaviour match documentLaunchMode=always. fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); if (mBubble.isAppBubble()) { PendingIntent pi = PendingIntent.getActivity(mContext, 0, mBubble.getAppBubbleIntent(), PendingIntent.FLAG_MUTABLE, null); mTaskView.startActivity(pi, fillInIntent, options, launchBounds); } else if (!mIsOverflow && mBubble.hasMetadataShortcutId()) { options.setApplyActivityFlagsForBubbles(true); mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), options, launchBounds); } else { if (mBubble != null) { mBubble.setIntentActive(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +2 −0 Original line number Diff line number Diff line Loading @@ -591,6 +591,7 @@ public abstract class WMShellBaseModule { ShellInit shellInit, ShellController shellController, ShellCommandHandler shellCommandHandler, Optional<BubbleController> bubbleController, WindowManager windowManager, ShellTaskOrganizer organizer, TaskViewTransitions taskViewTransitions, Loading @@ -602,6 +603,7 @@ public abstract class WMShellBaseModule { shellInit, shellController, shellCommandHandler, bubbleController, windowManager, organizer, taskViewTransitions, Loading libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java +25 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; Loading @@ -54,6 +55,7 @@ import com.android.wm.shell.sysui.ShellInit; import java.io.PrintWriter; import java.util.Objects; import java.util.Optional; /** * Entry point for creating and managing floating tasks. Loading @@ -70,6 +72,8 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont public static final boolean FLOATING_TASKS_ENABLED = SystemProperties.getBoolean("persist.wm.debug.floating_tasks", false); public static final boolean SHOW_FLOATING_TASKS_AS_BUBBLES = SystemProperties.getBoolean("persist.wm.debug.floating_tasks_as_bubbles", false); @VisibleForTesting static final int SMALLEST_SCREEN_WIDTH_DP_TO_BE_TABLET = 600; Loading @@ -82,6 +86,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont private Context mContext; private ShellController mShellController; private ShellCommandHandler mShellCommandHandler; private @Nullable BubbleController mBubbleController; private WindowManager mWindowManager; private ShellTaskOrganizer mTaskOrganizer; private TaskViewTransitions mTaskViewTransitions; Loading Loading @@ -111,6 +116,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont ShellInit shellInit, ShellController shellController, ShellCommandHandler shellCommandHandler, Optional<BubbleController> bubbleController, WindowManager windowManager, ShellTaskOrganizer organizer, TaskViewTransitions transitions, Loading @@ -120,6 +126,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont mContext = context; mShellController = shellController; mShellCommandHandler = shellCommandHandler; mBubbleController = bubbleController.get(); mWindowManager = windowManager; mTaskOrganizer = organizer; mTaskViewTransitions = transitions; Loading Loading @@ -187,6 +194,22 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont return true; } /** Returns true if the task was or should be shown as a bubble. */ private boolean maybeShowTaskAsBubble(Intent intent) { if (SHOW_FLOATING_TASKS_AS_BUBBLES && mBubbleController != null) { removeFloatingLayer(); if (intent.getPackage() != null) { mBubbleController.addAppBubble(intent); ProtoLog.d(WM_SHELL_FLOATING_APPS, "showing floating task as bubble: %s", intent); } else { ProtoLog.d(WM_SHELL_FLOATING_APPS, "failed to show floating task as bubble: %s; unknown package", intent); } return true; } return false; } /** * Shows, stashes, or un-stashes the floating task depending on state: * - If there is no floating task for this intent, it shows this the provided task. Loading @@ -195,6 +218,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont */ public void showOrSetStashed(Intent intent) { if (!canShowTask(intent)) return; if (maybeShowTaskAsBubble(intent)) return; addFloatingLayer(); Loading @@ -215,6 +239,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont */ public void showTask(Intent intent) { if (!canShowTask(intent)) return; if (maybeShowTaskAsBubble(intent)) return; addFloatingLayer(); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +39 −1 Original line number Diff line number Diff line Loading @@ -59,6 +59,8 @@ 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"; private final String mKey; @Nullable private final String mGroupKey; Loading Loading @@ -163,6 +165,14 @@ public class Bubble implements BubbleViewProvider { @Nullable private PendingIntent mDeleteIntent; /** * Used only for a special bubble in the stack that has the key {@link #KEY_APP_BUBBLE}. * There can only be one of these bubbles in the stack and this intent will be populated for * that bubble. */ @Nullable private Intent mAppIntent; /** * Create a bubble with limited information based on given {@link ShortcutInfo}. * Note: Currently this is only being used when the bubble is persisted to disk. Loading Loading @@ -192,6 +202,22 @@ public class Bubble implements BubbleViewProvider { mBubbleMetadataFlagListener = listener; } public Bubble(Intent intent, UserHandle user, Executor mainExecutor) { mKey = KEY_APP_BUBBLE; mGroupKey = null; mLocusId = null; mFlags = 0; mUser = user; mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; mTaskId = INVALID_TASK_ID; mAppIntent = intent; mDesiredHeight = Integer.MAX_VALUE; mPackageName = intent.getPackage(); } @VisibleForTesting(visibility = PRIVATE) public Bubble(@NonNull final BubbleEntry entry, final Bubbles.BubbleMetadataFlagListener listener, Loading Loading @@ -417,6 +443,9 @@ public class Bubble implements BubbleViewProvider { mShortcutInfo = info.shortcutInfo; mAppName = info.appName; if (mTitle == null) { mTitle = mAppName; } mFlyoutMessage = info.flyoutMessage; mBadgeBitmap = info.badgeBitmap; Loading Loading @@ -520,7 +549,7 @@ public class Bubble implements BubbleViewProvider { * @return the last time this bubble was updated or accessed, whichever is most recent. */ long getLastActivity() { return Math.max(mLastUpdated, mLastAccessed); return isAppBubble() ? Long.MAX_VALUE : Math.max(mLastUpdated, mLastAccessed); } /** Loading Loading @@ -719,6 +748,15 @@ public class Bubble implements BubbleViewProvider { return mDeleteIntent; } @Nullable Intent getAppBubbleIntent() { return mAppIntent; } boolean isAppBubble() { return KEY_APP_BUBBLE.equals(mKey); } Intent getSettingsIntent(final Context context) { final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +14 −0 Original line number Diff line number Diff line Loading @@ -1016,6 +1016,20 @@ public class BubbleController implements ConfigurationChangeListener { } } /** * Adds a bubble for a specific intent. These bubbles are <b>not</b> backed by a notification * and remain until the user dismisses the bubble or bubble stack. Only one intent bubble * is supported at a time. * * @param intent the intent to display in the bubble expanded view. */ public void addAppBubble(Intent intent) { if (intent == null || intent.getPackage() == null) return; Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor); b.setShouldAutoExpand(true); inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); } /** * Fills the overflow bubbles by loading them from disk. */ Loading
libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +13 −5 Original line number Diff line number Diff line Loading @@ -224,15 +224,23 @@ public class BubbleExpandedView extends LinearLayout { try { options.setTaskAlwaysOnTop(true); options.setLaunchedFromBubble(true); if (!mIsOverflow && mBubble.hasMetadataShortcutId()) { options.setApplyActivityFlagsForBubbles(true); mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), options, launchBounds); } else { Intent fillInIntent = new Intent(); // Apply flags to make behaviour match documentLaunchMode=always. fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT); fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK); if (mBubble.isAppBubble()) { PendingIntent pi = PendingIntent.getActivity(mContext, 0, mBubble.getAppBubbleIntent(), PendingIntent.FLAG_MUTABLE, null); mTaskView.startActivity(pi, fillInIntent, options, launchBounds); } else if (!mIsOverflow && mBubble.hasMetadataShortcutId()) { options.setApplyActivityFlagsForBubbles(true); mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), options, launchBounds); } else { if (mBubble != null) { mBubble.setIntentActive(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +2 −0 Original line number Diff line number Diff line Loading @@ -591,6 +591,7 @@ public abstract class WMShellBaseModule { ShellInit shellInit, ShellController shellController, ShellCommandHandler shellCommandHandler, Optional<BubbleController> bubbleController, WindowManager windowManager, ShellTaskOrganizer organizer, TaskViewTransitions taskViewTransitions, Loading @@ -602,6 +603,7 @@ public abstract class WMShellBaseModule { shellInit, shellController, shellCommandHandler, bubbleController, windowManager, organizer, taskViewTransitions, Loading
libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java +25 −0 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.TaskViewTransitions; import com.android.wm.shell.bubbles.BubbleController; import com.android.wm.shell.common.RemoteCallable; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.SyncTransactionQueue; Loading @@ -54,6 +55,7 @@ import com.android.wm.shell.sysui.ShellInit; import java.io.PrintWriter; import java.util.Objects; import java.util.Optional; /** * Entry point for creating and managing floating tasks. Loading @@ -70,6 +72,8 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont public static final boolean FLOATING_TASKS_ENABLED = SystemProperties.getBoolean("persist.wm.debug.floating_tasks", false); public static final boolean SHOW_FLOATING_TASKS_AS_BUBBLES = SystemProperties.getBoolean("persist.wm.debug.floating_tasks_as_bubbles", false); @VisibleForTesting static final int SMALLEST_SCREEN_WIDTH_DP_TO_BE_TABLET = 600; Loading @@ -82,6 +86,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont private Context mContext; private ShellController mShellController; private ShellCommandHandler mShellCommandHandler; private @Nullable BubbleController mBubbleController; private WindowManager mWindowManager; private ShellTaskOrganizer mTaskOrganizer; private TaskViewTransitions mTaskViewTransitions; Loading Loading @@ -111,6 +116,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont ShellInit shellInit, ShellController shellController, ShellCommandHandler shellCommandHandler, Optional<BubbleController> bubbleController, WindowManager windowManager, ShellTaskOrganizer organizer, TaskViewTransitions transitions, Loading @@ -120,6 +126,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont mContext = context; mShellController = shellController; mShellCommandHandler = shellCommandHandler; mBubbleController = bubbleController.get(); mWindowManager = windowManager; mTaskOrganizer = organizer; mTaskViewTransitions = transitions; Loading Loading @@ -187,6 +194,22 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont return true; } /** Returns true if the task was or should be shown as a bubble. */ private boolean maybeShowTaskAsBubble(Intent intent) { if (SHOW_FLOATING_TASKS_AS_BUBBLES && mBubbleController != null) { removeFloatingLayer(); if (intent.getPackage() != null) { mBubbleController.addAppBubble(intent); ProtoLog.d(WM_SHELL_FLOATING_APPS, "showing floating task as bubble: %s", intent); } else { ProtoLog.d(WM_SHELL_FLOATING_APPS, "failed to show floating task as bubble: %s; unknown package", intent); } return true; } return false; } /** * Shows, stashes, or un-stashes the floating task depending on state: * - If there is no floating task for this intent, it shows this the provided task. Loading @@ -195,6 +218,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont */ public void showOrSetStashed(Intent intent) { if (!canShowTask(intent)) return; if (maybeShowTaskAsBubble(intent)) return; addFloatingLayer(); Loading @@ -215,6 +239,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont */ public void showTask(Intent intent) { if (!canShowTask(intent)) return; if (maybeShowTaskAsBubble(intent)) return; addFloatingLayer(); Loading