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

Commit f349e41a authored by Caitlin Shkuratov's avatar Caitlin Shkuratov Committed by Automerger Merge Worker
Browse files

Merge changes I4e2c4584,I81919822,Ic3968b89 into tm-qpr-dev am: ec9b150a am: 7ba14e36

parents 416c6379 7ba14e36
Loading
Loading
Loading
Loading
+7 −2
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@ class ConfigurationControllerImpl @Inject constructor(context: Context) : Config
    private val lastConfig = Configuration()
    private var density: Int = 0
    private var smallestScreenWidth: Int = 0
    private var maxBounds: Rect? = null
    private var maxBounds = Rect()
    private var fontScale: Float = 0.toFloat()
    private val inCarMode: Boolean
    private var uiMode: Int = 0
@@ -47,6 +47,7 @@ class ConfigurationControllerImpl @Inject constructor(context: Context) : Config
        fontScale = currentConfig.fontScale
        density = currentConfig.densityDpi
        smallestScreenWidth = currentConfig.smallestScreenWidthDp
        maxBounds.set(currentConfig.windowConfiguration.maxBounds)
        inCarMode = currentConfig.uiMode and Configuration.UI_MODE_TYPE_MASK ==
                Configuration.UI_MODE_TYPE_CAR
        uiMode = currentConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK
@@ -92,7 +93,11 @@ class ConfigurationControllerImpl @Inject constructor(context: Context) : Config

        val maxBounds = newConfig.windowConfiguration.maxBounds
        if (maxBounds != this.maxBounds) {
            this.maxBounds = maxBounds
            // Update our internal rect to have the same bounds, instead of using
            // `this.maxBounds = maxBounds` directly. Setting it directly means that `maxBounds`
            // would be a direct reference to windowConfiguration.maxBounds, so the if statement
            // above would always fail. See b/245799099 for more information.
            this.maxBounds.set(maxBounds)
            listeners.filterForEach({ this.listeners.contains(it) }) {
                it.onMaxBoundsChanged()
            }
+316 −3
Original line number Diff line number Diff line
@@ -14,23 +14,37 @@

package com.android.systemui.statusbar.phone

import androidx.test.filters.SmallTest
import android.content.res.Configuration
import android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_LTR
import android.content.res.Configuration.SCREENLAYOUT_LAYOUTDIR_RTL
import android.content.res.Configuration.UI_MODE_NIGHT_NO
import android.content.res.Configuration.UI_MODE_NIGHT_YES
import android.content.res.Configuration.UI_MODE_TYPE_CAR
import android.os.LocaleList
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import java.util.Locale

@RunWith(AndroidTestingRunner::class)
@SmallTest
class ConfigurationControllerImplTest : SysuiTestCase() {

    private val mConfigurationController =
            com.android.systemui.statusbar.phone.ConfigurationControllerImpl(mContext)
    private lateinit var mConfigurationController: ConfigurationControllerImpl

    @Before
    fun setUp() {
        mConfigurationController = ConfigurationControllerImpl(mContext)
    }

    @Test
    fun testThemeChange() {
@@ -57,4 +71,303 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
        verify(listener).onThemeChanged()
        verify(listener2, never()).onThemeChanged()
    }

    @Test
    fun configChanged_listenerNotified() {
        val config = mContext.resources.configuration
        config.densityDpi = 12
        config.smallestScreenWidthDp = 240
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the config is updated
        config.densityDpi = 20
        config.smallestScreenWidthDp = 300
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.changedConfig?.densityDpi).isEqualTo(20)
        assertThat(listener.changedConfig?.smallestScreenWidthDp).isEqualTo(300)
    }

    @Test
    fun densityChanged_listenerNotified() {
        val config = mContext.resources.configuration
        config.densityDpi = 12
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the density is updated
        config.densityDpi = 20
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.densityOrFontScaleChanged).isTrue()
    }

    @Test
    fun fontChanged_listenerNotified() {
        val config = mContext.resources.configuration
        config.fontScale = 1.5f
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the font is updated
        config.fontScale = 1.4f
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.densityOrFontScaleChanged).isTrue()
    }

    @Test
    fun isCarAndUiModeChanged_densityListenerNotified() {
        val config = mContext.resources.configuration
        config.uiMode = UI_MODE_TYPE_CAR or UI_MODE_NIGHT_YES
        // Re-create the controller since we calculate car mode on creation
        mConfigurationController = ConfigurationControllerImpl(mContext)

        val listener = createAndAddListener()

        // WHEN the ui mode is updated
        config.uiMode = UI_MODE_TYPE_CAR or UI_MODE_NIGHT_NO
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.densityOrFontScaleChanged).isTrue()
    }

    @Test
    fun isNotCarAndUiModeChanged_densityListenerNotNotified() {
        val config = mContext.resources.configuration
        config.uiMode = UI_MODE_NIGHT_YES
        // Re-create the controller since we calculate car mode on creation
        mConfigurationController = ConfigurationControllerImpl(mContext)

        val listener = createAndAddListener()

        // WHEN the ui mode is updated
        config.uiMode = UI_MODE_NIGHT_NO
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is not notified because it's not car mode
        assertThat(listener.densityOrFontScaleChanged).isFalse()
    }

    @Test
    fun smallestScreenWidthChanged_listenerNotified() {
        val config = mContext.resources.configuration
        config.smallestScreenWidthDp = 240
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the width is updated
        config.smallestScreenWidthDp = 300
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.smallestScreenWidthChanged).isTrue()
    }

    @Test
    fun maxBoundsChange_newConfigObject_listenerNotified() {
        val config = mContext.resources.configuration
        config.windowConfiguration.setMaxBounds(0, 0, 200, 200)
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN a new configuration object with new bounds is sent
        val newConfig = Configuration()
        newConfig.windowConfiguration.setMaxBounds(0, 0, 100, 100)
        mConfigurationController.onConfigurationChanged(newConfig)

        // THEN the listener is notified
        assertThat(listener.maxBoundsChanged).isTrue()
    }

    // Regression test for b/245799099
    @Test
    fun maxBoundsChange_sameObject_listenerNotified() {
        val config = mContext.resources.configuration
        config.windowConfiguration.setMaxBounds(0, 0, 200, 200)
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the existing config is updated with new bounds
        config.windowConfiguration.setMaxBounds(0, 0, 100, 100)
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.maxBoundsChanged).isTrue()
    }


    @Test
    fun localeListChanged_listenerNotified() {
        val config = mContext.resources.configuration
        config.locales = LocaleList(Locale.CANADA, Locale.GERMANY)
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the locales are updated
        config.locales = LocaleList(Locale.FRANCE, Locale.JAPAN, Locale.CHINESE)
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.localeListChanged).isTrue()
    }

    @Test
    fun uiModeChanged_listenerNotified() {
        val config = mContext.resources.configuration
        config.uiMode = UI_MODE_NIGHT_YES
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the ui mode is updated
        config.uiMode = UI_MODE_NIGHT_NO
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.uiModeChanged).isTrue()
    }

    @Test
    fun layoutDirectionUpdated_listenerNotified() {
        val config = mContext.resources.configuration
        config.screenLayout = SCREENLAYOUT_LAYOUTDIR_LTR
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the layout is updated
        config.screenLayout = SCREENLAYOUT_LAYOUTDIR_RTL
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.layoutDirectionChanged).isTrue()
    }

    @Test
    fun assetPathsUpdated_listenerNotified() {
        val config = mContext.resources.configuration
        config.assetsSeq = 45
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN the assets sequence is updated
        config.assetsSeq = 46
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified
        assertThat(listener.themeChanged).isTrue()
    }

    @Test
    fun multipleUpdates_listenerNotifiedOfAll() {
        val config = mContext.resources.configuration
        config.densityDpi = 14
        config.windowConfiguration.setMaxBounds(0, 0, 2, 2)
        config.uiMode = UI_MODE_NIGHT_YES
        mConfigurationController.onConfigurationChanged(config)

        val listener = createAndAddListener()

        // WHEN multiple fields are updated
        config.densityDpi = 20
        config.windowConfiguration.setMaxBounds(0, 0, 3, 3)
        config.uiMode = UI_MODE_NIGHT_NO
        mConfigurationController.onConfigurationChanged(config)

        // THEN the listener is notified of all of them
        assertThat(listener.densityOrFontScaleChanged).isTrue()
        assertThat(listener.maxBoundsChanged).isTrue()
        assertThat(listener.uiModeChanged).isTrue()
    }

    @Test
    fun equivalentConfigObject_listenerNotNotified() {
        val config = mContext.resources.configuration
        val listener = createAndAddListener()

        // WHEN we update with the new object that has all the same fields
        mConfigurationController.onConfigurationChanged(Configuration(config))

        listener.assertNoMethodsCalled()
    }

    private fun createAndAddListener(): TestListener {
        val listener = TestListener()
        mConfigurationController.addCallback(listener)
        // Adding a listener can trigger some callbacks, so we want to reset the values right
        // after the listener is added
        listener.reset()
        return listener
    }

    private class TestListener : ConfigurationListener {
        var changedConfig: Configuration? = null
        var densityOrFontScaleChanged = false
        var smallestScreenWidthChanged = false
        var maxBoundsChanged = false
        var uiModeChanged = false
        var themeChanged = false
        var localeListChanged = false
        var layoutDirectionChanged = false

        override fun onConfigChanged(newConfig: Configuration?) {
            changedConfig = newConfig
        }
        override fun onDensityOrFontScaleChanged() {
            densityOrFontScaleChanged = true
        }
        override fun onSmallestScreenWidthChanged() {
            smallestScreenWidthChanged = true
        }
        override fun onMaxBoundsChanged() {
            maxBoundsChanged = true
        }
        override fun onUiModeChanged() {
            uiModeChanged = true
        }
        override fun onThemeChanged() {
            themeChanged = true
        }
        override fun onLocaleListChanged() {
            localeListChanged = true
        }
        override fun onLayoutDirectionChanged(isLayoutRtl: Boolean) {
            layoutDirectionChanged = true
        }

        fun assertNoMethodsCalled() {
            assertThat(densityOrFontScaleChanged).isFalse()
            assertThat(smallestScreenWidthChanged).isFalse()
            assertThat(maxBoundsChanged).isFalse()
            assertThat(uiModeChanged).isFalse()
            assertThat(themeChanged).isFalse()
            assertThat(localeListChanged).isFalse()
            assertThat(layoutDirectionChanged).isFalse()
        }

        fun reset() {
            changedConfig = null
            densityOrFontScaleChanged = false
            smallestScreenWidthChanged = false
            maxBoundsChanged = false
            uiModeChanged = false
            themeChanged = false
            localeListChanged = false
            layoutDirectionChanged = false
        }
    }
}
+74 −27
Original line number Diff line number Diff line
@@ -19,9 +19,9 @@ package com.android.systemui.statusbar.phone
import android.content.Context
import android.content.res.Configuration
import android.graphics.Rect
import android.test.suitebuilder.annotation.SmallTest
import android.view.Display
import android.view.DisplayCutout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -463,16 +463,10 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
        val provider = StatusBarContentInsetsProvider(contextMock, configurationController,
            mock(DumpManager::class.java))

        givenDisplay(
            screenBounds = Rect(0, 0, 1080, 2160),
            displayUniqueId = "1"
        )
        configuration.windowConfiguration.maxBounds = Rect(0, 0, 1080, 2160)
        val firstDisplayInsets = provider.getStatusBarContentAreaForRotation(ROTATION_NONE)
        givenDisplay(
            screenBounds = Rect(0, 0, 800, 600),
            displayUniqueId = "2"
        )
        configurationController.onConfigurationChanged(configuration)

        configuration.windowConfiguration.maxBounds = Rect(0, 0, 800, 600)

        // WHEN: get insets on the second display
        val secondDisplayInsets = provider.getStatusBarContentAreaForRotation(ROTATION_NONE)
@@ -487,23 +481,15 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
        // get insets and switch back
        val provider = StatusBarContentInsetsProvider(contextMock, configurationController,
            mock(DumpManager::class.java))
        givenDisplay(
            screenBounds = Rect(0, 0, 1080, 2160),
            displayUniqueId = "1"
        )

        configuration.windowConfiguration.maxBounds = Rect(0, 0, 1080, 2160)
        val firstDisplayInsetsFirstCall = provider
            .getStatusBarContentAreaForRotation(ROTATION_NONE)
        givenDisplay(
            screenBounds = Rect(0, 0, 800, 600),
            displayUniqueId = "2"
        )
        configurationController.onConfigurationChanged(configuration)

        configuration.windowConfiguration.maxBounds = Rect(0, 0, 800, 600)
        provider.getStatusBarContentAreaForRotation(ROTATION_NONE)
        givenDisplay(
            screenBounds = Rect(0, 0, 1080, 2160),
            displayUniqueId = "1"
        )
        configurationController.onConfigurationChanged(configuration)

        configuration.windowConfiguration.maxBounds = Rect(0, 0, 1080, 2160)

        // WHEN: get insets on the first display again
        val firstDisplayInsetsSecondCall = provider
@@ -513,9 +499,70 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() {
        assertThat(firstDisplayInsetsFirstCall).isEqualTo(firstDisplayInsetsSecondCall)
    }

    private fun givenDisplay(screenBounds: Rect, displayUniqueId: String) {
        `when`(display.uniqueId).thenReturn(displayUniqueId)
        configuration.windowConfiguration.maxBounds = screenBounds
    // Regression test for b/245799099
    @Test
    fun onMaxBoundsChanged_listenerNotified() {
        // Start out with an existing configuration with bounds
        configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100)
        configurationController.onConfigurationChanged(configuration)
        val provider = StatusBarContentInsetsProvider(contextMock, configurationController,
                mock(DumpManager::class.java))
        val listener = object : StatusBarContentInsetsChangedListener {
            var triggered = false

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

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

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

    @Test
    fun onDensityOrFontScaleChanged_listenerNotified() {
        configuration.densityDpi = 12
        val provider = StatusBarContentInsetsProvider(contextMock, configurationController,
                mock(DumpManager::class.java))
        val listener = object : StatusBarContentInsetsChangedListener {
            var triggered = false

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

        // WHEN the config is updated
        configuration.densityDpi = 20
        configurationController.onConfigurationChanged(configuration)

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

    @Test
    fun onThemeChanged_listenerNotified() {
        val provider = StatusBarContentInsetsProvider(contextMock, configurationController,
                mock(DumpManager::class.java))
        val listener = object : StatusBarContentInsetsChangedListener {
            var triggered = false

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

        configurationController.notifyThemeChanged()

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

    private fun assertRects(