summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt28
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java12
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt4
5 files changed, 59 insertions, 18 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
index 54a98ddaa01a..a7d4375362d3 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettings.kt
@@ -16,6 +16,8 @@
package com.android.systemui.qs.ui.composable
+import android.view.ViewGroup
+import android.widget.FrameLayout
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth
@@ -164,11 +166,8 @@ private fun QuickSettingsContent(
state: () -> QSSceneAdapter.State,
modifier: Modifier = Modifier,
) {
- val qsView by qsSceneAdapter.qsView.collectAsStateWithLifecycle(null)
- val isCustomizing by
- qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle(
- qsSceneAdapter.isCustomizerShowing.value
- )
+ val qsView by qsSceneAdapter.qsView.collectAsStateWithLifecycle()
+ val isCustomizing by qsSceneAdapter.isCustomizerShowing.collectAsStateWithLifecycle()
QuickSettingsTheme {
val context = LocalContext.current
@@ -184,11 +183,24 @@ private fun QuickSettingsContent(
) {
AndroidView(
modifier = Modifier.fillMaxWidth(),
- factory = { _ ->
+ factory = { context ->
+ qsSceneAdapter.setState(state())
+ FrameLayout(context).apply {
+ (view.parent as? ViewGroup)?.removeView(view)
+ addView(view)
+ }
+ },
+ // When the view changes (e.g. due to a theme change), this will be recomposed
+ // if needed and the new view will be attached to the FrameLayout here.
+ update = {
qsSceneAdapter.setState(state())
- view
+ if (view.parent != it) {
+ it.removeAllViews()
+ (view.parent as? ViewGroup)?.removeView(view)
+ it.addView(view)
+ }
},
- update = { qsSceneAdapter.setState(state()) }
+ onRelease = { it.removeAllViews() }
)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 583cfb9ab47e..bd1d709b086a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -93,6 +93,8 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
private final Provider<QSLongPressEffect> mLongPressEffectProvider;
+ private boolean mDestroyed = false;
+
@VisibleForTesting
protected final QSPanel.OnConfigurationChangedListener mOnConfigurationChangedListener =
new QSPanel.OnConfigurationChangedListener() {
@@ -192,7 +194,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
// will remove the attach listener. We don't need to do that, because once this object is
// detached from the graph, it will be gc.
mHost.removeCallback(mQSHostCallback);
-
+ mDestroyed = true;
for (TileRecord record : mRecords) {
record.tile.removeCallback(record.callback);
mView.removeTile(record);
@@ -242,6 +244,7 @@ public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewContr
/** */
public void setTiles(Collection<QSTile> tiles, boolean collapsedView) {
+ if (mDestroyed) return;
// TODO(b/168904199): move this logic into QSPanelController.
if (!collapsedView && mQsTileRevealController != null) {
mQsTileRevealController.updateRevealedTiles(tiles);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
index fb872d538e6c..a30360eb8280 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/adapter/QSSceneAdapter.kt
@@ -46,7 +46,6 @@ import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.BufferOverflow
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -89,8 +88,10 @@ interface QSSceneAdapter {
/**
* A view with the QS content ([QSContainerImpl]), managed by an instance of [QSImpl] tracked by
* the interactor.
+ *
+ * A null value means that there is no inflated view yet. See [inflate].
*/
- val qsView: Flow<View>
+ val qsView: StateFlow<View?>
/** Sets the [MirrorController] in [QSImpl]. Set to `null` to remove. */
fun setBrightnessMirrorController(mirrorController: MirrorController?)
@@ -141,14 +142,24 @@ interface QSSceneAdapter {
override val squishiness = { 1f }
}
- /** State for appearing QQS from Lockscreen or Gone */
- data class UnsquishingQQS(override val squishiness: () -> Float) : State {
+ /**
+ * State for appearing QQS from Lockscreen or Gone.
+ *
+ * This should not be a data class, as it has a method parameter and even if it's the same
+ * lambda the output value may have changed.
+ */
+ class UnsquishingQQS(override val squishiness: () -> Float) : State {
override val isVisible = true
override val expansion = 0f
}
- /** State for appearing QS from Lockscreen or Gone, used in Split shade */
- data class UnsquishingQS(override val squishiness: () -> Float) : State {
+ /**
+ * State for appearing QS from Lockscreen or Gone, used in Split shade.
+ *
+ * This should not be a data class, as it has a method parameter and even if it's the same
+ * lambda the output value may have changed.
+ */
+ class UnsquishingQS(override val squishiness: () -> Float) : State {
override val isVisible = true
override val expansion = 1f
}
@@ -236,7 +247,10 @@ constructor(
private val _qsImpl: MutableStateFlow<QSImpl?> = MutableStateFlow(null)
val qsImpl = _qsImpl.asStateFlow()
- override val qsView: Flow<View> = _qsImpl.map { it?.view }.filterNotNull()
+ override val qsView: StateFlow<View?> =
+ _qsImpl
+ .map { it?.view }
+ .stateIn(applicationScope, SharingStarted.WhileSubscribed(), _qsImpl.value?.view)
override val qqsHeight: Int
get() = qsImpl.value?.qqsHeight ?: 0
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index 542bfaaa8484..7c5bc7196b24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -502,4 +502,16 @@ public class QSPanelControllerBaseTest extends SysuiTestCase {
verify(mQSPanel, times(2)).removeTile(any());
verify(mQSPanel, times(2)).addTile(any());
}
+
+ @Test
+ public void dettach_destroy_attach_tilesAreNotReadded() {
+ when(mQSHost.getTiles()).thenReturn(List.of(mQSTile, mOtherTile));
+ mController.setTiles();
+
+ mController.onViewDetached();
+ mController.destroy();
+ mController.onViewAttached();
+
+ assertThat(mController.mRecords).isEmpty();
+ }
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
index e0f60e9b3a01..7553bf0c20ef 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/ui/adapter/FakeQSSceneAdapter.kt
@@ -19,8 +19,8 @@ package com.android.systemui.qs.ui.adapter
import android.content.Context
import android.view.View
import com.android.systemui.settings.brightness.MirrorController
-import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
@@ -41,7 +41,7 @@ class FakeQSSceneAdapter(
override val customizerAnimationDuration = _animationDuration.asStateFlow()
private val _view = MutableStateFlow<View?>(null)
- override val qsView: Flow<View> = _view.filterNotNull()
+ override val qsView: StateFlow<View?> = _view.asStateFlow()
private val _state = MutableStateFlow<QSSceneAdapter.State?>(null)
val state = _state.filterNotNull()