Merge "Modify the showAppBubble method to be showOrHideAppBubble" into tm-qpr-dev am: 027b3b377f

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20873919

Change-Id: I7b164ba6e4b1719d0b07e21d43c7229d6902c0c2
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Mady Mellor
2023-01-10 22:53:48 +00:00
committed by Automerger Merge Worker
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
* otification and remain until the user dismisses the bubble or bubble stack. Only one intent
* bubble is supported at a time.
* This method has different behavior depending on:
* - if an app bubble exists
* - 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.
*/
public void showAppBubble(Intent intent) {
if (intent == null || intent.getPackage() == null) return;
public void showOrHideAppBubble(Intent intent) {
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);
if (!isResizableActivity(intent, packageManager, KEY_APP_BUBBLE)) return;
Bubble b = new Bubble(intent, UserHandle.of(mCurrentUserId), mMainExecutor);
b.setShouldAutoExpand(true);
inflateAndAdd(b, /* suppressFlyout= */ true, /* showInShade= */ false);
Bubble existingAppBubble = mBubbleData.getBubbleInStackWithKey(KEY_APP_BUBBLE);
if (existingAppBubble != null) {
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
public void showAppBubble(Intent intent) {
public void showOrHideAppBubble(Intent intent) {
mMainExecutor.execute(() -> {
BubbleController.this.showAppBubble(intent);
BubbleController.this.showOrHideAppBubble(intent);
});
}

View File

@@ -109,13 +109,28 @@ public interface Bubbles {
void expandStackAndSelectBubble(Bubble bubble);
/**
* Adds and expands bubble that is not notification based, but instead based on an intent from
* the app. 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.
* This method has different behavior depending on:
* - if an app bubble exists
* - 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.

View File

@@ -57,7 +57,9 @@ constructor(
* 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.
*
* 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.
*/
fun showNoteTask(isInMultiWindowMode: Boolean = false) {
@@ -75,7 +77,7 @@ constructor(
context.startActivity(intent)
} else {
// 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)
verify(context).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent)
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -102,7 +102,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(bubbles).showAppBubble(notesIntent)
verify(bubbles).showOrHideAppBubble(notesIntent)
verify(context, never()).startActivity(notesIntent)
}
@@ -113,7 +113,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = true)
verify(context).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent)
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -123,7 +123,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent)
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -133,7 +133,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent)
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -143,7 +143,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent)
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -153,7 +153,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent)
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -161,7 +161,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController(isEnabled = false).showNoteTask()
verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent)
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
@Test
@@ -171,7 +171,7 @@ internal class NoteTaskControllerTest : SysuiTestCase() {
createNoteTaskController().showNoteTask(isInMultiWindowMode = false)
verify(context, never()).startActivity(notesIntent)
verify(bubbles, never()).showAppBubble(notesIntent)
verify(bubbles, never()).showOrHideAppBubble(notesIntent)
}
// 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 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;
@@ -228,6 +229,8 @@ public class BubblesTest extends SysuiTestCase {
private BubbleEntry mBubbleEntryUser11;
private BubbleEntry mBubbleEntry2User11;
private Intent mAppBubbleIntent;
@Mock
private ShellInit mShellInit;
@Mock
@@ -323,6 +326,9 @@ public class BubblesTest extends SysuiTestCase {
mBubbleEntry2User11 = BubblesManager.notifToBubbleEntry(
mNotificationTestHelper.createBubble(handle));
mAppBubbleIntent = new Intent(mContext, BubblesTestActivity.class);
mAppBubbleIntent.setPackage(mContext.getPackageName());
mZenModeConfig.suppressedVisualEffects = 0;
when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
@@ -1630,6 +1636,62 @@ public class BubblesTest extends SysuiTestCase {
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. */
private Bubble createBubble(int userId, String pkg) {
final UserHandle userHandle = new UserHandle(userId);