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

Commit 71448516 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

Write tests for all of ConfigurationControllerImpl.

Fixes: 259105114
Test: atest ConfigurationControllerImplTest
Test: verify privacy indicator still works on all displays (b/245799099)
Change-Id: I4e2c4584c3f18cf2157afc6a38434002ba307b65
parent 0f2a227b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+284 −20
Original line number Diff line number Diff line
@@ -15,23 +15,36 @@
package com.android.systemui.statusbar.phone

import android.content.res.Configuration
import androidx.test.filters.SmallTest
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 = ConfigurationControllerImpl(mContext)
    private lateinit var mConfigurationController: ConfigurationControllerImpl

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

    @Test
    fun testThemeChange() {
@@ -60,19 +73,113 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
    }

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

        val listener = object : ConfigurationListener {
            var triggered: Boolean = false
        val listener = createAndAddListener()

            override fun onMaxBoundsChanged() {
                triggered = true
        // 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()
    }
        mConfigurationController.addCallback(listener)

    @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()
@@ -80,7 +187,7 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
        mConfigurationController.onConfigurationChanged(newConfig)

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

    // Regression test for b/245799099
@@ -90,20 +197,177 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
        config.windowConfiguration.setMaxBounds(0, 0, 200, 200)
        mConfigurationController.onConfigurationChanged(config)

        val listener = object : ConfigurationListener {
            var triggered: Boolean = false
        val listener = createAndAddListener()

            override fun onMaxBoundsChanged() {
                triggered = true
        // 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()
    }
        mConfigurationController.addCallback(listener)

        // WHEN the existing config is updated with new bounds
        config.windowConfiguration.setMaxBounds(0, 0, 100, 100)
    @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.triggered).isTrue()
        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
        }
    }
}