diff options
11 files changed, 219 insertions, 119 deletions
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerTest.kt index cec67f26af92..71097aba87e2 100644 --- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerTest.kt +++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerTest.kt @@ -64,7 +64,7 @@ import org.mockito.kotlin.mock import org.mockito.kotlin.whenever import java.util.Optional -/** Tests for [BubbleControllerTest] */ +/** Tests for [BubbleController] */ @SmallTest @RunWith(AndroidJUnit4::class) class BubbleControllerTest { @@ -140,7 +140,7 @@ class BubbleControllerTest { assertThat(bubbleController.hasBubbles()).isTrue() assertThat(bubbleData.getAnyBubbleWithKey(expectedKey)).isNotNull() - assertThat(bubbleData.getAnyBubbleWithKey(expectedKey)!!.isNoteBubble).isTrue() + assertThat(bubbleData.getAnyBubbleWithKey(expectedKey)!!.isNote).isTrue() } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java index c1dadada505a..5bd8d86f1144 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BadgedImageView.java @@ -357,9 +357,9 @@ public class BadgedImageView extends ConstraintLayout { void showBadge() { Bitmap appBadgeBitmap = mBubble.getAppBadge(); - final boolean isAppLaunchIntent = (mBubble instanceof Bubble) - && ((Bubble) mBubble).isAppLaunchIntent(); - if (appBadgeBitmap == null || isAppLaunchIntent) { + final boolean showAppBadge = (mBubble instanceof Bubble) + && ((Bubble) mBubble).showAppBadge(); + if (appBadgeBitmap == null || !showAppBadge) { mAppIcon.setVisibility(GONE); return; } 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 d77c177437b8..50ff58d7cf22 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 @@ -56,7 +56,6 @@ import com.android.wm.shell.bubbles.bar.BubbleBarExpandedView; import com.android.wm.shell.bubbles.bar.BubbleBarLayerView; import com.android.wm.shell.shared.annotations.ShellBackgroundThread; import com.android.wm.shell.shared.annotations.ShellMainThread; -import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper; import com.android.wm.shell.shared.bubbles.BubbleInfo; import com.android.wm.shell.shared.bubbles.ParcelableFlyoutMessage; import com.android.wm.shell.taskview.TaskView; @@ -78,11 +77,19 @@ public class Bubble implements BubbleViewProvider { /** A string prefix used in note bubbles' {@link #mKey}. */ public static final String KEY_NOTE_BUBBLE = "key_note_bubble"; - /** Whether the bubble is an app bubble. */ - private final boolean mIsAppBubble; + /** The possible types a bubble may be. */ + public enum BubbleType { + /** Chat is from a notification. */ + TYPE_CHAT, + /** Notes are from the note taking API. */ + TYPE_NOTE, + /** Shortcuts from bubble anything, based on {@link ShortcutInfo}. */ + TYPE_SHORTCUT, + /** Apps are from bubble anything. */ + TYPE_APP, + } - /** Whether the bubble is a notetaking bubble. */ - private final boolean mIsNoteBubble; + private final BubbleType mType; private final String mKey; @Nullable @@ -221,7 +228,6 @@ public class Bubble implements BubbleViewProvider { * 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. */ - @VisibleForTesting(visibility = PRIVATE) public Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo, final int desiredHeight, final int desiredHeightResId, @Nullable final String title, int taskId, @Nullable final String locus, boolean isDismissable, @@ -248,16 +254,15 @@ public class Bubble implements BubbleViewProvider { mBgExecutor = bgExecutor; mTaskId = taskId; mBubbleMetadataFlagListener = listener; - mIsAppBubble = false; - mIsNoteBubble = false; + // TODO (b/394085999) read/write type to xml + mType = BubbleType.TYPE_CHAT; } private Bubble( Intent intent, UserHandle user, @Nullable Icon icon, - boolean isAppBubble, - boolean isNoteBubble, + BubbleType type, String key, @ShellMainThread Executor mainExecutor, @ShellBackgroundThread Executor bgExecutor) { @@ -266,8 +271,7 @@ public class Bubble implements BubbleViewProvider { mFlags = 0; mUser = user; mIcon = icon; - mIsAppBubble = isAppBubble; - mIsNoteBubble = isNoteBubble; + mType = type; mKey = key; mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; @@ -285,8 +289,7 @@ public class Bubble implements BubbleViewProvider { mFlags = 0; mUser = info.getUserHandle(); mIcon = info.getIcon(); - mIsAppBubble = false; - mIsNoteBubble = false; + mType = BubbleType.TYPE_SHORTCUT; mKey = getBubbleKeyForShortcut(info); mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; @@ -310,8 +313,7 @@ public class Bubble implements BubbleViewProvider { mFlags = 0; mUser = user; mIcon = icon; - mIsAppBubble = true; - mIsNoteBubble = false; + mType = BubbleType.TYPE_APP; mKey = key; mShowBubbleUpdateDot = false; mMainExecutor = mainExecutor; @@ -322,15 +324,14 @@ public class Bubble implements BubbleViewProvider { mPackageName = task.baseActivity.getPackageName(); } - /** Creates a notetaking bubble. */ + /** Creates a note taking bubble. */ public static Bubble createNotesBubble(Intent intent, UserHandle user, @Nullable Icon icon, @ShellMainThread Executor mainExecutor, @ShellBackgroundThread Executor bgExecutor) { return new Bubble(intent, user, icon, - /* isAppBubble= */ true, - /* isNoteBubble= */ true, - /* key= */ getNoteBubbleKeyForApp(intent.getPackage(), user), + BubbleType.TYPE_NOTE, + getNoteBubbleKeyForApp(intent.getPackage(), user), mainExecutor, bgExecutor); } @@ -340,9 +341,8 @@ public class Bubble implements BubbleViewProvider { return new Bubble(intent, user, icon, - /* isAppBubble= */ true, - /* isNoteBubble= */ false, - /* key= */ getAppBubbleKeyForApp(intent.getPackage(), user), + BubbleType.TYPE_APP, + getAppBubbleKeyForApp(intent.getPackage(), user), mainExecutor, bgExecutor); } @@ -400,13 +400,15 @@ public class Bubble implements BubbleViewProvider { return KEY_APP_BUBBLE + ":" + taskInfo.taskId; } + /** + * Creates a chat bubble based on a notification (contents of {@link BubbleEntry}. + */ @VisibleForTesting(visibility = PRIVATE) public Bubble(@NonNull final BubbleEntry entry, final Bubbles.BubbleMetadataFlagListener listener, final Bubbles.PendingIntentCanceledListener intentCancelListener, @ShellMainThread Executor mainExecutor, @ShellBackgroundThread Executor bgExecutor) { - mIsAppBubble = false; - mIsNoteBubble = false; + mType = BubbleType.TYPE_CHAT; mKey = entry.getKey(); mGroupKey = entry.getGroupKey(); mLocusId = entry.getLocusId(); @@ -436,7 +438,7 @@ public class Bubble implements BubbleViewProvider { getTitle(), getAppName(), isImportantConversation(), - !isAppLaunchIntent(), + showAppBadge(), getParcelableFlyoutMessage()); } @@ -1005,13 +1007,6 @@ public class Bubble implements BubbleViewProvider { } /** - * Whether this bubble is conversation - */ - public boolean isConversation() { - return null != mShortcutInfo; - } - - /** * Sets whether this notification should be suppressed in the shade. */ @VisibleForTesting @@ -1128,14 +1123,10 @@ public class Bubble implements BubbleViewProvider { } /** - * Whether this bubble represents the full app, i.e. the intent used is the launch - * intent for an app. In this case we don't show a badge on the icon. + * Whether an app badge should be shown for this bubble. */ - public boolean isAppLaunchIntent() { - if (BubbleAnythingFlagHelper.enableCreateAnyBubble() && mIntent != null) { - return mIntent.hasCategory("android.intent.category.LAUNCHER"); - } - return false; + public boolean showAppBadge() { + return isChat() || isShortcut() || isNote(); } /** @@ -1162,17 +1153,31 @@ public class Bubble implements BubbleViewProvider { } /** - * Returns whether this bubble is from an app (as well as notetaking) versus a notification. + * Returns whether this bubble is a conversation from the notification API. + */ + public boolean isChat() { + return mType == BubbleType.TYPE_CHAT; + } + + /** + * Returns whether this bubble is a note from the note taking API. + */ + public boolean isNote() { + return mType == BubbleType.TYPE_NOTE; + } + + /** + * Returns whether this bubble is a shortcut. */ - public boolean isAppBubble() { - return mIsAppBubble; + public boolean isShortcut() { + return mType == BubbleType.TYPE_SHORTCUT; } /** - * Returns whether this bubble is specific from the notetaking API. + * Returns whether this bubble is an app. */ - public boolean isNoteBubble() { - return mIsNoteBubble; + public boolean isApp() { + return mType == BubbleType.TYPE_APP; } /** Creates open app settings intent */ 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 10efd8e164e4..66abcabed109 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 @@ -2890,7 +2890,7 @@ public class BubbleController implements ConfigurationChangeListener, mShortcutIdToBubble.put(b.getShortcutId(), b); updateBubbleSuppressedState(b); - if (b.isNoteBubble()) { + if (b.isNote()) { mNoteBubbleTaskIds.put(b.getKey(), b.getTaskId()); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt index bd4708259b50..ed23986d0f64 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleEducationController.kt @@ -83,4 +83,4 @@ class BubbleEducationController(private val context: Context) { /** Convenience extension method to check if the bubble is a conversation bubble */ private val BubbleViewProvider.isConversationBubble: Boolean - get() = if (this is Bubble) isConversation else false + get() = if (this is Bubble) isChat else false 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 ad9ab7a722ee..3f607a9c52ef 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 @@ -227,10 +227,11 @@ public class BubbleExpandedView extends LinearLayout { MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS); final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId() - || (mBubble.getShortcutInfo() != null + || (mBubble.isShortcut() && BubbleAnythingFlagHelper.enableCreateAnyBubble())); - if (mBubble.isAppBubble()) { + // TODO - currently based on type, really it's what the "launch item" is. + if (mBubble.isApp() || mBubble.isNote()) { Context context = mContext.createContextAsUser( mBubble.getUser(), Context.CONTEXT_RESTRICTED); @@ -284,7 +285,7 @@ public class BubbleExpandedView extends LinearLayout { // The taskId is saved to use for removeTask, preventing appearance in recent tasks. mTaskId = taskId; - if (mBubble != null && mBubble.isNoteBubble()) { + if (mBubble != null && mBubble.isNote()) { // Let the controller know sooner what the taskId is. mManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java index 3babc0d801c4..dad627f85d95 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java @@ -1385,16 +1385,16 @@ public class BubbleStackView extends FrameLayout /** * Whether the selected bubble is conversation bubble */ - private boolean isConversationBubble() { + private boolean isChat() { BubbleViewProvider bubble = mBubbleData.getSelectedBubble(); - return bubble instanceof Bubble && ((Bubble) bubble).isConversation(); + return bubble instanceof Bubble && ((Bubble) bubble).isChat(); } /** * Whether the educational view should show for the expanded view "manage" menu. */ private boolean shouldShowManageEdu() { - if (!isConversationBubble()) { + if (!isChat()) { // We only show user education for conversation bubbles right now return false; } @@ -1441,7 +1441,7 @@ public class BubbleStackView extends FrameLayout * Whether education view should show for the collapsed stack. */ private boolean shouldShowStackEdu() { - if (!isConversationBubble()) { + if (!isChat()) { // We only show user education for conversation bubbles right now return false; } @@ -1976,7 +1976,7 @@ public class BubbleStackView extends FrameLayout return; } - if (firstBubble && bubble.isNoteBubble() && !mPositioner.hasUserModifiedDefaultPosition()) { + if (firstBubble && bubble.isNote() && !mPositioner.hasUserModifiedDefaultPosition()) { // If it's an note bubble and we don't have a previous resting position, update the // controllers to use the default position for the note bubble (it'd be different from // the position initialized with the controllers originally). @@ -3322,20 +3322,16 @@ public class BubbleStackView extends FrameLayout // name and icon. if (show) { final Bubble bubble = mBubbleData.getBubbleInStackWithKey(mExpandedBubble.getKey()); - if (bubble != null && !bubble.isAppBubble()) { - // Setup options for non app bubbles + if (bubble != null && bubble.isChat()) { + // Setup options for chat bubbles mManageDontBubbleView.setVisibility(VISIBLE); mManageSettingsIcon.setImageBitmap(bubble.getRawAppBadge()); mManageSettingsText.setText(getResources().getString( R.string.bubbles_app_settings, bubble.getAppName())); mManageSettingsView.setVisibility(VISIBLE); } else { - // Setup options for app bubbles - // App bubbles have no conversations - // so we don't show the option to not bubble conversation + // Not a chat bubble, so don't show conversation / notification settings mManageDontBubbleView.setVisibility(GONE); - // App bubbles are not notification based - // so we don't show the option to go to notification settings mManageSettingsView.setVisibility(GONE); } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java index 0d89bb260bf5..4a0eee861d21 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTaskViewHelper.java @@ -100,6 +100,7 @@ public class BubbleTaskViewHelper { // TODO: I notice inconsistencies in lifecycle // Post to keep the lifecycle normal + // TODO - currently based on type, really it's what the "launch item" is. mParentView.post(() -> { ProtoLog.d(WM_SHELL_BUBBLES, "onInitialized: calling startActivity, bubble=%s", getBubbleKey()); @@ -108,11 +109,11 @@ public class BubbleTaskViewHelper { options.setPendingIntentBackgroundActivityStartMode( MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS); final boolean isShortcutBubble = (mBubble.hasMetadataShortcutId() - || (mBubble.getShortcutInfo() != null + || (mBubble.isShortcut() && BubbleAnythingFlagHelper.enableCreateAnyBubble())); if (mBubble.getPreparingTransition() != null) { mBubble.getPreparingTransition().surfaceCreated(); - } else if (mBubble.isAppBubble()) { + } else if (mBubble.isApp() || mBubble.isNote()) { Context context = mContext.createContextAsUser( mBubble.getUser(), Context.CONTEXT_RESTRICTED); @@ -167,7 +168,7 @@ public class BubbleTaskViewHelper { // The taskId is saved to use for removeTask, preventing appearance in recent tasks. mTaskId = taskId; - if (mBubble != null && mBubble.isNoteBubble()) { + if (mBubble != null && mBubble.isNote()) { // Let the controller know sooner what the taskId is. mExpandedViewManager.setNoteBubbleTaskId(mBubble.getKey(), mTaskId); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java index 5f437d4af40f..b7761ec75782 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarMenuViewController.java @@ -222,7 +222,7 @@ class BubbleBarMenuViewController { Resources resources = mContext.getResources(); int tintColor = mContext.getColor(com.android.internal.R.color.materialColorOnSurface); - if (bubble.isConversation()) { + if (bubble.isChat()) { // Don't bubble conversation action menuActions.add(new BubbleBarMenuView.MenuAction( Icon.createWithResource(mContext, R.drawable.bubble_ic_stop_bubble), diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java index dca5fc4c2fe0..2c0ced4fd8de 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTest.java @@ -22,18 +22,22 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; import android.app.PendingIntent; +import android.app.TaskInfo; +import android.content.ComponentName; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.content.res.Resources; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.UserHandle; +import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -60,13 +64,17 @@ public class BubbleTest extends ShellTestCase { @Mock private StatusBarNotification mSbn; @Mock + private NotificationListenerService.Ranking mRanking; + @Mock private ShellExecutor mMainExecutor; @Mock private ShellExecutor mBgExecutor; - private BubbleEntry mBubbleEntry; private Bundle mExtras; - private Bubble mBubble; + + // This entry / bubble are set up with PendingIntent / Icon API for chat + private BubbleEntry mBubbleEntry; + private Bubble mChatBubble; @Mock private Bubbles.BubbleMetadataFlagListener mBubbleMetadataFlagListener; @@ -83,11 +91,16 @@ public class BubbleTest extends ShellTestCase { PendingIntent.getActivity(mContext, 0, target, PendingIntent.FLAG_MUTABLE), Icon.createWithResource(mContext, R.drawable.bubble_ic_create_bubble)) .build(); + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) + .setId("shortcutId") + .build(); when(mSbn.getNotification()).thenReturn(mNotif); when(mNotif.getBubbleMetadata()).thenReturn(metadata); when(mSbn.getKey()).thenReturn("mock"); - mBubbleEntry = new BubbleEntry(mSbn, null, true, false, false, false); - mBubble = new Bubble(mBubbleEntry, mBubbleMetadataFlagListener, null, mMainExecutor, + when(mRanking.getConversationShortcutInfo()).thenReturn(shortcutInfo); + + mBubbleEntry = new BubbleEntry(mSbn, mRanking, true, false, false, false); + mChatBubble = new Bubble(mBubbleEntry, mBubbleMetadataFlagListener, null, mMainExecutor, mBgExecutor); } @@ -152,42 +165,113 @@ public class BubbleTest extends ShellTestCase { @Test public void testBubbleMetadataFlagListener_change_notified() { - assertThat(mBubble.showInShade()).isTrue(); + assertThat(mChatBubble.showInShade()).isTrue(); - mBubble.setSuppressNotification(true); + mChatBubble.setSuppressNotification(true); - assertThat(mBubble.showInShade()).isFalse(); + assertThat(mChatBubble.showInShade()).isFalse(); - verify(mBubbleMetadataFlagListener).onBubbleMetadataFlagChanged(mBubble); + verify(mBubbleMetadataFlagListener).onBubbleMetadataFlagChanged(mChatBubble); } @Test public void testBubbleMetadataFlagListener_noChange_doesntNotify() { - assertThat(mBubble.showInShade()).isTrue(); + assertThat(mChatBubble.showInShade()).isTrue(); - mBubble.setSuppressNotification(false); + mChatBubble.setSuppressNotification(false); verify(mBubbleMetadataFlagListener, never()).onBubbleMetadataFlagChanged(any()); } @Test - public void testBubbleIsConversation_hasConversationShortcut() { - Bubble bubble = createBubbleWithShortcut(); - assertThat(bubble.getShortcutInfo()).isNotNull(); - assertThat(bubble.isConversation()).isTrue(); + public void testBubbleType_conversationShortcut() { + Bubble bubble = createChatBubble(true /* useShortcut */); + assertThat(bubble.isChat()).isTrue(); } @Test - public void testBubbleIsConversation_hasNoShortcut() { - Bubble bubble = new Bubble(mBubbleEntry, mBubbleMetadataFlagListener, null, mMainExecutor, - mBgExecutor); - assertThat(bubble.getShortcutInfo()).isNull(); - assertThat(bubble.isConversation()).isFalse(); + public void testBubbleType_conversationPendingIntent() { + Bubble bubble = createChatBubble(false /* useShortcut */); + assertThat(bubble.isChat()).isTrue(); + } + + @Test + public void testBubbleType_note() { + Bubble bubble = Bubble.createNotesBubble(createIntent(), UserHandle.of(0), + mock(Icon.class), + mMainExecutor, mBgExecutor); + assertThat(bubble.isNote()).isTrue(); + } + + @Test + public void testBubbleType_shortcut() { + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) + .setId("mockShortcutId") + .build(); + Bubble bubble = Bubble.createShortcutBubble(shortcutInfo, mMainExecutor, mBgExecutor); + assertThat(bubble.isShortcut()).isTrue(); + } + + @Test + public void testBubbleType_intent() { + Bubble bubble = Bubble.createAppBubble(createIntent(), UserHandle.of(0), + mock(Icon.class), + mMainExecutor, mBgExecutor); + assertThat(bubble.isApp()).isTrue(); + } + + @Test + public void testBubbleType_taskId() { + TaskInfo info = mock(TaskInfo.class); + ComponentName componentName = mock(ComponentName.class); + when(componentName.getPackageName()).thenReturn(mContext.getPackageName()); + info.taskId = 1; + info.baseActivity = componentName; + Bubble bubble = Bubble.createTaskBubble(info, UserHandle.of(0), + mock(Icon.class), + mMainExecutor, mBgExecutor); + assertThat(bubble.isApp()).isTrue(); + } + + @Test + public void testShowAppBadge_chat() { + Bubble bubble = createChatBubble(true /* useShortcut */); + assertThat(bubble.isChat()).isTrue(); + assertThat(bubble.showAppBadge()).isTrue(); + } + + @Test + public void testShowAppBadge_note() { + Bubble bubble = Bubble.createNotesBubble(createIntent(), UserHandle.of(0), + mock(Icon.class), + mMainExecutor, mBgExecutor); + assertThat(bubble.isNote()).isTrue(); + assertThat(bubble.showAppBadge()).isTrue(); + } + + @Test + public void testShowAppBadge_app() { + Bubble bubble = Bubble.createAppBubble(createIntent(), UserHandle.of(0), + mock(Icon.class), + mMainExecutor, mBgExecutor); + assertThat(bubble.isApp()).isTrue(); + assertThat(bubble.showAppBadge()).isFalse(); + } + + @Test + public void testShowAppBadge_shortcut() { + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) + .setId("mockShortcutId") + .build(); + Bubble bubble = Bubble.createShortcutBubble(shortcutInfo, + mMainExecutor, mBgExecutor); + assertThat(bubble.isShortcut()).isTrue(); + assertThat(bubble.showAppBadge()).isTrue(); } @Test public void testBubbleAsBubbleBarBubble_withShortcut() { - Bubble bubble = createBubbleWithShortcut(); + Bubble bubble = createChatBubble(true /* useShortcut */); BubbleInfo bubbleInfo = bubble.asBubbleBarBubble(); assertThat(bubble.getShortcutInfo()).isNotNull(); @@ -199,7 +283,7 @@ public class BubbleTest extends ShellTestCase { } @Test - public void testBubbleAsBubbleBarBubble_withoutShortcut() { + public void testBubbleAsBubbleBarBubble_withIntent() { Intent intent = new Intent(mContext, BubblesTestActivity.class); intent.setPackage(mContext.getPackageName()); Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1 /* userId */), @@ -213,12 +297,23 @@ public class BubbleTest extends ShellTestCase { assertThat(bubbleInfo.getPackageName()).isEqualTo(bubble.getPackageName()); } - private Bubble createBubbleWithShortcut() { - ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) - .setId("mockShortcutId") - .build(); - return new Bubble("mockKey", shortcutInfo, 10, Resources.ID_NULL, - "mockTitle", 0 /* taskId */, "mockLocus", true /* isDismissible */, - mMainExecutor, mBgExecutor, mBubbleMetadataFlagListener); + private Intent createIntent() { + Intent intent = new Intent(mContext, BubblesTestActivity.class); + intent.setPackage(mContext.getPackageName()); + return intent; + } + + private Bubble createChatBubble(boolean useShortcut) { + if (useShortcut) { + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) + .setId("mockShortcutId") + .build(); + return new Bubble("mockKey", shortcutInfo, 10, Resources.ID_NULL, + "mockTitle", 0 /* taskId */, "mockLocus", true /* isDismissible */, + mMainExecutor, mBgExecutor, mBubbleMetadataFlagListener); + } else { + return new Bubble(mBubbleEntry, mBubbleMetadataFlagListener, null, mMainExecutor, + mBgExecutor); + } } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java index bf10dc6c4aef..a38d71b178e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java @@ -1923,13 +1923,13 @@ public class BubblesTest extends SysuiTestCase { public void testShowStackEdu_isNotConversationBubble() { // Setup setPrefBoolean(StackEducationView.PREF_STACK_EDUCATION, false); - BubbleEntry bubbleEntry = createBubbleEntry(false /* isConversation */); - mBubbleController.updateBubble(bubbleEntry); + mBubbleController.showOrHideNotesBubble(mNotesBubbleIntent, mUser0, mNotesBubbleIcon); assertTrue(mBubbleController.hasBubbles()); - + String noteBubbleKey = Bubble.getNoteBubbleKeyForApp(mNotesBubbleIntent.getPackage(), + mUser0); // Click on bubble - Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey()); - assertFalse(bubble.isConversation()); + Bubble bubble = mBubbleData.getBubbleInStackWithKey(noteBubbleKey); + assertFalse(bubble.isChat()); bubble.getIconView().callOnClick(); // Check education is not shown @@ -1941,13 +1941,13 @@ public class BubblesTest extends SysuiTestCase { public void testShowStackEdu_isConversationBubble() { // Setup setPrefBoolean(StackEducationView.PREF_STACK_EDUCATION, false); - BubbleEntry bubbleEntry = createBubbleEntry(true /* isConversation */); + BubbleEntry bubbleEntry = createBubbleEntry(); mBubbleController.updateBubble(bubbleEntry); assertTrue(mBubbleController.hasBubbles()); // Click on bubble Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey()); - assertTrue(bubble.isConversation()); + assertTrue(bubble.isChat()); bubble.getIconView().callOnClick(); // Check education is shown @@ -1959,13 +1959,13 @@ public class BubblesTest extends SysuiTestCase { public void testShowStackEdu_isSeenConversationBubble() { // Setup setPrefBoolean(StackEducationView.PREF_STACK_EDUCATION, true); - BubbleEntry bubbleEntry = createBubbleEntry(true /* isConversation */); + BubbleEntry bubbleEntry = createBubbleEntry(); mBubbleController.updateBubble(bubbleEntry); assertTrue(mBubbleController.hasBubbles()); // Click on bubble Bubble bubble = mBubbleData.getBubbleInStackWithKey(bubbleEntry.getKey()); - assertTrue(bubble.isConversation()); + assertTrue(bubble.isChat()); bubble.getIconView().callOnClick(); // Check education is not shown @@ -2690,17 +2690,19 @@ public class BubblesTest extends SysuiTestCase { mock(Bubbles.PendingIntentCanceledListener.class), executor, executor); } - private BubbleEntry createBubbleEntry(boolean isConversation) { + /** + * Creates a BubbleEntry, which will represent a chat bubble. + * All bubble entries are notification based & therefore are chat bubbles. + */ + private BubbleEntry createBubbleEntry() { NotificationEntry notificationEntry = mNotificationTestHelper.createBubble(mDeleteIntent); - if (isConversation) { - ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) - .setId("shortcutId") - .build(); - NotificationEntryHelper.modifyRanking(notificationEntry) - .setIsConversation(true) - .setShortcutInfo(shortcutInfo) - .build(); - } + ShortcutInfo shortcutInfo = new ShortcutInfo.Builder(mContext) + .setId("shortcutId") + .build(); + NotificationEntryHelper.modifyRanking(notificationEntry) + .setIsConversation(true) + .setShortcutInfo(shortcutInfo) + .build(); return mBubblesManager.notifToBubbleEntry(notificationEntry); } |