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

Commit ed43b148 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce StatusBarContentInsetsProviderStore for multiple displays" into main

parents ba79f603 613c82b4
Loading
Loading
Loading
Loading
+11 −7
Original line number Original line Diff line number Diff line
@@ -6,12 +6,11 @@ import android.graphics.Rect
import android.view.DisplayCutout
import android.view.DisplayCutout
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.filters.SmallTest
import com.android.systemui.res.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.SysuiTestCase
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.res.R
import com.android.systemui.util.mockito.mock
import com.android.systemui.statusbar.data.repository.fakeStatusBarContentInsetsProviderStore
import com.android.systemui.util.mockito.whenever
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Before
import org.junit.Rule
import org.junit.Rule
@@ -19,6 +18,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever


@SmallTest
@SmallTest
@RunWith(AndroidJUnit4::class)
@RunWith(AndroidJUnit4::class)
@@ -35,9 +36,12 @@ class QsBatteryModeControllerTest : SysuiTestCase() {
        const val QS_END_FRAME = 58
        const val QS_END_FRAME = 58
    }
    }


    private val kosmos = testKosmos()
    private val insetsProviderStore = kosmos.fakeStatusBarContentInsetsProviderStore
    private val insetsProvider = insetsProviderStore.defaultDisplay

    @JvmField @Rule val mockitoRule = MockitoJUnit.rule()!!
    @JvmField @Rule val mockitoRule = MockitoJUnit.rule()!!


    @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider
    @Mock private lateinit var mockedContext: Context
    @Mock private lateinit var mockedContext: Context
    @Mock private lateinit var mockedResources: Resources
    @Mock private lateinit var mockedResources: Resources


@@ -49,8 +53,7 @@ class QsBatteryModeControllerTest : SysuiTestCase() {
        whenever(mockedResources.getInteger(R.integer.fade_in_start_frame)).thenReturn(QS_END_FRAME)
        whenever(mockedResources.getInteger(R.integer.fade_in_start_frame)).thenReturn(QS_END_FRAME)
        whenever(mockedResources.getInteger(R.integer.fade_out_complete_frame))
        whenever(mockedResources.getInteger(R.integer.fade_out_complete_frame))
            .thenReturn(QQS_START_FRAME)
            .thenReturn(QQS_START_FRAME)

        controller = QsBatteryModeController(mockedContext, insetsProviderStore)
        controller = QsBatteryModeController(mockedContext, insetsProvider)
    }
    }


    @Test
    @Test
@@ -96,5 +99,6 @@ class QsBatteryModeControllerTest : SysuiTestCase() {
    }
    }


    private fun Int.prevFrameToFraction(): Float = (this - 1) / MOTION_LAYOUT_MAX_FRAME.toFloat()
    private fun Int.prevFrameToFraction(): Float = (this - 1) / MOTION_LAYOUT_MAX_FRAME.toFloat()

    private fun Int.nextFrameToFraction(): Float = (this + 1) / MOTION_LAYOUT_MAX_FRAME.toFloat()
    private fun Int.nextFrameToFraction(): Float = (this + 1) / MOTION_LAYOUT_MAX_FRAME.toFloat()
}
}
+77 −0
Original line number Original line 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.statusbar.data.repository

import android.view.Display.DEFAULT_DISPLAY
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.display.data.repository.displayRepository
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.unconfinedTestDispatcher
import com.android.systemui.testKosmos
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.never
import org.mockito.kotlin.verify

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

    private val kosmos = testKosmos().also { it.testDispatcher = it.unconfinedTestDispatcher }
    private val testScope = kosmos.testScope
    private val fakeDisplayRepository = kosmos.displayRepository
    private val underTest = kosmos.multiDisplayStatusBarContentInsetsProviderStore

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

    @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }

    @Test
    fun forDisplay_startsInstances() =
        testScope.runTest {
            val instance = underTest.forDisplay(DEFAULT_DISPLAY)

            verify(instance).start()
        }

    @Test
    fun beforeDisplayRemoved_doesNotStopInstances() =
        testScope.runTest {
            val instance = underTest.forDisplay(DEFAULT_DISPLAY)

            verify(instance, never()).stop()
        }

    @Test
    fun displayRemoved_stopsInstance() =
        testScope.runTest {
            val instance = underTest.forDisplay(DEFAULT_DISPLAY)

            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)

            verify(instance).stop()
        }
}
+6 −2
Original line number Original line Diff line number Diff line
@@ -63,6 +63,7 @@ import com.android.systemui.res.R;
import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.shade.ShadeViewStateProvider;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.phone.ui.StatusBarIconController;
import com.android.systemui.statusbar.phone.ui.TintedIconManager;
import com.android.systemui.statusbar.phone.ui.TintedIconManager;
@@ -119,6 +120,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
    @Mock
    @Mock
    private StatusBarContentInsetsProvider mStatusBarContentInsetsProvider;
    private StatusBarContentInsetsProvider mStatusBarContentInsetsProvider;
    @Mock
    @Mock
    private StatusBarContentInsetsProviderStore mStatusBarContentInsetsProviderStore;
    @Mock
    private UserManager mUserManager;
    private UserManager mUserManager;
    @Mock
    @Mock
    private StatusBarUserChipViewModel mStatusBarUserChipViewModel;
    private StatusBarUserChipViewModel mStatusBarUserChipViewModel;
@@ -143,7 +146,8 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
        mShadeViewStateProvider = new TestShadeViewStateProvider();
        mShadeViewStateProvider = new TestShadeViewStateProvider();


        MockitoAnnotations.initMocks(this);
        MockitoAnnotations.initMocks(this);

        when(mStatusBarContentInsetsProviderStore.getDefaultDisplay())
                .thenReturn(mStatusBarContentInsetsProvider);
        when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);
        when(mIconManagerFactory.create(any(), any())).thenReturn(mIconManager);


        allowTestableLooperAsMainThread();
        allowTestableLooperAsMainThread();
@@ -175,7 +179,7 @@ public class KeyguardStatusBarViewControllerTest extends SysuiTestCase {
                mKosmos.getKeyguardStatusBarViewModel(),
                mKosmos.getKeyguardStatusBarViewModel(),
                mBiometricUnlockController,
                mBiometricUnlockController,
                mStatusBarStateController,
                mStatusBarStateController,
                mStatusBarContentInsetsProvider,
                mStatusBarContentInsetsProviderStore,
                mUserManager,
                mUserManager,
                mStatusBarUserChipViewModel,
                mStatusBarUserChipViewModel,
                mSecureSettings,
                mSecureSettings,
+104 −14
Original line number Original line Diff line number Diff line
@@ -36,14 +36,15 @@ import com.android.systemui.util.leak.RotationUtils.ROTATION_NONE
import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
import com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE
import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
import com.android.systemui.util.leak.RotationUtils.ROTATION_UPSIDE_DOWN
import com.android.systemui.util.leak.RotationUtils.Rotation
import com.android.systemui.util.leak.RotationUtils.Rotation
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertTrue
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Before
import org.junit.Before
import org.junit.Test
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.any
import org.mockito.ArgumentMatchers.any
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever


@RunWith(AndroidJUnit4::class)
@RunWith(AndroidJUnit4::class)
@SmallTest
@SmallTest
@@ -1018,7 +1019,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {


    // Regression test for b/245799099
    // Regression test for b/245799099
    @Test
    @Test
    fun onMaxBoundsChanged_listenerNotified() {
    fun onMaxBoundsChanged_afterStart_listenerNotified() {
        // Start out with an existing configuration with bounds
        // Start out with an existing configuration with bounds
        configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100)
        configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100)
        configurationController.onConfigurationChanged(configuration)
        configurationController.onConfigurationChanged(configuration)
@@ -1038,6 +1039,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
                    triggered = true
                    triggered = true
                }
                }
            }
            }
        provider.start()
        provider.addCallback(listener)
        provider.addCallback(listener)


        // WHEN the config is updated with new bounds
        // WHEN the config is updated with new bounds
@@ -1049,7 +1051,68 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
    }
    }


    @Test
    @Test
    fun onDensityOrFontScaleChanged_listenerNotified() {
    fun onMaxBoundsChanged_beforeStart_listenerNotNotified() {
        // Start out with an existing configuration with bounds
        configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100)
        configurationController.onConfigurationChanged(configuration)
        val provider =
            StatusBarContentInsetsProviderImpl(
                contextMock,
                configurationController,
                mock<DumpManager>(),
                mock<CommandRegistry>(),
                mock<SysUICutoutProvider>(),
            )
        val listener =
            object : StatusBarContentInsetsChangedListener {
                var triggered = false

                override fun onStatusBarContentInsetsChanged() {
                    triggered = true
                }
            }
        provider.addCallback(listener)

        // WHEN the config is updated with new bounds
        // but provider is not started
        configuration.windowConfiguration.setMaxBounds(0, 0, 456, 789)
        configurationController.onConfigurationChanged(configuration)

        // THEN the listener is not notified
        assertThat(listener.triggered).isFalse()
    }

    @Test
    fun onDensityOrFontScaleChanged_beforeStart_listenerNotNotified() {
        configuration.densityDpi = 12
        val provider =
            StatusBarContentInsetsProviderImpl(
                contextMock,
                configurationController,
                mock<DumpManager>(),
                mock<CommandRegistry>(),
                mock<SysUICutoutProvider>(),
            )
        val listener =
            object : StatusBarContentInsetsChangedListener {
                var triggered = false

                override fun onStatusBarContentInsetsChanged() {
                    triggered = true
                }
            }
        provider.addCallback(listener)

        // WHEN the config is updated, but the provider is not started
        configuration.densityDpi = 20
        configurationController.onConfigurationChanged(configuration)

        // THEN the listener is NOT notified
        assertThat(listener.triggered).isFalse()
    }

    @Test
    fun onDensityOrFontScaleChanged_afterStart_listenerNotified() {
        configuration.densityDpi = 12
        configuration.densityDpi = 12
        val provider =
        val provider =
            StatusBarContentInsetsProviderImpl(
            StatusBarContentInsetsProviderImpl(
@@ -1067,6 +1130,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
                    triggered = true
                    triggered = true
                }
                }
            }
            }
        provider.start()
        provider.addCallback(listener)
        provider.addCallback(listener)


        // WHEN the config is updated
        // WHEN the config is updated
@@ -1078,7 +1142,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
    }
    }


    @Test
    @Test
    fun onThemeChanged_listenerNotified() {
    fun onThemeChanged_afterStart_listenerNotified() {
        val provider =
        val provider =
            StatusBarContentInsetsProviderImpl(
            StatusBarContentInsetsProviderImpl(
                contextMock,
                contextMock,
@@ -1095,6 +1159,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
                    triggered = true
                    triggered = true
                }
                }
            }
            }
        provider.start()
        provider.addCallback(listener)
        provider.addCallback(listener)


        configurationController.notifyThemeChanged()
        configurationController.notifyThemeChanged()
@@ -1103,18 +1168,44 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
        assertThat(listener.triggered).isTrue()
        assertThat(listener.triggered).isTrue()
    }
    }


    @Test
    fun onThemeChanged_beforeStart_listenerNotNotified() {
        val provider =
            StatusBarContentInsetsProviderImpl(
                contextMock,
                configurationController,
                mock<DumpManager>(),
                mock<CommandRegistry>(),
                mock<SysUICutoutProvider>(),
            )
        val listener =
            object : StatusBarContentInsetsChangedListener {
                var triggered = false

                override fun onStatusBarContentInsetsChanged() {
                    triggered = true
                }
            }
        provider.addCallback(listener)

        configurationController.notifyThemeChanged()

        assertThat(listener.triggered).isFalse()
    }

    private fun assertRects(
    private fun assertRects(
        expected: Rect,
        expected: Rect,
        actual: Rect,
        actual: Rect,
        @Rotation currentRotation: Int,
        @Rotation currentRotation: Int,
        @Rotation targetRotation: Int,
        @Rotation targetRotation: Int,
    ) {
    ) {
        assertTrue(
        assertWithMessage(
                "Rects must match. currentRotation=${RotationUtils.toString(currentRotation)}" +
                "Rects must match. currentRotation=${RotationUtils.toString(currentRotation)}" +
                    " targetRotation=${RotationUtils.toString(targetRotation)}" +
                    " targetRotation=${RotationUtils.toString(targetRotation)}" +
                " expected=$expected actual=$actual",
                    " expected=$expected actual=$actual"
            expected.equals(actual),
            )
            )
            .that(actual)
            .isEqualTo(expected)
    }
    }


    private fun setNoCutout() {
    private fun setNoCutout() {
@@ -1136,8 +1227,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
    }
    }


    private fun setCameraProtectionBounds(protectionBounds: Rect) {
    private fun setCameraProtectionBounds(protectionBounds: Rect) {
        val protectionInfo =
        val protectionInfo = mock<CameraProtectionInfo> { on { bounds } doReturn protectionBounds }
            mock<CameraProtectionInfo> { whenever(this.bounds).thenReturn(protectionBounds) }
        whenever(sysUICutout.cameraProtection).thenReturn(protectionInfo)
        whenever(sysUICutout.cameraProtection).thenReturn(protectionInfo)
    }
    }


+1 −1
Original line number Original line Diff line number Diff line
@@ -76,7 +76,7 @@ abstract class PerDisplayStoreImpl<T>(
        }
        }
    }
    }


    abstract fun createInstanceForDisplay(displayId: Int): T
    protected abstract fun createInstanceForDisplay(displayId: Int): T


    override fun start() {
    override fun start() {
        val instanceType = instanceClass.simpleName
        val instanceType = instanceClass.simpleName
Loading