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

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

Merge "Hide NSSL while notification rebinding is in progress after display change" into main

parents ecd7824f 988f6831
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import org.mockito.kotlin.clearInvocations

@ExperimentalCoroutinesApi
@SmallTest
@@ -65,11 +66,13 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() {
                testScope.backgroundScope,
                displayUtils,
            )
        testScope.runCurrent()
    }

    @Test
    fun onAnyConfigurationChange_updatesOnUiModeChanged() =
        testScope.runTest {
            clearInvocations(configurationController)
            val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange)
            assertThat(lastAnyConfigurationChange).isNull()

@@ -85,6 +88,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() {
    @Test
    fun onAnyConfigurationChange_updatesOnThemeChanged() =
        testScope.runTest {
            clearInvocations(configurationController)
            val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange)
            assertThat(lastAnyConfigurationChange).isNull()

@@ -101,7 +105,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() {
    fun onMovedToDisplays_updatesOnMovedToDisplay() =
        testScope.runTest {
            val lastOnMovedToDisplay by collectLastValue(underTest.onMovedToDisplay)
            assertThat(lastOnMovedToDisplay).isNull()
            assertThat(lastOnMovedToDisplay).isEqualTo(Display.DEFAULT_DISPLAY)

            val configurationCallback = withArgCaptor {
                verify(configurationController).addCallback(capture())
@@ -115,6 +119,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() {
    @Test
    fun onAnyConfigurationChange_updatesOnConfigChanged() =
        testScope.runTest {
            clearInvocations(configurationController)
            val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange)
            assertThat(lastAnyConfigurationChange).isNull()

@@ -130,6 +135,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() {
    @Test
    fun onResolutionScale_updatesOnConfigurationChange() =
        testScope.runTest {
            clearInvocations(configurationController)
            val scaleForResolution by collectLastValue(underTest.scaleForResolution)
            assertThat(scaleForResolution).isEqualTo(displaySizeRatio)

@@ -149,6 +155,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() {
    @Test
    fun onResolutionScale_nullMaxResolution() =
        testScope.runTest {
            clearInvocations(configurationController)
            val scaleForResolution by collectLastValue(underTest.scaleForResolution)
            runCurrent()

@@ -203,7 +210,7 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() {
                    anyInt(),
                    anyInt(),
                    anyInt(),
                    anyInt()
                    anyInt(),
                )
            )
            .thenReturn(ratio)
+2 −3
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ import com.android.systemui.scene.data.repository.WindowRootViewVisibilityReposi
import com.android.systemui.statusbar.NotificationPresenter
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
import com.android.systemui.statusbar.notification.init.NotificationsController
import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
@@ -70,8 +70,7 @@ class WindowRootViewVisibilityInteractorTest : SysuiTestCase() {
    private val notificationsController = mock<NotificationsController>()
    private val powerInteractor = PowerInteractorFactory.create().powerInteractor
    private val activeNotificationsRepository = kosmos.activeNotificationListRepository
    private val activeNotificationsInteractor =
        ActiveNotificationsInteractor(activeNotificationsRepository, testDispatcher)
    private val activeNotificationsInteractor = kosmos.activeNotificationsInteractor

    private val underTest =
        WindowRootViewVisibilityInteractor(
+99 −15
Original line number Diff line number Diff line
@@ -22,17 +22,24 @@ import android.view.Display
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.configurationRepository
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.scene.ui.view.mockShadeRootView
import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
import com.android.systemui.statusbar.notification.row.notificationRebindingTracker
import com.android.systemui.statusbar.notification.stack.notificationStackRebindingHider
import com.android.systemui.testKosmos
import kotlinx.coroutines.test.advanceUntilIdle
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.never
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
@@ -42,7 +49,7 @@ import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
@SmallTest
class ShadeDisplaysInteractorTest : SysuiTestCase() {
    val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val kosmos = testKosmos().useUnconfinedTestDispatcher()

    private val testScope = kosmos.testScope
    private val shadeRootview = kosmos.mockShadeRootView
@@ -52,6 +59,10 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
    private val latencyTracker = kosmos.mockedShadeDisplayChangeLatencyTracker
    private val configuration = mock<Configuration>()
    private val display = mock<Display>()
    private val activeNotificationRepository = kosmos.activeNotificationListRepository
    private val notificationRebindingTracker = kosmos.notificationRebindingTracker
    private val notificationStackRebindingHider = kosmos.notificationStackRebindingHider
    private val configurationRepository = kosmos.fakeConfigurationRepository

    private val underTest by lazy { kosmos.shadeDisplaysInteractor }

@@ -68,7 +79,8 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
    }

    @Test
    fun start_shadeInCorrectPosition_notAddedOrRemoved() {
    fun start_shadeInCorrectPosition_notAddedOrRemoved() =
        testScope.runTest {
            whenever(display.displayId).thenReturn(0)
            positionRepository.setDisplayId(0)

@@ -78,7 +90,8 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
        }

    @Test
    fun start_shadeInWrongPosition_changes() {
    fun start_shadeInWrongPosition_changes() =
        testScope.runTest {
            whenever(display.displayId).thenReturn(0)
            positionRepository.setDisplayId(1)

@@ -94,8 +107,79 @@ class ShadeDisplaysInteractorTest : SysuiTestCase() {
            positionRepository.setDisplayId(1)

            underTest.start()
            advanceUntilIdle()

            verify(latencyTracker).onShadeDisplayChanging(eq(1))
        }

    @Test
    fun start_shadeInWrongPosition_someNotificationsVisible_hiddenThenShown() =
        testScope.runTest {
            whenever(display.displayId).thenReturn(0)
            positionRepository.setDisplayId(1)
            activeNotificationRepository.setActiveNotifs(1)

            underTest.start()

            verify(notificationStackRebindingHider).setVisible(eq(false), eq(false))
            configurationRepository.onMovedToDisplay(1)
            verify(notificationStackRebindingHider).setVisible(eq(true), eq(true))
        }

    @Test
    fun start_shadeInWrongPosition_someNotificationsVisible_waitsForInflationsBeforeShowingNssl() =
        testScope.runTest {
            whenever(display.displayId).thenReturn(0)
            positionRepository.setDisplayId(1)
            activeNotificationRepository.setActiveNotifs(1)

            val endRebinding = notificationRebindingTracker.trackRebinding("test")

            assertThat(notificationRebindingTracker.rebindingInProgressCount.value).isEqualTo(1)

            underTest.start()

            verify(notificationStackRebindingHider).setVisible(eq(false), eq(false))
            configurationRepository.onMovedToDisplay(1)

            // Verify that setVisible(true, true) is NOT called yet, as we
            // first need to wait for notification bindings to have happened
            verify(notificationStackRebindingHider, never()).setVisible(eq(true), eq(true))

            endRebinding.onFinished()

            // Now verify that setVisible(true, true) is called
            verify(notificationStackRebindingHider, times(1)).setVisible(eq(true), eq(true))
        }

    @Test
    fun start_shadeInWrongPosition_noNotifications_nsslNotHidden() =
        testScope.runTest {
            whenever(display.displayId).thenReturn(0)
            positionRepository.setDisplayId(1)
            activeNotificationRepository.setActiveNotifs(0)

            underTest.start()

            verify(notificationStackRebindingHider, never()).setVisible(eq(false), eq(false))
            verify(notificationStackRebindingHider, never()).setVisible(eq(true), eq(true))
        }

    @Test
    fun start_shadeInWrongPosition_waitsUntilMovedToDisplayReceived() =
        testScope.runTest {
            whenever(display.displayId).thenReturn(0)
            positionRepository.setDisplayId(1)
            activeNotificationRepository.setActiveNotifs(1)

            underTest.start()

            verify(notificationStackRebindingHider).setVisible(eq(false), eq(false))
            // It's not set to visible yet, as we first need to wait for the view to receive the
            // display moved callback.
            verify(notificationStackRebindingHider, never()).setVisible(eq(true), eq(true))

            configurationRepository.onMovedToDisplay(1)

            verify(notificationStackRebindingHider).setVisible(eq(true), eq(true))
        }
}
+2 −0
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
    private val statusBarService: IStatusBarService = mock()
    private val uiEventLogger: UiEventLogger = mock()
    private val msdlPlayer: MSDLPlayer = mock()
    private val rebindingTracker: NotificationRebindingTracker = mock()
    private lateinit var controller: ExpandableNotificationRowController

    @Before
@@ -150,6 +151,7 @@ class ExpandableNotificationRowControllerTest : SysuiTestCase() {
                statusBarService,
                uiEventLogger,
                msdlPlayer,
                rebindingTracker,
            )
        whenever(view.childrenContainer).thenReturn(childrenContainer)

+114 −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.statusbar.notification.row

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.data.repository.setActiveNotifs
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.test.Test
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class NotificationRebindingTrackerTest : SysuiTestCase() {

    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
    private val testScope = kosmos.testScope
    private val activeNotificationRepository = kosmos.activeNotificationListRepository

    private val underTest: NotificationRebindingTracker = kosmos.notificationRebindingTracker

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

    @Test
    fun rebindingInProgressCount_noneStarted_isZero() =
        testScope.runTest {
            val count by collectLastValue(underTest.rebindingInProgressCount)

            assertThat(count).isEqualTo(0)
        }

    @Test
    fun rebindingInProgressCount_oneStarted_isOne() =
        testScope.runTest {
            val count by collectLastValue(underTest.rebindingInProgressCount)
            activeNotificationRepository.setActiveNotifs(1)

            underTest.trackRebinding("0")

            assertThat(count).isEqualTo(1)
        }

    @Test
    fun rebindingInProgressCount_oneStartedThenFinished_goesFromOneToZero() =
        testScope.runTest {
            val count by collectLastValue(underTest.rebindingInProgressCount)
            activeNotificationRepository.setActiveNotifs(1)

            val endRebinding = underTest.trackRebinding("0")

            assertThat(count).isEqualTo(1)

            endRebinding.onFinished()

            assertThat(count).isEqualTo(0)
        }

    @Test
    fun rebindingInProgressCount_twoStarted_goesToTwo() =
        testScope.runTest {
            val count by collectLastValue(underTest.rebindingInProgressCount)
            activeNotificationRepository.setActiveNotifs(2)

            underTest.trackRebinding("0")
            underTest.trackRebinding("1")

            assertThat(count).isEqualTo(2)
        }

    @Test
    fun rebindingInProgressCount_twoStarted_oneNotActiveAnymore_goesToZero() =
        testScope.runTest {
            val count by collectLastValue(underTest.rebindingInProgressCount)
            activeNotificationRepository.setActiveNotifs(2)

            val finishFirstRebinding = underTest.trackRebinding("0")
            underTest.trackRebinding("1")

            assertThat(count).isEqualTo(2)

            activeNotificationRepository.setActiveNotifs(1)

            assertThat(count).isEqualTo(1)

            finishFirstRebinding.onFinished()

            assertThat(count).isEqualTo(0)
        }
}
Loading