Merge "Allow floating tasks to be shown as bubbles (behind a sysui flag)" into tm-qpr-dev

This commit is contained in:
Mady Mellor
2022-09-23 15:13:03 +00:00
committed by Android (Google) Code Review
7 changed files with 100 additions and 6 deletions

View File

@@ -59,6 +59,8 @@ 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";
private final String mKey; private final String mKey;
@Nullable @Nullable
private final String mGroupKey; private final String mGroupKey;
@@ -163,6 +165,14 @@ public class Bubble implements BubbleViewProvider {
@Nullable @Nullable
private PendingIntent mDeleteIntent; 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}. * 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. * 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; 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) @VisibleForTesting(visibility = PRIVATE)
public Bubble(@NonNull final BubbleEntry entry, public Bubble(@NonNull final BubbleEntry entry,
final Bubbles.BubbleMetadataFlagListener listener, final Bubbles.BubbleMetadataFlagListener listener,
@@ -417,6 +443,9 @@ public class Bubble implements BubbleViewProvider {
mShortcutInfo = info.shortcutInfo; mShortcutInfo = info.shortcutInfo;
mAppName = info.appName; mAppName = info.appName;
if (mTitle == null) {
mTitle = mAppName;
}
mFlyoutMessage = info.flyoutMessage; mFlyoutMessage = info.flyoutMessage;
mBadgeBitmap = info.badgeBitmap; 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. * @return the last time this bubble was updated or accessed, whichever is most recent.
*/ */
long getLastActivity() { 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; return mDeleteIntent;
} }
@Nullable
Intent getAppBubbleIntent() {
return mAppIntent;
}
boolean isAppBubble() {
return KEY_APP_BUBBLE.equals(mKey);
}
Intent getSettingsIntent(final Context context) { Intent getSettingsIntent(final Context context) {
final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS); final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());

View File

@@ -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. * Fills the overflow bubbles by loading them from disk.
*/ */

View File

@@ -224,15 +224,23 @@ public class BubbleExpandedView extends LinearLayout {
try { try {
options.setTaskAlwaysOnTop(true); options.setTaskAlwaysOnTop(true);
options.setLaunchedFromBubble(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); options.setApplyActivityFlagsForBubbles(true);
mTaskView.startShortcutActivity(mBubble.getShortcutInfo(), mTaskView.startShortcutActivity(mBubble.getShortcutInfo(),
options, launchBounds); options, launchBounds);
} else { } 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) { if (mBubble != null) {
mBubble.setIntentActive(); mBubble.setIntentActive();
} }

View File

@@ -591,6 +591,7 @@ public abstract class WMShellBaseModule {
ShellInit shellInit, ShellInit shellInit,
ShellController shellController, ShellController shellController,
ShellCommandHandler shellCommandHandler, ShellCommandHandler shellCommandHandler,
Optional<BubbleController> bubbleController,
WindowManager windowManager, WindowManager windowManager,
ShellTaskOrganizer organizer, ShellTaskOrganizer organizer,
TaskViewTransitions taskViewTransitions, TaskViewTransitions taskViewTransitions,
@@ -602,6 +603,7 @@ public abstract class WMShellBaseModule {
shellInit, shellInit,
shellController, shellController,
shellCommandHandler, shellCommandHandler,
bubbleController,
windowManager, windowManager,
organizer, organizer,
taskViewTransitions, taskViewTransitions,

View File

@@ -39,6 +39,7 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog; import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.ShellTaskOrganizer; import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.TaskViewTransitions; 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.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue; import com.android.wm.shell.common.SyncTransactionQueue;
@@ -54,6 +55,7 @@ import com.android.wm.shell.sysui.ShellInit;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
/** /**
* Entry point for creating and managing floating tasks. * 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 = public static final boolean FLOATING_TASKS_ENABLED =
SystemProperties.getBoolean("persist.wm.debug.floating_tasks", false); 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 @VisibleForTesting
static final int SMALLEST_SCREEN_WIDTH_DP_TO_BE_TABLET = 600; 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 Context mContext;
private ShellController mShellController; private ShellController mShellController;
private ShellCommandHandler mShellCommandHandler; private ShellCommandHandler mShellCommandHandler;
private @Nullable BubbleController mBubbleController;
private WindowManager mWindowManager; private WindowManager mWindowManager;
private ShellTaskOrganizer mTaskOrganizer; private ShellTaskOrganizer mTaskOrganizer;
private TaskViewTransitions mTaskViewTransitions; private TaskViewTransitions mTaskViewTransitions;
@@ -111,6 +116,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont
ShellInit shellInit, ShellInit shellInit,
ShellController shellController, ShellController shellController,
ShellCommandHandler shellCommandHandler, ShellCommandHandler shellCommandHandler,
Optional<BubbleController> bubbleController,
WindowManager windowManager, WindowManager windowManager,
ShellTaskOrganizer organizer, ShellTaskOrganizer organizer,
TaskViewTransitions transitions, TaskViewTransitions transitions,
@@ -120,6 +126,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont
mContext = context; mContext = context;
mShellController = shellController; mShellController = shellController;
mShellCommandHandler = shellCommandHandler; mShellCommandHandler = shellCommandHandler;
mBubbleController = bubbleController.get();
mWindowManager = windowManager; mWindowManager = windowManager;
mTaskOrganizer = organizer; mTaskOrganizer = organizer;
mTaskViewTransitions = transitions; mTaskViewTransitions = transitions;
@@ -187,6 +194,22 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont
return true; 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: * 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. * - 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) { public void showOrSetStashed(Intent intent) {
if (!canShowTask(intent)) return; if (!canShowTask(intent)) return;
if (maybeShowTaskAsBubble(intent)) return;
addFloatingLayer(); addFloatingLayer();
@@ -215,6 +239,7 @@ public class FloatingTasksController implements RemoteCallable<FloatingTasksCont
*/ */
public void showTask(Intent intent) { public void showTask(Intent intent) {
if (!canShowTask(intent)) return; if (!canShowTask(intent)) return;
if (maybeShowTaskAsBubble(intent)) return;
addFloatingLayer(); addFloatingLayer();

View File

@@ -62,6 +62,8 @@ import org.mockito.Captor;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.Optional;
/** /**
* Tests for the floating tasks controller. * Tests for the floating tasks controller.
*/ */
@@ -123,6 +125,7 @@ public class FloatingTasksControllerTest extends ShellTestCase {
mShellInit, mShellInit,
mShellController, mShellController,
mock(ShellCommandHandler.class), mock(ShellCommandHandler.class),
Optional.empty(),
mWindowManager, mWindowManager,
mTaskOrganizer, mTaskOrganizer,
mock(TaskViewTransitions.class), mock(TaskViewTransitions.class),

View File

@@ -238,6 +238,10 @@ public class Flags {
public static final SysPropBooleanFlag FLOATING_TASKS_ENABLED = public static final SysPropBooleanFlag FLOATING_TASKS_ENABLED =
new SysPropBooleanFlag(1106, "persist.wm.debug.floating_tasks", false); 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 // 1200 - predictive back
@Keep @Keep
public static final SysPropBooleanFlag WM_ENABLE_PREDICTIVE_BACK = new SysPropBooleanFlag( public static final SysPropBooleanFlag WM_ENABLE_PREDICTIVE_BACK = new SysPropBooleanFlag(