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

Commit c59a827e authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Cancel toasts when display mirroring starts

When display mirroring starts, all windows on the mirroring display must
be removed. Otherwise, SurfaceFlinger will not initiate mirroring.

Previously, if a toast was on the mirroring display, it prevented
mirroring from starting and remained visible.

This change updates DisplayPolicy to cancel toasts when mirroring
begins.

Bug: 389833251
Test: DisplayWindowSettingsTests
Test: NotificationManagerServiceTest
Flag: com.android.server.display.feature.flags.enable_display_content_mode_management
Change-Id: If54418a0526b7b6c8f00e972bc0b39e362d6d7df
parent 12bd0c83
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -82,4 +82,11 @@ public interface NotificationManagerInternal {
    byte[] getBackupPayload(int user, BackupRestoreEventLogger logger);

    void applyRestore(byte[] payload, int user, BackupRestoreEventLogger logger);

    /**
     * Notifies NotificationManager that the system decorations should be removed from the display.
     *
     * @param displayId display ID
     */
    void onDisplayRemoveSystemDecorations(int displayId);
}
+12 −0
Original line number Diff line number Diff line
@@ -8197,6 +8197,18 @@ public class NotificationManagerService extends SystemService {
            // This can also throw IllegalStateException if called too late.
            mZenModeHelper.setDeviceEffectsApplier(applier);
        }
        @Override
        public void onDisplayRemoveSystemDecorations(int displayId) {
            synchronized (mToastQueue) {
                for (int i = mToastQueue.size() - 1; i >= 0; i--) {
                    final ToastRecord toast = mToastQueue.get(i);
                    if (toast.displayId == displayId) {
                        cancelToastLocked(i);
                    }
                }
            }
        }
    };
    private static boolean isBigPictureWithBitmapOrIcon(Notification n) {
+6 −0
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@ import com.android.internal.view.AppearanceRegion;
import com.android.internal.widget.PointerLocationView;
import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.notification.NotificationManagerInternal;
import com.android.server.policy.WindowManagerPolicy.ScreenOnListener;
import com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -1925,6 +1926,11 @@ public class DisplayPolicy {
                    if (wpMgr != null) {
                        wpMgr.onDisplayRemoveSystemDecorations(displayId);
                    }
                    final NotificationManagerInternal notificationManager =
                            LocalServices.getService(NotificationManagerInternal.class);
                    if (notificationManager != null) {
                        notificationManager.onDisplayRemoveSystemDecorations(displayId);
                    }
                });
    }

+33 −0
Original line number Diff line number Diff line
@@ -18657,4 +18657,37 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        verify(mGroupHelper).onNotificationRemoved(eq(n), any(), eq(false));
    }
    @Test
    public void onDisplayRemoveSystemDecorations_cancelToasts() throws RemoteException {
        final String testPackage = "testPackageName";
        final INotificationManager service = ((INotificationManager) mService.mService);
        final IBinder firstExternal = new Binder();
        final IBinder secondExternal = new Binder();
        final IBinder firstBuiltin = new Binder();
        service.enqueueTextToast(testPackage,
                firstExternal, "First external", TOAST_DURATION,
                /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null);
        service.enqueueTextToast(testPackage,
                secondExternal, "Second external", TOAST_DURATION,
                /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null);
        service.enqueueTextToast(testPackage,
                firstBuiltin, "First built-in", TOAST_DURATION, /* isUiContext= */ true,
                /* displayId= */ DEFAULT_DISPLAY, /* callback= */ null);
        mInternalService.onDisplayRemoveSystemDecorations(10);
        verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstExternal),
                any(String.class), any(IBinder.class), anyInt(), any(), eq(10));
        verify(mStatusBar).hideToast(eq(testPackage), eq(firstExternal));
        // The second toast has not been shown but invokes hide() anyway as
        // NotificationManagerService does not remembered if it invoked show().
        verify(mStatusBar, never()).showToast(anyInt(), eq(testPackage), eq(secondExternal),
                any(String.class), any(IBinder.class), anyInt(), any(), eq(10));
        verify(mStatusBar).hideToast(eq(testPackage), eq(secondExternal));
        // The toast on the default display is shown as other notifications are cancelled.
        verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstBuiltin), any(String.class),
                any(IBinder.class), anyInt(), any(), eq(DEFAULT_DISPLAY));
        verify(mStatusBar, never()).hideToast(eq(testPackage), eq(firstBuiltin));
    }
}
+27 −0
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ import android.view.Surface;
import androidx.test.filters.SmallTest;

import com.android.server.LocalServices;
import com.android.server.UiThread;
import com.android.server.notification.NotificationManagerInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.wm.DisplayWindowSettings.SettingsProvider.SettingsEntry;
import com.android.window.flags.Flags;
@@ -59,6 +61,7 @@ import com.android.window.flags.Flags;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;

import java.util.HashMap;
import java.util.Map;
@@ -386,6 +389,30 @@ public class DisplayWindowSettingsTests extends WindowTestsBase {
        assertFalse(mDisplayWindowSettings.shouldShowSystemDecorsLocked(mSecondaryDisplay));
    }

    @Test
    @EnableFlags(com.android.server.display.feature.flags.Flags
            .FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT)
    public void testSetShouldShowSystemDecorsNotifyNotificationManager() {
        final NotificationManagerInternal notificationManager = Mockito.mock(
                NotificationManagerInternal.class);
        LocalServices.addService(NotificationManagerInternal.class, notificationManager);
        try {
            // First show the decoration because setting false is noop if the decoration has already
            // been hidden.
            mDisplayWindowSettings.setShouldShowSystemDecorsLocked(
                    mSecondaryDisplay, /* shouldShow= */ true);

            mDisplayWindowSettings.setShouldShowSystemDecorsLocked(
                    mSecondaryDisplay, /* shouldShow= */ false);

            waitHandlerIdle(UiThread.getHandler());
            Mockito.verify(notificationManager).onDisplayRemoveSystemDecorations(
                    mSecondaryDisplay.mDisplayId);
        } finally {
            LocalServices.removeServiceForTest(NotificationManagerInternal.class);
        }
    }

    @Test
    public void testPrimaryDisplayImePolicy() {
        assertEquals(DISPLAY_IME_POLICY_LOCAL,