Merge "Modify the showAppBubble method to be showOrHideAppBubble" into tm-qpr-dev

This commit is contained in:
Mady Mellor
2023-01-10 22:53:09 +00:00
committed by Android (Google) Code Review
5 changed files with 143 additions and 26 deletions

View File

@@ -973,21 +973,59 @@ public class BubbleController implements ConfigurationChangeListener {
} }
/** /**
* Adds and expands bubble for a specific intent. These bubbles are <b>not</b> backed by a n * This method has different behavior depending on:
* otification and remain until the user dismisses the bubble or bubble stack. Only one intent * - if an app bubble exists
* bubble is supported at a time. * - if an app bubble is expanded
*
* If no app bubble exists, this will add and expand a bubble with the provided intent. The
* intent must be explicit (i.e. include a package name or fully qualified component class name)
* and the activity for it should be resizable.
*
* If an app bubble exists, this will toggle the visibility of it, i.e. if the app bubble is
* expanded, calling this method will collapse it. If the app bubble is not expanded, calling
* this method will expand it.
*
* These bubbles are <b>not</b> backed by a notification and remain until the user dismisses
* the bubble or bubble stack.
*
* Some notes:
* - Only one app bubble is supported at a time
* - 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 intent the intent to display in the bubble expanded view.
*/ */
public void showAppBubble(Intent intent) { public void showOrHideAppBubble(Intent intent) {
if (intent == null || intent.getPackage() == null) return; 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, mCurrentUserId);
if (!isResizableActivity(intent, packageManager, KEY_APP_BUBBLE)) return; if (!isResizableActivity(intent, packageManager, KEY_APP_BUBBLE)) return;
Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor); Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE);
b.setShouldAutoExpand(true); if (existingAppBubble != null) {
inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false); BubbleViewProvider selectedBubble = mBubbleData.getSelectedBubble();
if (isStackExpanded()) {
if (selectedBubble != null && KEY_APP_BUBBLE.equals(selectedBubble.getKey())) {
// App bubble is expanded, lets collapse
collapseStack();
} else {
// App bubble is not selected, select it
mBubbleData.setSelectedBubble(existingAppBubble);
}
} else {
// App bubble is not selected, select it & expand
mBubbleData.setSelectedBubble(existingAppBubble);
mBubbleData.setExpanded(true);
}
} else {
// App bubble does not exist, lets add and expand it
Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor);
b.setShouldAutoExpand(true);
inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
}
} }
/** /**
@@ -1697,9 +1735,9 @@ public class BubbleController implements ConfigurationChangeListener {
} }
@Override @Override
public void showAppBubble(Intent intent) { public void showOrHideAppBubble(Intent intent) {
mMainExecutor.execute(() -> { mMainExecutor.execute(() -> {
BubbleController.this.showAppBubble(intent); BubbleController.this.showOrHideAppBubble(intent);
}); });
} }

View File

@@ -109,13 +109,28 @@ public interface Bubbles {
void expandStackAndSelectBubble(Bubble bubble); void expandStackAndSelectBubble(Bubble bubble);
/** /**
* Adds and expands bubble that is not notification based, but instead based on an intent from * This method has different behavior depending on:
* the app. The intent must be explicit (i.e. include a package name or fully qualified * - if an app bubble exists
* component class name) and the activity for it should be resizable. * - if an app bubble is expanded
* *
* @param intent the intent to populate the bubble. * If no app bubble exists, this will add and expand a bubble with the provided intent. The
* intent must be explicit (i.e. include a package name or fully qualified component class name)
* and the activity for it should be resizable.
*
* If an app bubble exists, this will toggle the visibility of it, i.e. if the app bubble is
* expanded, calling this method will collapse it. If the app bubble is not expanded, calling
* this method will expand it.
*
* These bubbles are <b>not</b> backed by a notification and remain until the user dismisses
* the bubble or bubble stack.
*
* Some notes:
* - Only one app bubble is supported at a time
* - 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.
*/ */
void showAppBubble(Intent intent); void showOrHideAppBubble(Intent intent);
/** /**
* @return a bubble that matches the provided shortcutId, if one exists. * @return a bubble that matches the provided shortcutId, if one exists.

View File

@@ -57,7 +57,9 @@ constructor(
* If the keyguard is locked, notes will open as a full screen experience. A locked device has * If the keyguard is locked, notes will open as a full screen experience. A locked device has
* no contextual information which let us use the whole screen space available. * no contextual information which let us use the whole screen space available.
* *
* If no in multi-window or the keyguard is unlocked, notes will open as a floating experience. * If no in multi-window or the keyguard is unlocked, notes will open as a bubble OR it will be
* collapsed if the notes bubble is already opened.
*
* That will let users open other apps in full screen, and take contextual notes. * That will let users open other apps in full screen, and take contextual notes.
*/ */
fun showNoteTask(isInMultiWindowMode: Boolean = false) { fun showNoteTask(isInMultiWindowMode: Boolean = false) {
@@ -75,7 +77,7 @@ constructor(
context.startActivity(intent) context.startActivity(intent)
} else { } else {
// TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter. // TODO(b/254606432): Should include Intent.EXTRA_FLOATING_WINDOW_MODE parameter.
bubbles.showAppBubble(intent) bubbles.showOrHideAppBubble(intent)
} }
} }

View File

@@ -93,7 +93,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context).startActivity(notesIntent) verify(context).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showOrHideAppBubble(notesIntent)
} }
@Test @Test
@@ -102,7 +102,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(bubbles).showAppBubble(notesIntent) verify(bubbles).showOrHideAppBubble(notesIntent)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
} }
@@ -113,7 +113,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = true) createNoteTaskController().showNoteTask(isInMultiWindowMode = true)
verify(context).startActivity(notesIntent) verify(context).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showOrHideAppBubble(notesIntent)
} }
@Test @Test
@@ -123,7 +123,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showOrHideAppBubble(notesIntent)
} }
@Test @Test
@@ -133,7 +133,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showOrHideAppBubble(notesIntent)
} }
@Test @Test
@@ -143,7 +143,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showOrHideAppBubble(notesIntent)
} }
@Test @Test
@@ -153,7 +153,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showOrHideAppBubble(notesIntent)
} }
@Test @Test
@@ -161,7 +161,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController(isEnabled = false).showNoteTask() createNoteTaskController(isEnabled = false).showNoteTask()
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showOrHideAppBubble(notesIntent)
} }
@Test @Test
@@ -171,7 +171,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false) createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent) verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent) verify(bubbles, never()).showOrHideAppBubble(notesIntent)
} }
// endregion // endregion

View File

@@ -24,6 +24,7 @@ import static android.service.notification.NotificationListenerService.REASON_AP
import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED; import static android.service.notification.NotificationListenerService.REASON_GROUP_SUMMARY_CANCELED;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.wm.shell.bubbles.Bubble.KEY_APP_BUBBLE;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
@@ -228,6 +229,8 @@ public class BubblesTest extends SysuiTestCase {
private BubbleEntry mBubbleEntryUser11; private BubbleEntry mBubbleEntryUser11;
private BubbleEntry mBubbleEntry2User11; private BubbleEntry mBubbleEntry2User11;
private Intent mAppBubbleIntent;
@Mock @Mock
private ShellInit mShellInit; private ShellInit mShellInit;
@Mock @Mock
@@ -323,6 +326,9 @@ public class BubblesTest extends SysuiTestCase {
mBubbleEntry2User11 = BubblesManager.notifToBubbleEntry( mBubbleEntry2User11 = BubblesManager.notifToBubbleEntry(
mNotificationTestHelper.createBubble(handle)); mNotificationTestHelper.createBubble(handle));
mAppBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
mAppBubbleIntent.setPackage(mContext.getPackageName());
mZenModeConfig.suppressedVisualEffects = 0; mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig); when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
@@ -1630,6 +1636,62 @@ public class BubblesTest extends SysuiTestCase {
any(Bubble.class), anyBoolean(), anyBoolean()); any(Bubble.class), anyBoolean(), anyBoolean());
} }
@Test
public void testShowOrHideAppBubble_addsAndExpand() {
assertThat(mBubbleController.isStackExpanded()).isFalse();
assertThat(mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE)).isNull();
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
verify(mBubbleController).inflateAndAdd(any(Bubble.class), /* suppressFlyout= */ eq(true),
/* showInShade= */ eq(false));
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isTrue();
}
@Test
public void testShowOrHideAppBubble_expandIfCollapsed() {
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.updateBubble(mBubbleEntry);
mBubbleController.collapseStack();
assertThat(mBubbleController.isStackExpanded()).isFalse();
// Calling this while collapsed will expand the app bubble
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isTrue();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(2);
}
@Test
public void testShowOrHideAppBubble_collapseIfSelected() {
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
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);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isFalse();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(1);
}
@Test
public void testShowOrHideAppBubble_selectIfNotSelected() {
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
mBubbleController.updateBubble(mBubbleEntry);
mBubbleController.expandStackAndSelectBubble(mBubbleEntry);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(mBubbleEntry.getKey());
assertThat(mBubbleController.isStackExpanded()).isTrue();
mBubbleController.showOrHideAppBubble(mAppBubbleIntent);
assertThat(mBubbleData.getSelectedBubble().getKey()).isEqualTo(KEY_APP_BUBBLE);
assertThat(mBubbleController.isStackExpanded()).isTrue();
assertThat(mBubbleData.getBubbles().size()).isEqualTo(2);
}
/** Creates a bubble using the userId and package. */ /** Creates a bubble using the userId and package. */
private Bubble createBubble(int userId, String pkg) { private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId); final UserHandle userHandle = new UserHandle(userId);