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

Commit 8de6adaf authored by Ats Jenk's avatar Ats Jenk
Browse files

Listen for dreaming state changes in BubblesManager

Fixes a bug with bubbles remaining hidden if keyguard dismissed event is
received before dreaming stops.

Bubbles are hidden when device is locked or is in dreaming state.
We have a callback to get notified of keyguard state changes.
That callback checks for both keyguard state and dreaming state.
We were not listening specifically for dreaming state changes.
This led to a bug with bubbles remaining hidden after device unlock.
We were not notified of dreaming state change and left the bubbles
hidden.
We were already listening for status bar events. This change includes a
check for dreaming state changes. If dreaming state changes and keyguard
is already dismissed, we show the bubbles.

Flag: NONE
Bug: 314124017
Test: atest SystemUITests:BubblesTest
Test: manual
    - have fingerprint lock set up on the device
    - open gmail
    - lock device
    - wait for screen to turn off, unlock device with fingerprint
    - trigger a bubble
    - observe that bubble is visible

Change-Id: Id58ad112828748fcc0709b1366fe447fc22f357b
parent 7682cc97
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import com.android.systemui.complication.dagger.ComplicationComponent;
import com.android.systemui.controls.dagger.ControlsModule;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dagger.qualifiers.SystemUser;
import com.android.systemui.dagger.qualifiers.UiBackground;
import com.android.systemui.demomode.dagger.DemoModeModule;
import com.android.systemui.deviceentry.DeviceEntryModule;
import com.android.systemui.display.DisplayModule;
@@ -365,7 +366,8 @@ public abstract class SystemUIModule {
            SysUiState sysUiState,
            FeatureFlags featureFlags,
            NotifPipelineFlags notifPipelineFlags,
            @Main Executor sysuiMainExecutor) {
            @Main Executor sysuiMainExecutor,
            @UiBackground Executor sysuiUiBgExecutor) {
        return Optional.ofNullable(BubblesManager.create(context,
                bubblesOptional,
                notificationShadeWindowController,
@@ -384,7 +386,8 @@ public abstract class SystemUIModule {
                sysUiState,
                featureFlags,
                notifPipelineFlags,
                sysuiMainExecutor));
                sysuiMainExecutor,
                sysuiUiBgExecutor));
    }

    @Binds
+38 −7
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_N
import static com.android.server.notification.Flags.screenshareNotificationHiding;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_BUBBLES;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BUBBLES;

import android.app.INotificationManager;
import android.app.Notification;
@@ -50,6 +51,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.flags.FeatureFlags;
@@ -97,6 +99,7 @@ public class BubblesManager {
    private final Context mContext;
    private final Bubbles mBubbles;
    private final NotificationShadeWindowController mNotificationShadeWindowController;
    private final KeyguardStateController mKeyguardStateController;
    private final ShadeController mShadeController;
    private final IStatusBarService mBarService;
    private final INotificationManager mNotificationManager;
@@ -109,6 +112,7 @@ public class BubblesManager {
    private final NotifPipeline mNotifPipeline;
    private final NotifPipelineFlags mNotifPipelineFlags;
    private final Executor mSysuiMainExecutor;
    private final Executor mSysuiUiBgExecutor;

    private final Bubbles.SysuiProxy mSysuiProxy;
    // TODO (b/145659174): allow for multiple callbacks to support the "shadow" new notif pipeline
@@ -116,6 +120,8 @@ public class BubblesManager {
    private final StatusBarWindowCallback mStatusBarWindowCallback;
    private final Runnable mSensitiveStateChangedListener;
    private boolean mPanelExpanded;
    private boolean mKeyguardShowing;
    private boolean mDreamingOrInPreview;

    /**
     * Creates {@link BubblesManager}, returns {@code null} if Optional {@link Bubbles} not present
@@ -140,7 +146,8 @@ public class BubblesManager {
            SysUiState sysUiState,
            FeatureFlags featureFlags,
            NotifPipelineFlags notifPipelineFlags,
            Executor sysuiMainExecutor) {
            Executor sysuiMainExecutor,
            Executor sysuiUiBgExecutor) {
        if (bubblesOptional.isPresent()) {
            return new BubblesManager(context,
                    bubblesOptional.get(),
@@ -160,7 +167,8 @@ public class BubblesManager {
                    sysUiState,
                    featureFlags,
                    notifPipelineFlags,
                    sysuiMainExecutor);
                    sysuiMainExecutor,
                    sysuiUiBgExecutor);
        } else {
            return null;
        }
@@ -185,10 +193,12 @@ public class BubblesManager {
            SysUiState sysUiState,
            FeatureFlags featureFlags,
            NotifPipelineFlags notifPipelineFlags,
            Executor sysuiMainExecutor) {
            Executor sysuiMainExecutor,
            Executor sysuiUiBgExecutor) {
        mContext = context;
        mBubbles = bubbles;
        mNotificationShadeWindowController = notificationShadeWindowController;
        mKeyguardStateController = keyguardStateController;
        mShadeController = shadeController;
        mNotificationManager = notificationManager;
        mDreamManager = dreamManager;
@@ -200,6 +210,7 @@ public class BubblesManager {
        mNotifPipeline = notifPipeline;
        mNotifPipelineFlags = notifPipelineFlags;
        mSysuiMainExecutor = sysuiMainExecutor;
        mSysuiUiBgExecutor = sysuiUiBgExecutor;

        mBarService = statusBarService == null
                ? IStatusBarService.Stub.asInterface(
@@ -208,12 +219,11 @@ public class BubblesManager {

        setupNotifPipeline();

        keyguardStateController.addCallback(new KeyguardStateController.Callback() {
        // TODO(b/327410864): use KeyguardTransitionInteractor to listen for keyguard changes
        mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
            @Override
            public void onKeyguardShowingChanged() {
                boolean isUnlockedShade = !keyguardStateController.isShowing()
                        && !isDreamingOrInPreview();
                bubbles.onStatusBarStateChanged(isUnlockedShade);
                updateKeyguardAndDreamingState();
            }
        });

@@ -256,6 +266,14 @@ public class BubblesManager {
                        mPanelExpanded = panelExpanded;
                        mBubbles.onNotificationPanelExpandedChanged(panelExpanded);
                    }
                    if (!mKeyguardShowing && mDreamingOrInPreview && !isDreaming) {
                        // We check for dreaming state changes when keyguard status changes.
                        // This causes us to miss events if dreaming state changes after keyguard.
                        // Add a check here for the case where keyguard is dismissed before
                        // dreaming state changes. Otherwise bubbles remain invisible.
                        // TODO(b/327410864): use KeyguardTransitionInteractor for dreaming changes
                        updateKeyguardAndDreamingState();
                    }
                };
        notificationShadeWindowController.registerCallback(mStatusBarWindowCallback);

@@ -395,6 +413,19 @@ public class BubblesManager {
        mBubbles.setSysuiProxy(mSysuiProxy);
    }

    private void updateKeyguardAndDreamingState() {
        mSysuiUiBgExecutor.execute(() -> {
            mKeyguardShowing = mKeyguardStateController.isShowing();
            mDreamingOrInPreview = isDreamingOrInPreview();
            boolean isUnlockedShade = !mKeyguardShowing && !mDreamingOrInPreview;
            ProtoLog.d(WM_SHELL_BUBBLES,
                    "handleKeyguardOrDreamChange isUnlockedShade=%b keyguardShowing=%b "
                            + "dreamingOrInPreview=%b",
                    isUnlockedShade, mKeyguardShowing, mDreamingOrInPreview);
            mBubbles.onStatusBarStateChanged(isUnlockedShade);
        });
    }

    private boolean isDreamingOrInPreview() {
        try {
            return mDreamManager.isDreamingOrInPreview();
+12 −1
Original line number Diff line number Diff line
@@ -609,6 +609,7 @@ public class BubblesTest extends SysuiTestCase {
                mSysUiState,
                mFeatureFlags,
                mNotifPipelineFlags,
                syncExecutor,
                syncExecutor);
        mBubblesManager.addNotifCallback(mNotifCallback);

@@ -651,7 +652,7 @@ public class BubblesTest extends SysuiTestCase {
    }

    @Test
    public void dreamingHidesBubbles() throws RemoteException {
    public void bubblesHiddenWhileDreaming() throws RemoteException {
        mBubbleController.updateBubble(mBubbleEntry);
        assertTrue(mBubbleController.hasBubbles());
        assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.VISIBLE);
@@ -662,7 +663,17 @@ public class BubblesTest extends SysuiTestCase {
                mKeyguardStateControllerCallbackCaptor.getValue();
        callback.onKeyguardShowingChanged();

        // Dreaming should hide bubbles
        assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.INVISIBLE);

        // Finish dreaming should show bubbles
        mNotificationShadeWindowController.setDreaming(false);
        when(mIDreamManager.isDreamingOrInPreview()).thenReturn(false); // dreaming finished

        // Dreaming updates come through mNotificationShadeWindowController
        mNotificationShadeWindowController.notifyStateChangedCallbacks();

        assertThat(mBubbleController.getStackView().getVisibility()).isEqualTo(View.VISIBLE);
    }

    @Test