diff options
4 files changed, 139 insertions, 14 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 4a2731e5437a..0b12ea56b8c7 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -26,6 +26,7 @@ import static com.android.systemui.statusbar.notification.NotificationAlertingMa import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.Nullable; +import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.app.IActivityTaskManager; @@ -64,6 +65,7 @@ import com.android.systemui.statusbar.phone.StatusBarWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; import java.lang.annotation.Retention; +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -340,6 +342,9 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe // It's new mStackView.addBubble(notif); } + if (shouldAutoExpand(notif)) { + mStackView.setExpandedBubble(notif); + } updateVisibility(); } @@ -522,6 +527,23 @@ public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListe || autoBubbleAll; } + private boolean shouldAutoExpand(NotificationEntry entry) { + Notification.BubbleMetadata metadata = entry.getBubbleMetadata(); + return metadata != null && metadata.getAutoExpandBubble() + && isForegroundApp(entry.notification.getPackageName()); + } + + /** + * Return true if the applications with the package name is running in foreground. + * + * @param pkgName application package name. + */ + private boolean isForegroundApp(String pkgName) { + ActivityManager am = mContext.getSystemService(ActivityManager.class); + List<RunningTaskInfo> tasks = am.getRunningTasks(1 /* maxNum */); + return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName()); + } + /** * This task stack listener is responsible for responding to tasks moved to the front * which are on the default (main) display. When this happens, expanded bubbles must be diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index c9b550cd6e64..f666d60d6282 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -16,6 +16,8 @@ package com.android.systemui.bubbles; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -26,8 +28,13 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.IActivityManager; +import android.app.Notification; import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.graphics.drawable.Icon; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.WindowManager; @@ -36,6 +43,7 @@ import android.widget.FrameLayout; import androidx.test.filters.SmallTest; import com.android.internal.statusbar.NotificationVisibility; +import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.NotificationTestHelper; import com.android.systemui.statusbar.notification.NotificationEntryListener; @@ -55,6 +63,9 @@ import org.mockito.Captor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + @SmallTest @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @@ -83,6 +94,7 @@ public class BubbleControllerTest extends SysuiTestCase { private ExpandableNotificationRow mRow; private ExpandableNotificationRow mRow2; private ExpandableNotificationRow mNoChannelRow; + private ExpandableNotificationRow mAutoExpandRow; @Mock private NotificationData mNotificationData; @@ -104,7 +116,6 @@ public class BubbleControllerTest extends SysuiTestCase { mStatusBarView = new FrameLayout(mContext); mDependency.injectTestDependency(NotificationEntryManager.class, mNotificationEntryManager); - // Bubbles get added to status bar window view mStatusBarWindowController = new StatusBarWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters); @@ -115,6 +126,9 @@ public class BubbleControllerTest extends SysuiTestCase { mRow = mNotificationTestHelper.createBubble(mDeleteIntent); mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent); mNoChannelRow = mNotificationTestHelper.createBubble(mDeleteIntent); + Notification.BubbleMetadata metadata = getBuilder().setAutoExpandBubble(true).build(); + mAutoExpandRow = mNotificationTestHelper.createBubble(metadata, + "com.android.systemui.tests"); // Return non-null notification data from the NEM when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData); @@ -303,6 +317,63 @@ public class BubbleControllerTest extends SysuiTestCase { } @Test + public void testAutoExpandFailsNotForeground() { + assertFalse(mBubbleController.isStackExpanded()); + + // Add the auto expand bubble + mEntryListener.onPendingEntryAdded(mAutoExpandRow.getEntry()); + mBubbleController.updateBubble(mAutoExpandRow.getEntry(), true /* updatePosition */); + + // Expansion shouldn't change + verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */, + mAutoExpandRow.getEntry().key); + assertFalse(mBubbleController.isStackExpanded()); + + // # of bubbles should change + verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */); + } + + @Test + public void testAutoExpandSucceedsForeground() { + final CountDownLatch latch = new CountDownLatch(1); + BroadcastReceiver receiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + latch.countDown(); + } + }; + IntentFilter filter = new IntentFilter(BubblesTestActivity.BUBBLE_ACTIVITY_OPENED); + mContext.registerReceiver(receiver, filter); + + assertFalse(mBubbleController.isStackExpanded()); + + // Make ourselves foreground + Intent i = new Intent(mContext, BubblesTestActivity.class); + i.setFlags(FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(i); + + try { + latch.await(100, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + // Add the auto expand bubble + mEntryListener.onPendingEntryAdded(mAutoExpandRow.getEntry()); + mBubbleController.updateBubble(mAutoExpandRow.getEntry(), true /* updatePosition */); + + // Expansion should change + verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */, + mAutoExpandRow.getEntry().key); + assertTrue(mBubbleController.isStackExpanded()); + + // # of bubbles should change + verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */); + mContext.unregisterReceiver(receiver); + } + + + @Test public void testMarkNewNotificationAsBubble() { mEntryListener.onPendingEntryAdded(mRow.getEntry()); assertTrue(mRow.getEntry().isBubble()); @@ -349,4 +420,15 @@ public class BubbleControllerTest extends SysuiTestCase { return entry.notification.getNotification().getBubbleMetadata() != null; } } + + /** + * @return basic {@link android.app.Notification.BubbleMetadata.Builder} + */ + private Notification.BubbleMetadata.Builder getBuilder() { + Intent target = new Intent(mContext, BubblesTestActivity.class); + PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target, 0); + return new Notification.BubbleMetadata.Builder() + .setIntent(bubbleIntent) + .setIcon(Icon.createWithResource(mContext, R.drawable.android)); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java index ea472da910f2..43d2ad1dfe0a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubblesTestActivity.java @@ -17,6 +17,7 @@ package com.android.systemui.bubbles; import android.app.Activity; +import android.content.Intent; import android.os.Bundle; import com.android.systemui.R; @@ -26,9 +27,15 @@ import com.android.systemui.R; */ public class BubblesTestActivity extends Activity { + public static final String BUBBLE_ACTIVITY_OPENED = + "com.android.systemui.bubbles.BUBBLE_ACTIVITY_OPENED"; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); + + Intent i = new Intent(BUBBLE_ACTIVITY_OPENED); + sendBroadcast(i); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index 1bcf8803b5cf..8c5f6f24ee79 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -151,24 +151,41 @@ public class NotificationTestHelper { /** * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble. + * + * @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent} */ - public ExpandableNotificationRow createBubble() throws Exception { - return createBubble(null); + public ExpandableNotificationRow createBubble(@Nullable PendingIntent deleteIntent) + throws Exception { + Notification n = createNotification(false /* isGroupSummary */, + null /* groupKey */, makeBubbleMetadata(deleteIntent)); + return generateRow(n, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH); } /** * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble. * - * @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent} + * @param bubbleMetadata the {@link BubbleMetadata} to use */ - public ExpandableNotificationRow createBubble(@Nullable PendingIntent deleteIntent) + public ExpandableNotificationRow createBubble(BubbleMetadata bubbleMetadata) throws Exception { Notification n = createNotification(false /* isGroupSummary */, - null /* groupKey */, true /* isBubble */, deleteIntent); + null /* groupKey */, bubbleMetadata); return generateRow(n, PKG, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH); } /** + * Returns an {@link ExpandableNotificationRow} that should be shown as a bubble. + * + * @param bubbleMetadata the {@link BubbleMetadata} to use + */ + public ExpandableNotificationRow createBubble(BubbleMetadata bubbleMetadata, String pkg) + throws Exception { + Notification n = createNotification(false /* isGroupSummary */, + null /* groupKey */, bubbleMetadata); + return generateRow(n, pkg, UID, USER_HANDLE, 0 /* extraInflationFlags */, IMPORTANCE_HIGH); + } + + /** * Creates a notification row with the given details. * * @param pkg package used for creating a {@link StatusBarNotification} @@ -207,8 +224,7 @@ public class NotificationTestHelper { * @return a notification that is in the group specified or standalone if unspecified */ private Notification createNotification(boolean isGroupSummary, @Nullable String groupKey) { - return createNotification(isGroupSummary, groupKey, false /* isBubble */, - null /* bubbleDeleteIntent */); + return createNotification(isGroupSummary, groupKey, null /* bubble metadata */); } /** @@ -216,12 +232,11 @@ public class NotificationTestHelper { * * @param isGroupSummary whether the notification is a group summary * @param groupKey the group key for the notification group used across notifications - * @param isBubble whether this notification should bubble + * @param bubbleMetadata the bubble metadata to use for this notification if it exists. * @return a notification that is in the group specified or standalone if unspecified */ private Notification createNotification(boolean isGroupSummary, - @Nullable String groupKey, boolean isBubble, - @Nullable PendingIntent bubbleDeleteIntent) { + @Nullable String groupKey, @Nullable BubbleMetadata bubbleMetadata) { Notification publicVersion = new Notification.Builder(mContext).setSmallIcon( R.drawable.ic_person) .setCustomContentView(new RemoteViews(mContext.getPackageName(), @@ -239,9 +254,8 @@ public class NotificationTestHelper { if (!TextUtils.isEmpty(groupKey)) { notificationBuilder.setGroup(groupKey); } - if (isBubble) { - BubbleMetadata metadata = makeBubbleMetadata(bubbleDeleteIntent); - notificationBuilder.setBubbleMetadata(metadata); + if (bubbleMetadata != null) { + notificationBuilder.setBubbleMetadata(bubbleMetadata); } return notificationBuilder.build(); } |