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

Commit 6e98adea authored by Nicolò Mazzucato's avatar Nicolò Mazzucato Committed by Android (Google) Code Review
Browse files

Merge "Dismiss dialogs when shade moves between displays" into main

parents 08d5c041 1ef684a3
Loading
Loading
Loading
Loading
+63 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.systemui.shade.domain.interactor

import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.statusbar.phone.systemUIDialogManager
import com.android.systemui.testKosmos
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.eq
import org.mockito.kotlin.verify

@RunWith(AndroidJUnit4::class)
@SmallTest
@EnableFlags(ShadeWindowGoesAround.FLAG_NAME)
class ShadeDisplayDialogInteractorTest : SysuiTestCase() {
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val dialogManager: SystemUIDialogManager = kosmos.systemUIDialogManager
    private val shadeDisplaysRepository = kosmos.fakeShadeDisplaysRepository

    private val underTest = kosmos.shadeDisplayDialogInteractor

    @Before
    fun setup() {
        underTest.start()
    }

    @Test
    fun displayIdChanges_previousOneDismissed() =
        kosmos.testScope.runTest {
            shadeDisplaysRepository.setPendingDisplayId(0)
            shadeDisplaysRepository.setPendingDisplayId(1)

            verify(dialogManager).dismissDialogsForDisplayId(eq(0))

            shadeDisplaysRepository.setPendingDisplayId(2)

            verify(dialogManager).dismissDialogsForDisplayId(eq(1))
        }
}
+14 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl
import com.android.systemui.shade.display.ShadeDisplayPolicyModule
import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractor
import com.android.systemui.shade.domain.interactor.ShadeDialogContextInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeDisplaysDialogInteractor
import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.statusbar.notification.stack.NotificationStackRebindingHider
@@ -306,6 +307,19 @@ object ShadeDisplayAwareModule {
            systraceTrackName = trackGroup("shade", logBufferName),
        )
    }

    @Provides
    @IntoMap
    @ClassKey(ShadeDisplaysDialogInteractor::class)
    fun provideShadeDisplayDialogInteractor(
        impl: Provider<ShadeDisplaysDialogInteractor>
    ): CoreStartable {
        return if (ShadeWindowGoesAround.isEnabled) {
            impl.get()
        } else {
            CoreStartable.NOP
        }
    }
}

/** Module that should be included only if the shade window [WindowRootView] is available. */
+51 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.shade.domain.interactor

import com.android.app.tracing.coroutines.launchTraced
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.statusbar.phone.SystemUIDialogManager
import com.android.systemui.util.kotlin.pairwise
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope

/**
 * Dismisses dialogs from the previous display when the shade moves.
 *
 * This is needed as dialogs don't receive configuration changes and therefore can't handle the
 * shade display change gracefully. Now, every time the shade moves away from a display, we're
 * dismissing all dialogs from that display.
 */
@SysUISingleton
class ShadeDisplaysDialogInteractor
@Inject
constructor(
    private val dialogManager: SystemUIDialogManager,
    private val shadeDisplaysRepository: ShadeDisplaysRepository,
    @Background private val coroutineScope: CoroutineScope,
) : CoreStartable {
    override fun start() {
        coroutineScope.launchTraced("ShadeDisplayDialogInteractor") {
            shadeDisplaysRepository.pendingDisplayId.pairwise().collect { (previousDisplayId, _) ->
                dialogManager.dismissDialogsForDisplayId(previousDisplayId)
            }
        }
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -80,6 +80,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
    public static final boolean DEFAULT_DISMISS_ON_DEVICE_LOCK = true;

    private final Context mContext;
    private final DialogTransitionAnimator mDialogTransitionAnimator;
    private final DialogDelegate<SystemUIDialog> mDelegate;
    @Nullable
    private final DismissReceiver mDismissReceiver;
@@ -259,6 +260,7 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
            boolean shouldAcsdDismissDialog) {
        super(context, theme);
        mContext = context;
        mDialogTransitionAnimator = dialogTransitionAnimator;
        mDelegate = delegate;

        applyFlags(this);
@@ -490,6 +492,12 @@ public class SystemUIDialog extends AlertDialog implements ViewRootImpl.ConfigCh
        }
    }

    /** Dismisses the dialog without animation. */
    public void dismissWithoutAnimation() {
        mDialogTransitionAnimator.disableAllCurrentDialogsExitAnimations();
        dismiss();
    }

    public static void setShowForAllUsers(Dialog dialog, boolean show) {
        if (show) {
            dialog.getWindow().getAttributes().privateFlags |=
+8 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.statusbar.phone;


import androidx.annotation.NonNull;

import com.android.keyguard.KeyguardViewController;
@@ -58,6 +59,13 @@ public class SystemUIDialogManager implements Dumpable {
        return !mDialogsShowing.isEmpty();
    }

    /** Dismisses all dialogs on a specific display. */
    public void dismissDialogsForDisplayId(int displayId) {
        mDialogsShowing.stream().filter(
                dialog -> dialog.getContext().getDisplayId() == displayId).forEach(
                SystemUIDialog::dismissWithoutAnimation);
    }

    /**
     * Register a listener to receive callbacks.
     */
Loading