summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt15
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt10
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationForwarder.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt10
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java8
13 files changed, 185 insertions, 7 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt
index a308c8ee38ca..3f4d3f8ba12a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/ui/data/repository/ConfigurationRepositoryImplTest.kt
@@ -98,6 +98,21 @@ class ConfigurationRepositoryImplTest : SysuiTestCase() {
}
@Test
+ fun onMovedToDisplays_updatesOnMovedToDisplay() =
+ testScope.runTest {
+ val lastOnMovedToDisplay by collectLastValue(underTest.onMovedToDisplay)
+ assertThat(lastOnMovedToDisplay).isNull()
+
+ val configurationCallback = withArgCaptor {
+ verify(configurationController).addCallback(capture())
+ }
+
+ configurationCallback.onMovedToDisplay(1, Configuration())
+ runCurrent()
+ assertThat(lastOnMovedToDisplay).isEqualTo(1)
+ }
+
+ @Test
fun onAnyConfigurationChange_updatesOnConfigChanged() =
testScope.runTest {
val lastAnyConfigurationChange by collectLastValue(underTest.onAnyConfigurationChange)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 5d1ce7c5ca05..929537dcf757 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -253,6 +253,16 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
verify(configurationForwarder).onConfigurationChanged(eq(config))
}
+ @Test
+ @EnableFlags(AConfigFlags.FLAG_SHADE_WINDOW_GOES_AROUND)
+ fun onMovedToDisplay_configForwarderSet_propagatesConfig() {
+ val config = Configuration()
+
+ underTest.onMovedToDisplay(1, config)
+
+ verify(configurationForwarder).dispatchOnMovedToDisplay(eq(1), eq(config))
+ }
+
private fun captureInteractionEventHandler() {
verify(underTest).setInteractionEventHandler(interactionEventHandlerCaptor.capture())
interactionEventHandler = interactionEventHandlerCaptor.value
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
index 942ea65ec49e..e87077db8e75 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ConfigurationControllerImplTest.kt
@@ -21,11 +21,13 @@ 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.view.Display
import androidx.test.ext.junit.runners.AndroidJUnit4
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 java.util.Locale
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
@@ -34,7 +36,6 @@ 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(AndroidJUnit4::class)
@SmallTest
@@ -64,9 +65,11 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
mConfigurationController.addCallback(listener2)
doAnswer {
- mConfigurationController.removeCallback(listener2)
- null
- }.`when`(listener).onThemeChanged()
+ mConfigurationController.removeCallback(listener2)
+ null
+ }
+ .`when`(listener)
+ .onThemeChanged()
mConfigurationController.notifyThemeChanged()
verify(listener).onThemeChanged()
@@ -208,7 +211,6 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
assertThat(listener.maxBoundsChanged).isTrue()
}
-
@Test
fun localeListChanged_listenerNotified() {
val config = mContext.resources.configuration
@@ -289,7 +291,6 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
assertThat(listener.orientationChanged).isTrue()
}
-
@Test
fun multipleUpdates_listenerNotifiedOfAll() {
val config = mContext.resources.configuration
@@ -313,6 +314,17 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
}
@Test
+ fun onMovedToDisplay_dispatchedToChildren() {
+ val config = mContext.resources.configuration
+ val listener = createAndAddListener()
+
+ mConfigurationController.dispatchOnMovedToDisplay(newDisplayId = 1, config)
+
+ assertThat(listener.display).isEqualTo(1)
+ assertThat(listener.changedConfig).isEqualTo(config)
+ }
+
+ @Test
@Ignore("b/261408895")
fun equivalentConfigObject_listenerNotNotified() {
val config = mContext.resources.configuration
@@ -343,35 +355,49 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
var localeListChanged = false
var layoutDirectionChanged = false
var orientationChanged = false
+ var display = Display.DEFAULT_DISPLAY
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
}
+
override fun onOrientationChanged(orientation: Int) {
orientationChanged = true
}
+ override fun onMovedToDisplay(newDisplayId: Int, newConfiguration: Configuration?) {
+ display = newDisplayId
+ changedConfig = newConfiguration
+ }
+
fun assertNoMethodsCalled() {
assertThat(densityOrFontScaleChanged).isFalse()
assertThat(smallestScreenWidthChanged).isFalse()
@@ -391,6 +417,7 @@ class ConfigurationControllerImplTest : SysuiTestCase() {
themeChanged = false
localeListChanged = false
layoutDirectionChanged = false
+ display = Display.DEFAULT_DISPLAY
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
index 4d804d06fe87..747a2a9bd887 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/data/repository/ConfigurationRepository.kt
@@ -53,8 +53,12 @@ interface ConfigurationRepository {
val onConfigurationChange: Flow<Unit>
val scaleForResolution: Flow<Float>
+
val configurationValues: Flow<Configuration>
+ /** Emits the latest display this configuration controller has been moved to. */
+ val onMovedToDisplay: Flow<Int>
+
fun getResolutionScale(): Float
/** Convenience to context.resources.getDimensionPixelSize() */
@@ -117,6 +121,20 @@ constructor(
configurationController.addCallback(callback)
awaitClose { configurationController.removeCallback(callback) }
}
+ override val onMovedToDisplay: Flow<Int>
+ get() = conflatedCallbackFlow {
+ val callback =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onMovedToDisplay(
+ newDisplayId: Int,
+ newConfiguration: Configuration?,
+ ) {
+ trySend(newDisplayId)
+ }
+ }
+ configurationController.addCallback(callback)
+ awaitClose { configurationController.removeCallback(callback) }
+ }
override val scaleForResolution: StateFlow<Float> =
onConfigurationChange
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
index bf672be3c8d0..0a9aa9b49e8c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
@@ -169,6 +169,10 @@ public class NotificationShadeWindowView extends WindowRootView {
public void onMovedToDisplay(int displayId, Configuration config) {
super.onMovedToDisplay(displayId, config);
ShadeWindowGoesAround.isUnexpectedlyInLegacyMode();
+ ShadeTraceLogger.INSTANCE.logOnMovedToDisplay(displayId, config);
+ if (mConfigurationForwarder != null) {
+ mConfigurationForwarder.dispatchOnMovedToDisplay(displayId, config);
+ }
// When the window is moved we're only receiving a call to this method instead of the
// onConfigurationChange itself. Let's just trigegr a normal config change.
onConfigurationChanged(config);
@@ -177,6 +181,7 @@ public class NotificationShadeWindowView extends WindowRootView {
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ ShadeTraceLogger.INSTANCE.logOnConfigChanged(newConfig);
if (mConfigurationForwarder != null) {
ShadeWindowGoesAround.isUnexpectedlyInLegacyMode();
mConfigurationForwarder.onConfigurationChanged(newConfig);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt
new file mode 100644
index 000000000000..a596d4f64638
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeTraceLogger.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 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.shade
+
+import android.content.res.Configuration
+import android.os.Trace
+import com.android.app.tracing.TraceUtils.traceAsync
+
+/**
+ * Centralized logging for shade-related events to a dedicated Perfetto track.
+ *
+ * Used by shade components to log events to a track named [TAG]. This consolidates shade-specific
+ * events into a single track for easier analysis in Perfetto, rather than scattering them across
+ * various threads' logs.
+ */
+object ShadeTraceLogger {
+ private const val TAG = "ShadeTraceLogger"
+
+ fun logOnMovedToDisplay(displayId: Int, config: Configuration) {
+ if (!Trace.isEnabled()) return
+ Trace.instantForTrack(
+ Trace.TRACE_TAG_APP,
+ TAG,
+ "onMovedToDisplay(displayId=$displayId, dpi=" + config.densityDpi + ")",
+ )
+ }
+
+ fun logOnConfigChanged(config: Configuration) {
+ if (!Trace.isEnabled()) return
+ Trace.instantForTrack(
+ Trace.TRACE_TAG_APP,
+ TAG,
+ "onConfigurationChanged(dpi=" + config.densityDpi + ")",
+ )
+ }
+
+ fun logMoveShadeWindowTo(displayId: Int) {
+ if (!Trace.isEnabled()) return
+ Trace.instantForTrack(Trace.TRACE_TAG_APP, TAG, "moveShadeWindowTo(displayId=$displayId)")
+ }
+
+ fun traceReparenting(r: () -> Unit) {
+ traceAsync(TAG, { "reparenting" }) { r() }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
index 08c03e28d596..8d536accaf76 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -27,6 +27,8 @@ import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.scene.ui.view.WindowRootView
import com.android.systemui.shade.ShadeDisplayAware
+import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo
+import com.android.systemui.shade.ShadeTraceLogger.traceReparenting
import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
import com.android.systemui.util.kotlin.getOrNull
@@ -68,6 +70,7 @@ constructor(
/** Tries to move the shade. If anything wrong happens, fails gracefully without crashing. */
private suspend fun moveShadeWindowTo(destinationId: Int) {
Log.d(TAG, "Trying to move shade window to display with id $destinationId")
+ logMoveShadeWindowTo(destinationId)
// Why using the shade context here instead of the view's Display?
// The context's display is updated before the view one, so it is a better indicator of
// which display the shade is supposed to be at. The View display is updated after the first
@@ -83,7 +86,9 @@ constructor(
return
}
try {
- withContext(mainThreadContext) { reparentToDisplayId(id = destinationId) }
+ withContext(mainThreadContext) {
+ traceReparenting { reparentToDisplayId(id = destinationId) }
+ }
} catch (e: IllegalStateException) {
Log.e(
TAG,
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 858cac111525..9c7af181284e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.kt
@@ -65,6 +65,13 @@ constructor(@Assisted private val context: Context) :
listeners.filterForEach({ this.listeners.contains(it) }) { it.onThemeChanged() }
}
+ override fun dispatchOnMovedToDisplay(newDisplayId: Int, newConfiguration: Configuration) {
+ val listeners = synchronized(this.listeners) { ArrayList(this.listeners) }
+ listeners.filterForEach({ this.listeners.contains(it) }) {
+ it.onMovedToDisplay(newDisplayId, newConfiguration)
+ }
+ }
+
override fun onConfigurationChanged(newConfig: Configuration) {
// Avoid concurrent modification exception
val listeners = synchronized(this.listeners) { ArrayList(this.listeners) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationForwarder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationForwarder.kt
index 3fd46fc484a9..537e3e1893b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationForwarder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationForwarder.kt
@@ -28,4 +28,13 @@ import android.content.res.Configuration
interface ConfigurationForwarder {
/** Should be called when a new configuration is received. */
fun onConfigurationChanged(newConfiguration: Configuration)
+
+ /**
+ * Should be called when the view associated to this configuration forwarded moved to another
+ * display, usually as a consequence of [View.onMovedToDisplay].
+ *
+ * For the default configuration forwarder (associated with the global configuration) this is
+ * never expected to be called.
+ */
+ fun dispatchOnMovedToDisplay(newDisplayId: Int, newConfiguration: Configuration)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index 1bb4e8c66ef1..c77f6c1b8552 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -45,5 +45,6 @@ public interface ConfigurationController extends CallbackController<Configuratio
default void onLocaleListChanged() {}
default void onLayoutDirectionChanged(boolean isLayoutRtl) {}
default void onOrientationChanged(int orientation) {}
+ default void onMovedToDisplay(int newDisplayId, Configuration newConfiguration) {}
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
index 4d74254cf9f8..487049740079 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/common/ui/data/repository/FakeConfigurationRepository.kt
@@ -17,6 +17,7 @@
package com.android.systemui.common.ui.data.repository
import android.content.res.Configuration
+import android.view.Display
import com.android.systemui.dagger.SysUISingleton
import dagger.Binds
import dagger.Module
@@ -25,6 +26,7 @@ import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -46,6 +48,10 @@ class FakeConfigurationRepository @Inject constructor() : ConfigurationRepositor
override val configurationValues: Flow<Configuration> =
_configurationChangeValues.asSharedFlow()
+ private val _onMovedToDisplay = MutableStateFlow<Int>(Display.DEFAULT_DISPLAY)
+ override val onMovedToDisplay: StateFlow<Int>
+ get() = _onMovedToDisplay
+
private val _scaleForResolution = MutableStateFlow(1f)
override val scaleForResolution: Flow<Float> = _scaleForResolution.asStateFlow()
@@ -64,6 +70,10 @@ class FakeConfigurationRepository @Inject constructor() : ConfigurationRepositor
onAnyConfigurationChange()
}
+ fun onMovedToDisplay(newDisplayId: Int) {
+ _onMovedToDisplay.value = newDisplayId
+ }
+
fun setScaleForResolution(scale: Float) {
_scaleForResolution.value = scale
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
index 32191277c94a..13673d16bf3c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeConfigurationController.kt
@@ -27,6 +27,10 @@ class FakeConfigurationController @Inject constructor() :
listeners.forEach { it.onConfigChanged(newConfiguration) }
}
+ override fun dispatchOnMovedToDisplay(newDisplayId: Int, newConfiguration: Configuration) {
+ listeners.forEach { it.onMovedToDisplay(newDisplayId, newConfiguration) }
+ }
+
override fun notifyThemeChanged() {
listeners.forEach { it.onThemeChanged() }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
index 111c40d49efc..9cf25e8df727 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
@@ -16,6 +16,8 @@ package com.android.systemui.utils.leaks;
import android.content.res.Configuration;
+import androidx.annotation.NonNull;
+
import com.android.systemui.statusbar.policy.ConfigurationController;
public class FakeConfigurationController
@@ -43,4 +45,10 @@ public class FakeConfigurationController
public String getNightModeName() {
return "undefined";
}
+
+ @Override
+ public void dispatchOnMovedToDisplay(int newDisplayId,
+ @NonNull Configuration newConfiguration) {
+
+ }
}