diff options
| author | 2022-09-06 11:12:37 -0700 | |
|---|---|---|
| committer | 2022-09-22 12:11:28 -0700 | |
| commit | 3b9ef3fee1457b6493e3fe7664ac0a2bd0806730 (patch) | |
| tree | 3ba0886cb9773e30a108f8fddfde27dbce7e69f0 | |
| parent | 027ea363fe3dae7d33e24bee9fbd6f892009550f (diff) | |
Allow floating tasks to be shown as bubbles (behind a sysui flag)
Special "app bubble" that is ordered at the front of the list unless
something else was selected. This is guarded behind the flag to
enable floating tasks, and a new flag to allow floating tasks to be
bubbles.
Test: manual - enable the flags and create a floating task
=> floating task appears in a bubble
Bug: 237678727
Change-Id: Ibf66e8bae07800b5f64598c9b50de7a7995d09e6
7 files changed, 100 insertions, 6 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java index b5a575499a3a..922472a26113 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java @@ -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; @@ -164,6 +166,14 @@ 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}. + * 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. */ @@ -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, @@ -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; @@ -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); } /** @@ -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()); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 0dfba3464f23..93413dbe7e5f 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -1017,6 +1017,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. */ void loadOverflowBubblesFromDisk() { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java index 840b2856270c..06f232cb7489 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleExpandedView.java @@ -224,15 +224,23 @@ public class BubbleExpandedView extends LinearLayout { try { options.setTaskAlwaysOnTop(true); options.setLaunchedFromBubble(true); - if (!mIsOverflow && mBubble.hasMetadataShortcutId()) { + + 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 { - 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 != null) { mBubble.setIntentActive(); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index c9d523c779ea..33074de8f583 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -591,6 +591,7 @@ public abstract class WMShellBaseModule { ShellInit shellInit, ShellController shellController, ShellCommandHandler shellCommandHandler, + Optional<BubbleController> bubbleController, WindowManager windowManager, ShellTaskOrganizer organizer, TaskViewTransitions taskViewTransitions, @@ -602,6 +603,7 @@ public abstract class WMShellBaseModule { shellInit, shellController, shellCommandHandler, + bubbleController, windowManager, organizer, taskViewTransitions, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java index c79b9b8cc443..67552991869b 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/floating/FloatingTasksController.java @@ -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; @@ -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. @@ -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; @@ -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; @@ -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, @@ -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; @@ -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. @@ -195,6 +218,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont */ public void showOrSetStashed(Intent intent) { if (!canShowTask(intent)) return; + if (maybeShowTaskAsBubble(intent)) return; addFloatingLayer(); @@ -215,6 +239,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont */ public void showTask(Intent intent) { if (!canShowTask(intent)) return; + if (maybeShowTaskAsBubble(intent)) return; addFloatingLayer(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java index f1b4311e5aa5..a88c83779f25 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/floating/FloatingTasksControllerTest.java @@ -62,6 +62,8 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.Optional; + /** * Tests for the floating tasks controller. */ @@ -123,6 +125,7 @@ public class FloatingTasksControllerTest extends ShellTestCase { mShellInit, mShellController, mock(ShellCommandHandler.class), + Optional.empty(), mWindowManager, mTaskOrganizer, mock(TaskViewTransitions.class), diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java index 030c7ce299be..44feac13198f 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java @@ -238,6 +238,10 @@ public class Flags { public static final SysPropBooleanFlag FLOATING_TASKS_ENABLED = new SysPropBooleanFlag(1106, "persist.wm.debug.floating_tasks", false); + @Keep + public static final SysPropBooleanFlag SHOW_FLOATING_TASKS_AS_BUBBLES = + new SysPropBooleanFlag(1107, "persist.wm.debug.floating_tasks_as_bubbles", false); + // 1200 - predictive back @Keep public static final SysPropBooleanFlag WM_ENABLE_PREDICTIVE_BACK = new SysPropBooleanFlag( |