Allow callers to specify UserHandle when launching an intent in a Bubble

Test: atest SystemUITests:com.android.systemui.wmshell.BubblesTest
atest SystemUITests:com.android.systemui.notetask.NoteTaskControllerTest
Fix: 268351693

Change-Id: I853102bb1e6866d1efde19eb65cbd33680ea753b
This commit is contained in:
Steven Ng
2023-03-13 19:24:08 +00:00
parent 81a6dbd32f
commit ea7d93896b
6 changed files with 60 additions and 24 deletions

View File

@@ -1028,19 +1028,21 @@ public class BubbleController implements ConfigurationChangeListener {
* the bubble or bubble stack.
*
* Some notes:
* - Only one app bubble is supported at a time
* - Only one app bubble is supported at a time, regardless of users. Multi-users support is
* tracked in b/273533235.
* - Calling this method with a different intent than the existing app bubble will do nothing
*
* @param intent the intent to display in the bubble expanded view.
* @param user the {@link UserHandle} of the user to start this activity for.
*/
public void showOrHideAppBubble(Intent intent) {
public void showOrHideAppBubble(Intent intent, UserHandle user) {
if (intent == null || intent.getPackage() == null) {
Log.w(TAG, "App bubble failed to show, invalid intent: " + intent
+ ((intent != null) ? " with package: " + intent.getPackage() : " "));
return;
}
PackageManager packageManager = getPackageManagerForUser(mContext, mCurrentUserId);
PackageManager packageManager = getPackageManagerForUser(mContext, user.getIdentifier());
if (!isResizableActivity(intent, packageManager, KEY_APP_BUBBLE)) return;
Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE);
@@ -1061,7 +1063,7 @@ public class BubbleController implements ConfigurationChangeListener {
}
} else {
// App bubble does not exist, lets add and expand it
Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor);
Bubble b = new Bubble(intent, user, mMainExecutor);
b.setShouldAutoExpand(true);
inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
}
@@ -1869,10 +1871,9 @@ public class BubbleController implements ConfigurationChangeListener {
}
@Override
public void showOrHideAppBubble(Intent intent) {
mMainExecutor.execute(() -> {
BubbleController.this.showOrHideAppBubble(intent);
});
public void showOrHideAppBubble(Intent intent, UserHandle user) {
mMainExecutor.execute(
() -> BubbleController.this.showOrHideAppBubble(intent, user));
}
@Override

View File

@@ -236,12 +236,17 @@ public class BubbleExpandedView extends LinearLayout {
fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
if (mBubble.isAppBubble()) {
PendingIntent pi = PendingIntent.getActivity(mContext, 0,
Context context =
mContext.createContextAsUser(
mBubble.getUser(), Context.CONTEXT_RESTRICTED);
PendingIntent pi = PendingIntent.getActivity(
context,
/* requestCode= */ 0,
mBubble.getAppBubbleIntent()
.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT)
.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK),
PendingIntent.FLAG_IMMUTABLE,
null);
/* options= */ null);
mTaskView.startActivity(pi, /* fillInIntent= */ null, options,
launchBounds);
} else if (!mIsOverflow && mBubble.hasMetadataShortcutId()) {

View File

@@ -129,12 +129,14 @@ public interface Bubbles {
* the bubble or bubble stack.
*
* Some notes:
* - Only one app bubble is supported at a time
* - Only one app bubble is supported at a time, regardless of users. Multi-users support is
* tracked in b/273533235.
* - Calling this method with a different intent than the existing app bubble will do nothing
*
* @param intent the intent to display in the bubble expanded view.
* @param user the {@link UserHandle} of the user to start this activity for.
*/
void showOrHideAppBubble(Intent intent);
void showOrHideAppBubble(Intent intent, UserHandle user);
/** @return true if the specified {@code taskId} corresponds to app bubble's taskId. */
boolean isAppBubbleTaskId(int taskId);

View File

@@ -129,8 +129,7 @@ constructor(
logDebug { "onShowNoteTask - start: $info" }
when (info.launchMode) {
is NoteTaskLaunchMode.AppBubble -> {
// TODO(b/267634412, b/268351693): Should use `showOrHideAppBubbleAsUser`
bubbles.showOrHideAppBubble(intent)
bubbles.showOrHideAppBubble(intent, userTracker.userHandle)
// App bubble logging happens on `onBubbleExpandChanged`.
logDebug { "onShowNoteTask - opened as app bubble: $info" }
}

View File

@@ -232,7 +232,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
verifyZeroInteractions(context)
val intentCaptor = argumentCaptor<Intent>()
verify(bubbles).showOrHideAppBubble(capture(intentCaptor))
verify(bubbles).showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle))
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
@@ -366,7 +366,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
val intentCaptor = argumentCaptor<Intent>()
verify(bubbles).showOrHideAppBubble(capture(intentCaptor))
verify(bubbles).showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle))
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)
@@ -389,7 +389,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(entryPoint = NoteTaskEntryPoint.QUICK_AFFORDANCE)
val intentCaptor = argumentCaptor<Intent>()
verify(bubbles).showOrHideAppBubble(capture(intentCaptor))
verify(bubbles).showOrHideAppBubble(capture(intentCaptor), eq(userTracker.userHandle))
intentCaptor.value.let { intent ->
assertThat(intent.action).isEqualTo(Intent.ACTION_CREATE_NOTE)
assertThat(intent.`package`).isEqualTo(NOTES_PACKAGE_NAME)

View File

@@ -293,6 +293,8 @@ public class BubblesTest extends SysuiTestCase {
private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
private UserHandle mUser0;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
@@ -301,6 +303,8 @@ public class BubblesTest extends SysuiTestCase {
// For the purposes of this test, just run everything synchronously
ShellExecutor syncExecutor = new SyncExecutor();
mUser0 = createUserHande(/* userId= */ 0);
when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors);
when(mNotificationShadeWindowView.getViewTreeObserver())
.thenReturn(mock(ViewTreeObserver.class));
@@ -1650,7 +1654,7 @@ public class BubblesTest extends SysuiTestCase {
assertThat(mBubbleController.isStackExpanded()).isFalse();
assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull();
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0);
verify(mBubbleController).inflateAndAdd(any(Bubble.class), /* suppressFlyout= */ eq(true),
/* showInShade= */ eq(false));
@@ -1660,13 +1664,13 @@ public class BubblesTest extends SysuiTestCase {
@Test
public void testShowOrHideAppBubble_expandIfCollapsed() {
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0);
mBubbleController.updateBubble(mBubbleEntry);
mBubbleController.collapseStack();
assertThat(mBubbleController.isStackExpanded()).isFalse();
// Calling this while collapsed will expand the app bubble
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isTrue();
@@ -1675,27 +1679,46 @@ public class BubblesTest extends SysuiTestCase {
@Test
public void testShowOrHideAppBubble_collapseIfSelected() {
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isTrue();
// Calling this while the app bubble is expanded should collapse the stack
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isFalse();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(1);
assertThat(mBubbleData.getBubbles().get(0).getUser()).isEqualTo(mUser0);
}
@Test
public void testShowOrHideAppBubbleWithNonPrimaryUser_bubbleCollapsedWithExpectedUser() {
UserHandle user10 = createUserHande(/* userId = */ 10);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, user10);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isTrue();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(1);
assertThat(mBubbleData.getBubbles().get(0).getUser()).isEqualTo(user10);
// Calling this while the app bubble is expanded should collapse the stack
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, user10);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isFalse();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(1);
assertThat(mBubbleData.getBubbles().get(0).getUser()).isEqualTo(user10);
}
@Test
public void testShowOrHideAppBubble_selectIfNotSelected() {
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0);
mBubbleController.updateBubble(mBubbleEntry);
mBubbleController.expandStackAndSelectBubble(mBubbleEntry);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(mBubbleEntry.getKey());
assertThat(mBubbleController.isStackExpanded()).isTrue();
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.showOrHideAppBubble(mAppBubbleIntent, mUser0);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isTrue();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(2);
@@ -1830,6 +1853,12 @@ public class BubblesTest extends SysuiTestCase {
mBubbleController.onUserChanged(userId);
}
private UserHandle createUserHande(int userId) {
UserHandle user = mock(UserHandle.class);
when(user.getIdentifier()).thenReturn(userId);
return user;
}
/**
* Asserts that the bubble stack is expanded and also validates the cached state is updated.
*/