From 714485160cd4c97d0f97f8eb063649a1f9badcf8 Mon Sep 17 00:00:00 2001 From: Caitlin Shkuratov Date: Mon, 14 Nov 2022 21:25:56 +0000 Subject: [PATCH] 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 --- .../phone/ConfigurationControllerImpl.kt | 1 + .../phone/ConfigurationControllerImplTest.kt | 304 ++++++++++++++++-- 2 files changed, 285 insertions(+), 20 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt index 110dc90b62918..7dcdc0bdb3832 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt @@ -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 diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt index b1e62e19dd3bb..038af8ff53967 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt @@ -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() { @@ -59,20 +72,114 @@ class ConfigurationControllerImplTest : SysuiTestCase() { 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 = object : ConfigurationListener { - var triggered: Boolean = false - - override fun onMaxBoundsChanged() { - triggered = true - } - } - mConfigurationController.addCallback(listener) + 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 - - override fun onMaxBoundsChanged() { - triggered = true - } - } - mConfigurationController.addCallback(listener) + 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.triggered).isTrue() + 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 + } } }