Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e80930ea authored by Mady Mellor's avatar Mady Mellor
Browse files

Auto expand bubbles when foreground with the flag set

- Tests if you're not foreground that it's not auto expanded
- Tests if you are foreground it does expand

Test: atest BubbleControllerTest
Bug: 123542531
Change-Id: I016a39236f1d1ac83518f6cc57099c4e5bc83686
parent c6479fd8
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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
+83 −1
Original line number Diff line number Diff line
@@ -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);
@@ -302,6 +316,63 @@ public class BubbleControllerTest extends SysuiTestCase {
        assertFalse(mBubbleController.hasBubbles());
    }

    @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());
@@ -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));
    }
}
+7 −0
Original line number Diff line number Diff line
@@ -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);
    }
}
+27 −13
Original line number Diff line number Diff line
@@ -151,23 +151,40 @@ 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.
     *
@@ -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();
    }