Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt +10 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone import android.content.Context import android.content.pm.ActivityInfo import android.content.res.Configuration import android.graphics.Rect import android.os.LocaleList import android.view.View.LAYOUT_DIRECTION_RTL import com.android.systemui.statusbar.policy.ConfigurationController Loading @@ -29,6 +30,7 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController { private val lastConfig = Configuration() private var density: Int = 0 private var smallestScreenWidth: Int = 0 private var maxBounds: Rect? = null private var fontScale: Float = 0.toFloat() private val inCarMode: Boolean private var uiMode: Int = 0 Loading Loading @@ -85,6 +87,14 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController { } } val maxBounds = newConfig.windowConfiguration.maxBounds if (maxBounds != this.maxBounds) { this.maxBounds = maxBounds listeners.filterForEach({ this.listeners.contains(it) }) { it.onMaxBoundsChanged() } } val localeList = newConfig.locales if (localeList != this.localeList) { this.localeList = localeList Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +44 −41 Original line number Diff line number Diff line Loading @@ -19,11 +19,10 @@ package com.android.systemui.statusbar.phone import android.content.Context import android.content.res.Resources import android.graphics.Rect import android.util.Log import android.util.LruCache import android.util.Pair import android.view.DisplayCutout import android.view.View.LAYOUT_DIRECTION_RTL import android.view.WindowManager import android.view.WindowMetrics import androidx.annotation.VisibleForTesting import com.android.systemui.Dumpable Loading @@ -38,6 +37,7 @@ 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_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation import java.io.FileDescriptor import java.io.PrintWriter import java.lang.Math.max Loading @@ -61,13 +61,14 @@ import javax.inject.Inject class StatusBarContentInsetsProvider @Inject constructor( val context: Context, val configurationController: ConfigurationController, val windowManager: WindowManager, val dumpManager: DumpManager ) : CallbackController<StatusBarContentInsetsChangedListener>, ConfigurationController.ConfigurationListener, Dumpable { // Indexed by @Rotation private val insetsByCorner = arrayOfNulls<Rect>(4) // Limit cache size as potentially we may connect large number of displays // (e.g. network displays) private val insetsCache = LruCache<CacheKey, Rect>(MAX_CACHE_SIZE) private val listeners = mutableSetOf<StatusBarContentInsetsChangedListener>() init { Loading @@ -91,12 +92,12 @@ class StatusBarContentInsetsProvider @Inject constructor( clearCachedInsets() } private fun clearCachedInsets() { insetsByCorner[0] = null insetsByCorner[1] = null insetsByCorner[2] = null insetsByCorner[3] = null override fun onMaxBoundsChanged() { notifyInsetsChanged() } private fun clearCachedInsets() { insetsCache.evictAll() notifyInsetsChanged() } Loading @@ -111,10 +112,10 @@ class StatusBarContentInsetsProvider @Inject constructor( * dot in the coordinates relative to the given rotation. */ fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int): Rect { var insets = insetsByCorner[rotation] val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context) var insets = insetsCache[getCacheKey(rotation = rotation)] val rotatedResources = getResourcesForRotation(rotation, context) if (insets == null) { insets = getAndSetInsetsForRotation(rotation, rotatedResources) insets = getStatusBarContentInsetsForRotation(rotation, rotatedResources) } val dotWidth = rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter) Loading @@ -129,24 +130,16 @@ class StatusBarContentInsetsProvider @Inject constructor( * Calculates the necessary left and right locations for the status bar contents invariant of * the current device rotation, in the target rotation's coordinates */ fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Rect { var insets = insetsByCorner[rotation] if (insets == null) { val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context) insets = getAndSetInsetsForRotation(rotation, rotatedResources) } return insets } private fun getAndSetInsetsForRotation( @Rotation rot: Int, rotatedResources: Resources @JvmOverloads fun getStatusBarContentInsetsForRotation( @Rotation rotation: Int, rotatedResources: Resources = getResourcesForRotation(rotation, context) ): Rect { val insets = getCalculatedInsetsForRotation(rot, rotatedResources) insetsByCorner[rot] = insets return insets val key = getCacheKey(rotation = rotation) return insetsCache[key] ?: getCalculatedInsetsForRotation(rotation, rotatedResources) .also { insetsCache.put(key, it) } } private fun getCalculatedInsetsForRotation( Loading Loading @@ -176,17 +169,29 @@ class StatusBarContentInsetsProvider @Inject constructor( currentRotation, targetRotation, dc, windowManager.maximumWindowMetrics, context.resources.configuration.windowConfiguration.maxBounds, rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height), minLeft, minRight) } override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { insetsByCorner.forEachIndexed { index, rect -> pw.println("${RotationUtils.toString(index)} -> $rect") insetsCache.snapshot().forEach { (key, rect) -> pw.println("$key -> $rect") } pw.println(insetsCache) } private fun getCacheKey(@Rotation rotation: Int): CacheKey = CacheKey( uniqueDisplayId = context.display.uniqueId, rotation = rotation ) private data class CacheKey( val uniqueDisplayId: String, @Rotation val rotation: Int ) } interface StatusBarContentInsetsChangedListener { Loading @@ -194,10 +199,9 @@ interface StatusBarContentInsetsChangedListener { } private const val TAG = "StatusBarInsetsProvider" private const val MAX_CACHE_SIZE = 16 private fun getRotationZeroDisplayBounds(wm: WindowMetrics, @Rotation exactRotation: Int): Rect { val bounds = wm.bounds private fun getRotationZeroDisplayBounds(bounds: Rect, @Rotation exactRotation: Int): Rect { if (exactRotation == ROTATION_NONE || exactRotation == ROTATION_UPSIDE_DOWN) { return bounds } Loading Loading @@ -243,7 +247,7 @@ fun calculateInsetsForRotationWithRotatedResources( @Rotation currentRotation: Int, @Rotation targetRotation: Int, displayCutout: DisplayCutout?, windowMetrics: WindowMetrics, maxBounds: Rect, statusBarHeight: Int, minLeft: Int, minRight: Int Loading @@ -254,16 +258,15 @@ fun calculateInsetsForRotationWithRotatedResources( val right = if (isRtl) paddingStart else paddingEnd */ val rotZeroBounds = getRotationZeroDisplayBounds(windowMetrics, currentRotation) val currentBounds = windowMetrics.bounds val rotZeroBounds = getRotationZeroDisplayBounds(maxBounds, currentRotation) val sbLeftRight = getStatusBarLeftRight( displayCutout, statusBarHeight, rotZeroBounds.right, rotZeroBounds.bottom, currentBounds.width(), currentBounds.height(), maxBounds.width(), maxBounds.height(), minLeft, minRight, targetRotation, Loading packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ public interface ConfigurationController extends CallbackController<Configuratio default void onConfigChanged(Configuration newConfig) {} default void onDensityOrFontScaleChanged() {} default void onSmallestScreenWidthChanged() {} default void onMaxBoundsChanged() {} default void onOverlayChanged() {} default void onUiModeChanged() {} default void onThemeChanged() {} Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt +100 −24 Original line number Diff line number Diff line Loading @@ -16,32 +16,54 @@ 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 android.view.WindowMetrics import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.leak.RotationUtils import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE 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_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations @SmallTest class StatusBarContentInsetsProviderTest : SysuiTestCase() { @Mock private lateinit var dc: DisplayCutout @Mock private lateinit var windowMetrics: WindowMetrics @Mock private lateinit var contextMock: Context @Mock private lateinit var display: Display private lateinit var configurationController: ConfigurationController private val configuration = Configuration() @Before fun setup() { MockitoAnnotations.initMocks(this) `when`(contextMock.display).thenReturn(display) context.ensureTestableResources() `when`(contextMock.resources).thenReturn(context.resources) `when`(contextMock.resources.configuration).thenReturn(configuration) `when`(contextMock.createConfigurationContext(any())).thenAnswer { context.createConfigurationContext(it.arguments[0] as Configuration) } configurationController = ConfigurationControllerImpl(contextMock) } @Test Loading @@ -55,15 +77,13 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val chipWidth = 30 val dotWidth = 10 `when`(windowMetrics.bounds).thenReturn(screenBounds) var isRtl = false var targetRotation = ROTATION_NONE var bounds = calculateInsetsForRotationWithRotatedResources( currentRotation, targetRotation, null, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading Loading @@ -92,7 +112,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading Loading @@ -127,7 +147,6 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE `when`(windowMetrics.bounds).thenReturn(screenBounds) `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) // THEN rotations which share a short side should use the greater value between rounded Loading @@ -142,7 +161,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -159,7 +178,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -178,7 +197,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -196,7 +215,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -219,7 +238,6 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE `when`(windowMetrics.bounds).thenReturn(screenBounds) `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) // THEN only the landscape/seascape rotations should avoid the cutout area because of the Loading @@ -234,7 +252,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -251,7 +269,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -268,7 +286,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -285,7 +303,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -303,8 +321,6 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightPortrait = 100 val sbHeightLandscape = 60 `when`(windowMetrics.bounds).thenReturn(screenBounds) // THEN content insets should only use rounded corner padding var targetRotation = ROTATION_NONE var expectedBounds = Rect(minLeftPadding, Loading @@ -316,7 +332,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, null, /* no cutout */ windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -332,7 +348,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, null, /* no cutout */ windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -348,7 +364,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, null, /* no cutout */ windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -364,7 +380,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, null, /* no cutout */ windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -382,7 +398,6 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE `when`(windowMetrics.bounds).thenReturn(screenBounds) `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) // THEN left should be set to the display cutout width, and right should use the minRight Loading @@ -396,7 +411,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -404,6 +419,67 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { assertRects(expectedBounds, bounds, currentRotation, targetRotation) } @Test fun testDisplayChanged_returnsUpdatedInsets() { // GIVEN: get insets on the first display and switch to the second display val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) givenDisplay( screenBounds = Rect(0, 0, 1080, 2160), displayUniqueId = "1" ) val firstDisplayInsets = provider.getStatusBarContentInsetsForRotation(ROTATION_NONE) givenDisplay( screenBounds = Rect(0, 0, 800, 600), displayUniqueId = "2" ) configurationController.onConfigurationChanged(configuration) // WHEN: get insets on the second display val secondDisplayInsets = provider.getStatusBarContentInsetsForRotation(ROTATION_NONE) // THEN: insets are updated assertThat(firstDisplayInsets).isNotEqualTo(secondDisplayInsets) } @Test fun testDisplayChangedAndReturnedBack_returnsTheSameInsets() { // GIVEN: get insets on the first display, switch to the second display, // get insets and switch back val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) givenDisplay( screenBounds = Rect(0, 0, 1080, 2160), displayUniqueId = "1" ) val firstDisplayInsetsFirstCall = provider .getStatusBarContentInsetsForRotation(ROTATION_NONE) givenDisplay( screenBounds = Rect(0, 0, 800, 600), displayUniqueId = "2" ) configurationController.onConfigurationChanged(configuration) provider.getStatusBarContentInsetsForRotation(ROTATION_NONE) givenDisplay( screenBounds = Rect(0, 0, 1080, 2160), displayUniqueId = "1" ) configurationController.onConfigurationChanged(configuration) // WHEN: get insets on the first display again val firstDisplayInsetsSecondCall = provider .getStatusBarContentInsetsForRotation(ROTATION_NONE) // THEN: insets for the first and second calls for the first display are the same assertThat(firstDisplayInsetsFirstCall).isEqualTo(firstDisplayInsetsSecondCall) } private fun givenDisplay(screenBounds: Rect, displayUniqueId: String) { `when`(display.uniqueId).thenReturn(displayUniqueId) configuration.windowConfiguration.maxBounds = screenBounds } private fun assertRects( expected: Rect, actual: Rect, Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt +10 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.systemui.statusbar.phone import android.content.Context import android.content.pm.ActivityInfo import android.content.res.Configuration import android.graphics.Rect import android.os.LocaleList import android.view.View.LAYOUT_DIRECTION_RTL import com.android.systemui.statusbar.policy.ConfigurationController Loading @@ -29,6 +30,7 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController { private val lastConfig = Configuration() private var density: Int = 0 private var smallestScreenWidth: Int = 0 private var maxBounds: Rect? = null private var fontScale: Float = 0.toFloat() private val inCarMode: Boolean private var uiMode: Int = 0 Loading Loading @@ -85,6 +87,14 @@ class ConfigurationControllerImpl(context: Context) : ConfigurationController { } } val maxBounds = newConfig.windowConfiguration.maxBounds if (maxBounds != this.maxBounds) { this.maxBounds = maxBounds listeners.filterForEach({ this.listeners.contains(it) }) { it.onMaxBoundsChanged() } } val localeList = newConfig.locales if (localeList != this.localeList) { this.localeList = localeList Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +44 −41 Original line number Diff line number Diff line Loading @@ -19,11 +19,10 @@ package com.android.systemui.statusbar.phone import android.content.Context import android.content.res.Resources import android.graphics.Rect import android.util.Log import android.util.LruCache import android.util.Pair import android.view.DisplayCutout import android.view.View.LAYOUT_DIRECTION_RTL import android.view.WindowManager import android.view.WindowMetrics import androidx.annotation.VisibleForTesting import com.android.systemui.Dumpable Loading @@ -38,6 +37,7 @@ 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_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation import java.io.FileDescriptor import java.io.PrintWriter import java.lang.Math.max Loading @@ -61,13 +61,14 @@ import javax.inject.Inject class StatusBarContentInsetsProvider @Inject constructor( val context: Context, val configurationController: ConfigurationController, val windowManager: WindowManager, val dumpManager: DumpManager ) : CallbackController<StatusBarContentInsetsChangedListener>, ConfigurationController.ConfigurationListener, Dumpable { // Indexed by @Rotation private val insetsByCorner = arrayOfNulls<Rect>(4) // Limit cache size as potentially we may connect large number of displays // (e.g. network displays) private val insetsCache = LruCache<CacheKey, Rect>(MAX_CACHE_SIZE) private val listeners = mutableSetOf<StatusBarContentInsetsChangedListener>() init { Loading @@ -91,12 +92,12 @@ class StatusBarContentInsetsProvider @Inject constructor( clearCachedInsets() } private fun clearCachedInsets() { insetsByCorner[0] = null insetsByCorner[1] = null insetsByCorner[2] = null insetsByCorner[3] = null override fun onMaxBoundsChanged() { notifyInsetsChanged() } private fun clearCachedInsets() { insetsCache.evictAll() notifyInsetsChanged() } Loading @@ -111,10 +112,10 @@ class StatusBarContentInsetsProvider @Inject constructor( * dot in the coordinates relative to the given rotation. */ fun getBoundingRectForPrivacyChipForRotation(@Rotation rotation: Int): Rect { var insets = insetsByCorner[rotation] val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context) var insets = insetsCache[getCacheKey(rotation = rotation)] val rotatedResources = getResourcesForRotation(rotation, context) if (insets == null) { insets = getAndSetInsetsForRotation(rotation, rotatedResources) insets = getStatusBarContentInsetsForRotation(rotation, rotatedResources) } val dotWidth = rotatedResources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter) Loading @@ -129,24 +130,16 @@ class StatusBarContentInsetsProvider @Inject constructor( * Calculates the necessary left and right locations for the status bar contents invariant of * the current device rotation, in the target rotation's coordinates */ fun getStatusBarContentInsetsForRotation(@Rotation rotation: Int): Rect { var insets = insetsByCorner[rotation] if (insets == null) { val rotatedResources = RotationUtils.getResourcesForRotation(rotation, context) insets = getAndSetInsetsForRotation(rotation, rotatedResources) } return insets } private fun getAndSetInsetsForRotation( @Rotation rot: Int, rotatedResources: Resources @JvmOverloads fun getStatusBarContentInsetsForRotation( @Rotation rotation: Int, rotatedResources: Resources = getResourcesForRotation(rotation, context) ): Rect { val insets = getCalculatedInsetsForRotation(rot, rotatedResources) insetsByCorner[rot] = insets return insets val key = getCacheKey(rotation = rotation) return insetsCache[key] ?: getCalculatedInsetsForRotation(rotation, rotatedResources) .also { insetsCache.put(key, it) } } private fun getCalculatedInsetsForRotation( Loading Loading @@ -176,17 +169,29 @@ class StatusBarContentInsetsProvider @Inject constructor( currentRotation, targetRotation, dc, windowManager.maximumWindowMetrics, context.resources.configuration.windowConfiguration.maxBounds, rotatedResources.getDimensionPixelSize(R.dimen.status_bar_height), minLeft, minRight) } override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { insetsByCorner.forEachIndexed { index, rect -> pw.println("${RotationUtils.toString(index)} -> $rect") insetsCache.snapshot().forEach { (key, rect) -> pw.println("$key -> $rect") } pw.println(insetsCache) } private fun getCacheKey(@Rotation rotation: Int): CacheKey = CacheKey( uniqueDisplayId = context.display.uniqueId, rotation = rotation ) private data class CacheKey( val uniqueDisplayId: String, @Rotation val rotation: Int ) } interface StatusBarContentInsetsChangedListener { Loading @@ -194,10 +199,9 @@ interface StatusBarContentInsetsChangedListener { } private const val TAG = "StatusBarInsetsProvider" private const val MAX_CACHE_SIZE = 16 private fun getRotationZeroDisplayBounds(wm: WindowMetrics, @Rotation exactRotation: Int): Rect { val bounds = wm.bounds private fun getRotationZeroDisplayBounds(bounds: Rect, @Rotation exactRotation: Int): Rect { if (exactRotation == ROTATION_NONE || exactRotation == ROTATION_UPSIDE_DOWN) { return bounds } Loading Loading @@ -243,7 +247,7 @@ fun calculateInsetsForRotationWithRotatedResources( @Rotation currentRotation: Int, @Rotation targetRotation: Int, displayCutout: DisplayCutout?, windowMetrics: WindowMetrics, maxBounds: Rect, statusBarHeight: Int, minLeft: Int, minRight: Int Loading @@ -254,16 +258,15 @@ fun calculateInsetsForRotationWithRotatedResources( val right = if (isRtl) paddingStart else paddingEnd */ val rotZeroBounds = getRotationZeroDisplayBounds(windowMetrics, currentRotation) val currentBounds = windowMetrics.bounds val rotZeroBounds = getRotationZeroDisplayBounds(maxBounds, currentRotation) val sbLeftRight = getStatusBarLeftRight( displayCutout, statusBarHeight, rotZeroBounds.right, rotZeroBounds.bottom, currentBounds.width(), currentBounds.height(), maxBounds.width(), maxBounds.height(), minLeft, minRight, targetRotation, Loading
packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ public interface ConfigurationController extends CallbackController<Configuratio default void onConfigChanged(Configuration newConfig) {} default void onDensityOrFontScaleChanged() {} default void onSmallestScreenWidthChanged() {} default void onMaxBoundsChanged() {} default void onOverlayChanged() {} default void onUiModeChanged() {} default void onThemeChanged() {} Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt +100 −24 Original line number Diff line number Diff line Loading @@ -16,32 +16,54 @@ 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 android.view.WindowMetrics import com.android.systemui.SysuiTestCase import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.leak.RotationUtils import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE 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_UPSIDE_DOWN import com.android.systemui.util.leak.RotationUtils.Rotation import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue import org.junit.Before import org.junit.Test import org.mockito.ArgumentMatchers.any import org.mockito.Mock import org.mockito.Mockito.`when` import org.mockito.Mockito.mock import org.mockito.MockitoAnnotations @SmallTest class StatusBarContentInsetsProviderTest : SysuiTestCase() { @Mock private lateinit var dc: DisplayCutout @Mock private lateinit var windowMetrics: WindowMetrics @Mock private lateinit var contextMock: Context @Mock private lateinit var display: Display private lateinit var configurationController: ConfigurationController private val configuration = Configuration() @Before fun setup() { MockitoAnnotations.initMocks(this) `when`(contextMock.display).thenReturn(display) context.ensureTestableResources() `when`(contextMock.resources).thenReturn(context.resources) `when`(contextMock.resources.configuration).thenReturn(configuration) `when`(contextMock.createConfigurationContext(any())).thenAnswer { context.createConfigurationContext(it.arguments[0] as Configuration) } configurationController = ConfigurationControllerImpl(contextMock) } @Test Loading @@ -55,15 +77,13 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val chipWidth = 30 val dotWidth = 10 `when`(windowMetrics.bounds).thenReturn(screenBounds) var isRtl = false var targetRotation = ROTATION_NONE var bounds = calculateInsetsForRotationWithRotatedResources( currentRotation, targetRotation, null, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading Loading @@ -92,7 +112,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading Loading @@ -127,7 +147,6 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE `when`(windowMetrics.bounds).thenReturn(screenBounds) `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) // THEN rotations which share a short side should use the greater value between rounded Loading @@ -142,7 +161,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -159,7 +178,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -178,7 +197,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -196,7 +215,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -219,7 +238,6 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE `when`(windowMetrics.bounds).thenReturn(screenBounds) `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) // THEN only the landscape/seascape rotations should avoid the cutout area because of the Loading @@ -234,7 +252,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -251,7 +269,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -268,7 +286,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -285,7 +303,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -303,8 +321,6 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightPortrait = 100 val sbHeightLandscape = 60 `when`(windowMetrics.bounds).thenReturn(screenBounds) // THEN content insets should only use rounded corner padding var targetRotation = ROTATION_NONE var expectedBounds = Rect(minLeftPadding, Loading @@ -316,7 +332,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, null, /* no cutout */ windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -332,7 +348,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, null, /* no cutout */ windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -348,7 +364,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, null, /* no cutout */ windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -364,7 +380,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, null, /* no cutout */ windowMetrics, screenBounds, sbHeightLandscape, minLeftPadding, minRightPadding) Loading @@ -382,7 +398,6 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { val sbHeightLandscape = 60 val currentRotation = ROTATION_NONE `when`(windowMetrics.bounds).thenReturn(screenBounds) `when`(dc.boundingRects).thenReturn(listOf(dcBounds)) // THEN left should be set to the display cutout width, and right should use the minRight Loading @@ -396,7 +411,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { currentRotation, targetRotation, dc, windowMetrics, screenBounds, sbHeightPortrait, minLeftPadding, minRightPadding) Loading @@ -404,6 +419,67 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { assertRects(expectedBounds, bounds, currentRotation, targetRotation) } @Test fun testDisplayChanged_returnsUpdatedInsets() { // GIVEN: get insets on the first display and switch to the second display val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) givenDisplay( screenBounds = Rect(0, 0, 1080, 2160), displayUniqueId = "1" ) val firstDisplayInsets = provider.getStatusBarContentInsetsForRotation(ROTATION_NONE) givenDisplay( screenBounds = Rect(0, 0, 800, 600), displayUniqueId = "2" ) configurationController.onConfigurationChanged(configuration) // WHEN: get insets on the second display val secondDisplayInsets = provider.getStatusBarContentInsetsForRotation(ROTATION_NONE) // THEN: insets are updated assertThat(firstDisplayInsets).isNotEqualTo(secondDisplayInsets) } @Test fun testDisplayChangedAndReturnedBack_returnsTheSameInsets() { // GIVEN: get insets on the first display, switch to the second display, // get insets and switch back val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) givenDisplay( screenBounds = Rect(0, 0, 1080, 2160), displayUniqueId = "1" ) val firstDisplayInsetsFirstCall = provider .getStatusBarContentInsetsForRotation(ROTATION_NONE) givenDisplay( screenBounds = Rect(0, 0, 800, 600), displayUniqueId = "2" ) configurationController.onConfigurationChanged(configuration) provider.getStatusBarContentInsetsForRotation(ROTATION_NONE) givenDisplay( screenBounds = Rect(0, 0, 1080, 2160), displayUniqueId = "1" ) configurationController.onConfigurationChanged(configuration) // WHEN: get insets on the first display again val firstDisplayInsetsSecondCall = provider .getStatusBarContentInsetsForRotation(ROTATION_NONE) // THEN: insets for the first and second calls for the first display are the same assertThat(firstDisplayInsetsFirstCall).isEqualTo(firstDisplayInsetsSecondCall) } private fun givenDisplay(screenBounds: Rect, displayUniqueId: String) { `when`(display.uniqueId).thenReturn(displayUniqueId) configuration.windowConfiguration.maxBounds = screenBounds } private fun assertRects( expected: Rect, actual: Rect, Loading