Loading packages/SystemUI/src/com/android/systemui/StatusBarInsetsCommand.kt 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 import android.view.Surface import android.view.Surface.Rotation import com.android.systemui.statusbar.commandline.ParseableCommand import com.android.systemui.statusbar.commandline.Type import java.io.PrintWriter class StatusBarInsetsCommand( private val callback: Callback, ) : ParseableCommand(NAME) { val bottomMargin: BottomMarginCommand? by subCommand(BottomMarginCommand()) override fun execute(pw: PrintWriter) { callback.onExecute(command = this, pw) } interface Callback { fun onExecute(command: StatusBarInsetsCommand, printWriter: PrintWriter) } companion object { const val NAME = "status-bar-insets" } } class BottomMarginCommand : ParseableCommand(NAME) { private val rotationDegrees: Int? by param( longName = "rotation", shortName = "r", description = "For which rotation the margin should be set. One of 0, 90, 180, 270", valueParser = Type.Int, ) @Rotation val rotationValue: Int? get() = ROTATION_DEGREES_TO_VALUE_MAPPING[rotationDegrees] val marginBottomDp: Float? by param( longName = "margin", shortName = "m", description = "Margin amount, in dp. Can be a fractional value, such as 10.5", valueParser = Type.Float, ) override fun execute(pw: PrintWriter) { // Not needed for a subcommand } companion object { const val NAME = "bottom-margin" private val ROTATION_DEGREES_TO_VALUE_MAPPING = mapOf( 0 to Surface.ROTATION_0, 90 to Surface.ROTATION_90, 180 to Surface.ROTATION_180, 270 to Surface.ROTATION_270, ) val ROTATION_DEGREES_OPTIONS: Set<Int> = ROTATION_DEGREES_TO_VALUE_MAPPING.keys } } packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +46 −1 Original line number Diff line number Diff line Loading @@ -42,6 +42,9 @@ import com.android.systemui.util.leak.RotationUtils.Rotation import com.android.systemui.util.leak.RotationUtils.getExactRotation import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation import com.android.app.tracing.traceSection import com.android.systemui.BottomMarginCommand import com.android.systemui.StatusBarInsetsCommand import com.android.systemui.statusbar.commandline.CommandRegistry import java.io.PrintWriter import java.lang.Math.max import javax.inject.Inject Loading @@ -64,7 +67,8 @@ import javax.inject.Inject class StatusBarContentInsetsProvider @Inject constructor( val context: Context, val configurationController: ConfigurationController, val dumpManager: DumpManager val dumpManager: DumpManager, val commandRegistry: CommandRegistry, ) : CallbackController<StatusBarContentInsetsChangedListener>, ConfigurationController.ConfigurationListener, Dumpable { Loading @@ -80,6 +84,13 @@ class StatusBarContentInsetsProvider @Inject constructor( init { configurationController.addCallback(this) dumpManager.registerDumpable(TAG, this) commandRegistry.registerCommand(StatusBarInsetsCommand.NAME) { StatusBarInsetsCommand(object : StatusBarInsetsCommand.Callback { override fun onExecute(command: StatusBarInsetsCommand, printWriter: PrintWriter) { executeCommand(command, printWriter) } }) } } override fun addCallback(listener: StatusBarContentInsetsChangedListener) { Loading Loading @@ -271,8 +282,41 @@ class StatusBarContentInsetsProvider @Inject constructor( statusBarContentHeight) } private fun executeCommand(command: StatusBarInsetsCommand, printWriter: PrintWriter) { command.bottomMargin?.let { executeBottomMarginCommand(it, printWriter) } } private fun executeBottomMarginCommand(command: BottomMarginCommand, printWriter: PrintWriter) { val rotation = command.rotationValue if (rotation == null) { printWriter.println( "Rotation should be one of ${BottomMarginCommand.ROTATION_DEGREES_OPTIONS}" ) return } val marginBottomDp = command.marginBottomDp if (marginBottomDp == null) { printWriter.println("Margin bottom not set.") return } setBottomMarginOverride(rotation, marginBottomDp) } private val marginBottomOverrides = mutableMapOf<Int, Int>() private fun setBottomMarginOverride(rotation: Int, marginBottomDp: Float) { insetsCache.evictAll() val marginBottomPx = (marginBottomDp * context.resources.displayMetrics.density).toInt() marginBottomOverrides[rotation] = marginBottomPx notifyInsetsChanged() } @Px private fun getBottomAlignedMargin(targetRotation: Int, resources: Resources): Int { val override = marginBottomOverrides[targetRotation] if (override != null) { return override } val dimenRes = when (targetRotation) { Surface.ROTATION_0 -> R.dimen.status_bar_bottom_aligned_margin_rotation_0 Loading @@ -294,6 +338,7 @@ class StatusBarContentInsetsProvider @Inject constructor( pw.println("$key -> $rect") } pw.println(insetsCache) pw.println("Bottom margin overrides: $marginBottomOverrides") } private fun getCacheKey( Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt +7 −6 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ 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.commandline.CommandRegistry import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.leak.RotationUtils import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE Loading @@ -31,6 +32,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.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue Loading @@ -39,7 +41,6 @@ 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 Loading Loading @@ -556,7 +557,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { 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)) mock<DumpManager>(), mock<CommandRegistry>()) configuration.windowConfiguration.setMaxBounds(Rect(0, 0, 1080, 2160)) val firstDisplayInsets = provider.getStatusBarContentAreaForRotation(ROTATION_NONE) Loading @@ -575,7 +576,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { // 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)) mock<DumpManager>(), mock<CommandRegistry>()) configuration.windowConfiguration.setMaxBounds(Rect(0, 0, 1080, 2160)) val firstDisplayInsetsFirstCall = provider Loading @@ -601,7 +602,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100) configurationController.onConfigurationChanged(configuration) val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) mock<DumpManager>(), mock<CommandRegistry>()) val listener = object : StatusBarContentInsetsChangedListener { var triggered = false Loading @@ -623,7 +624,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { fun onDensityOrFontScaleChanged_listenerNotified() { configuration.densityDpi = 12 val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) mock<DumpManager>(), mock<CommandRegistry>()) val listener = object : StatusBarContentInsetsChangedListener { var triggered = false Loading @@ -644,7 +645,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { @Test fun onThemeChanged_listenerNotified() { val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) mock<DumpManager>(), mock<CommandRegistry>()) val listener = object : StatusBarContentInsetsChangedListener { var triggered = false Loading Loading
packages/SystemUI/src/com/android/systemui/StatusBarInsetsCommand.kt 0 → 100644 +82 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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 import android.view.Surface import android.view.Surface.Rotation import com.android.systemui.statusbar.commandline.ParseableCommand import com.android.systemui.statusbar.commandline.Type import java.io.PrintWriter class StatusBarInsetsCommand( private val callback: Callback, ) : ParseableCommand(NAME) { val bottomMargin: BottomMarginCommand? by subCommand(BottomMarginCommand()) override fun execute(pw: PrintWriter) { callback.onExecute(command = this, pw) } interface Callback { fun onExecute(command: StatusBarInsetsCommand, printWriter: PrintWriter) } companion object { const val NAME = "status-bar-insets" } } class BottomMarginCommand : ParseableCommand(NAME) { private val rotationDegrees: Int? by param( longName = "rotation", shortName = "r", description = "For which rotation the margin should be set. One of 0, 90, 180, 270", valueParser = Type.Int, ) @Rotation val rotationValue: Int? get() = ROTATION_DEGREES_TO_VALUE_MAPPING[rotationDegrees] val marginBottomDp: Float? by param( longName = "margin", shortName = "m", description = "Margin amount, in dp. Can be a fractional value, such as 10.5", valueParser = Type.Float, ) override fun execute(pw: PrintWriter) { // Not needed for a subcommand } companion object { const val NAME = "bottom-margin" private val ROTATION_DEGREES_TO_VALUE_MAPPING = mapOf( 0 to Surface.ROTATION_0, 90 to Surface.ROTATION_90, 180 to Surface.ROTATION_180, 270 to Surface.ROTATION_270, ) val ROTATION_DEGREES_OPTIONS: Set<Int> = ROTATION_DEGREES_TO_VALUE_MAPPING.keys } }
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProvider.kt +46 −1 Original line number Diff line number Diff line Loading @@ -42,6 +42,9 @@ import com.android.systemui.util.leak.RotationUtils.Rotation import com.android.systemui.util.leak.RotationUtils.getExactRotation import com.android.systemui.util.leak.RotationUtils.getResourcesForRotation import com.android.app.tracing.traceSection import com.android.systemui.BottomMarginCommand import com.android.systemui.StatusBarInsetsCommand import com.android.systemui.statusbar.commandline.CommandRegistry import java.io.PrintWriter import java.lang.Math.max import javax.inject.Inject Loading @@ -64,7 +67,8 @@ import javax.inject.Inject class StatusBarContentInsetsProvider @Inject constructor( val context: Context, val configurationController: ConfigurationController, val dumpManager: DumpManager val dumpManager: DumpManager, val commandRegistry: CommandRegistry, ) : CallbackController<StatusBarContentInsetsChangedListener>, ConfigurationController.ConfigurationListener, Dumpable { Loading @@ -80,6 +84,13 @@ class StatusBarContentInsetsProvider @Inject constructor( init { configurationController.addCallback(this) dumpManager.registerDumpable(TAG, this) commandRegistry.registerCommand(StatusBarInsetsCommand.NAME) { StatusBarInsetsCommand(object : StatusBarInsetsCommand.Callback { override fun onExecute(command: StatusBarInsetsCommand, printWriter: PrintWriter) { executeCommand(command, printWriter) } }) } } override fun addCallback(listener: StatusBarContentInsetsChangedListener) { Loading Loading @@ -271,8 +282,41 @@ class StatusBarContentInsetsProvider @Inject constructor( statusBarContentHeight) } private fun executeCommand(command: StatusBarInsetsCommand, printWriter: PrintWriter) { command.bottomMargin?.let { executeBottomMarginCommand(it, printWriter) } } private fun executeBottomMarginCommand(command: BottomMarginCommand, printWriter: PrintWriter) { val rotation = command.rotationValue if (rotation == null) { printWriter.println( "Rotation should be one of ${BottomMarginCommand.ROTATION_DEGREES_OPTIONS}" ) return } val marginBottomDp = command.marginBottomDp if (marginBottomDp == null) { printWriter.println("Margin bottom not set.") return } setBottomMarginOverride(rotation, marginBottomDp) } private val marginBottomOverrides = mutableMapOf<Int, Int>() private fun setBottomMarginOverride(rotation: Int, marginBottomDp: Float) { insetsCache.evictAll() val marginBottomPx = (marginBottomDp * context.resources.displayMetrics.density).toInt() marginBottomOverrides[rotation] = marginBottomPx notifyInsetsChanged() } @Px private fun getBottomAlignedMargin(targetRotation: Int, resources: Resources): Int { val override = marginBottomOverrides[targetRotation] if (override != null) { return override } val dimenRes = when (targetRotation) { Surface.ROTATION_0 -> R.dimen.status_bar_bottom_aligned_margin_rotation_0 Loading @@ -294,6 +338,7 @@ class StatusBarContentInsetsProvider @Inject constructor( pw.println("$key -> $rect") } pw.println(insetsCache) pw.println("Bottom margin overrides: $marginBottomOverrides") } private fun getCacheKey( Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarContentInsetsProviderTest.kt +7 −6 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ 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.commandline.CommandRegistry import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.leak.RotationUtils import com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE Loading @@ -31,6 +32,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.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat import junit.framework.Assert.assertTrue Loading @@ -39,7 +41,6 @@ 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 Loading Loading @@ -556,7 +557,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { 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)) mock<DumpManager>(), mock<CommandRegistry>()) configuration.windowConfiguration.setMaxBounds(Rect(0, 0, 1080, 2160)) val firstDisplayInsets = provider.getStatusBarContentAreaForRotation(ROTATION_NONE) Loading @@ -575,7 +576,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { // 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)) mock<DumpManager>(), mock<CommandRegistry>()) configuration.windowConfiguration.setMaxBounds(Rect(0, 0, 1080, 2160)) val firstDisplayInsetsFirstCall = provider Loading @@ -601,7 +602,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { configuration.windowConfiguration.setMaxBounds(0, 0, 100, 100) configurationController.onConfigurationChanged(configuration) val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) mock<DumpManager>(), mock<CommandRegistry>()) val listener = object : StatusBarContentInsetsChangedListener { var triggered = false Loading @@ -623,7 +624,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { fun onDensityOrFontScaleChanged_listenerNotified() { configuration.densityDpi = 12 val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) mock<DumpManager>(), mock<CommandRegistry>()) val listener = object : StatusBarContentInsetsChangedListener { var triggered = false Loading @@ -644,7 +645,7 @@ class StatusBarContentInsetsProviderTest : SysuiTestCase() { @Test fun onThemeChanged_listenerNotified() { val provider = StatusBarContentInsetsProvider(contextMock, configurationController, mock(DumpManager::class.java)) mock<DumpManager>(), mock<CommandRegistry>()) val listener = object : StatusBarContentInsetsChangedListener { var triggered = false Loading