Merge changes from topic "374107471" into main

* changes:
  Trigger configuration listener after reattach
  Fix crash when folding with open shade
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 58801e0..e725ce5 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
@@ -128,10 +128,10 @@
                         QSSceneAdapter.State.QS
                     }
                     else ->
-                        error(
-                            "Bad transition for QuickSettings: fromContent=$fromContent," +
-                                " toScene=$toContent"
-                        )
+                        // We are not in a transition between states that have QS, so just make
+                        // sure it's closed. This could be an issue if going from SplitShade to
+                        // a folded device.
+                        QSSceneAdapter.State.CLOSED
                 }
             }
         is TransitionState.Transition.OverlayTransition ->
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index 527aeaa..83f95ea 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -28,6 +28,8 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
@@ -604,6 +606,46 @@
         assertThat(mPagedTileLayoutListening).isFalse();
     }
 
+    @Test
+    public void reAttach_configurationChangePending_triggersConfigurationListener() {
+        mController.onViewDetached();
+
+        when(mQSPanel.hadConfigurationChangeWhileDetached()).thenReturn(true);
+        clearInvocations(mQSLogger);
+
+        mController.onViewAttached();
+
+        verify(mQSLogger).logOnConfigurationChanged(
+                anyInt(),
+                anyInt(),
+                anyBoolean(),
+                anyBoolean(),
+                anyInt(),
+                anyInt(),
+                anyString()
+        );
+    }
+
+    @Test
+    public void reAttach_noConfigurationChangePending_doesntTriggerConfigurationListener() {
+        mController.onViewDetached();
+
+        when(mQSPanel.hadConfigurationChangeWhileDetached()).thenReturn(false);
+        clearInvocations(mQSLogger);
+
+        mController.onViewAttached();
+
+        verify(mQSLogger, never()).logOnConfigurationChanged(
+                anyInt(),
+                anyInt(),
+                anyBoolean(),
+                anyBoolean(),
+                anyInt(),
+                anyInt(),
+                anyString()
+        );
+    }
+
 
     private boolean usingMediaPlayer() {
         return !SceneContainerFlag.isEnabled();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index d3bed27..602f593 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -116,6 +116,8 @@
     @Nullable
     private View mMediaViewPlaceHolderForScene;
 
+    private boolean mHadConfigurationChangeWhileDetached;
+
     public QSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
         mUsingMediaPlayer = useQsMediaPlayer(context);
@@ -425,10 +427,23 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        if (!isAttachedToWindow()) {
+            mHadConfigurationChangeWhileDetached = true;
+        }
         mOnConfigurationChangedListeners.forEach(
                 listener -> listener.onConfigurationChange(newConfig));
     }
 
+    final boolean hadConfigurationChangeWhileDetached() {
+        return mHadConfigurationChangeWhileDetached;
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mHadConfigurationChangeWhileDetached = false;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 6cf5b32..85bcc25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -234,6 +234,12 @@
             mMediaHost.addVisibilityChangeListener(mMediaHostVisibilityListener);
         }
         mView.addOnConfigurationChangedListener(mOnConfigurationChangedListener);
+        // We were not attached and the configuration may have changed, trigger the listener.
+        if (mView.hadConfigurationChangeWhileDetached()) {
+            mOnConfigurationChangedListener.onConfigurationChange(
+                    getContext().getResources().getConfiguration()
+            );
+        }
         setTiles();
         mLastOrientation = getResources().getConfiguration().orientation;
         mLastScreenLayout = getResources().getConfiguration().screenLayout;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index 8aaa121..3c922dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -13,6 +13,7 @@
  */
 package com.android.systemui.qs
 
+import android.content.res.Configuration
 import android.graphics.Rect
 import android.platform.test.flag.junit.FlagsParameterization
 import android.testing.TestableContext
@@ -91,7 +92,9 @@
 
     @After
     fun tearDown() {
-        ViewUtils.detachView(qsPanel)
+        if (qsPanel.isAttachedToWindow) {
+            ViewUtils.detachView(qsPanel)
+        }
     }
 
     @Test
@@ -119,7 +122,7 @@
         qsPanel.tileLayout?.addTile(
             QSPanelControllerBase.TileRecord(
                 mock(QSTile::class.java),
-                QSTileViewImpl(themedContext)
+                QSTileViewImpl(themedContext),
             )
         )
 
@@ -129,7 +132,7 @@
         qsPanel.setUsingHorizontalLayout(/* horizontal */ true, mediaView, /* force */ true)
         qsPanel.measure(
             /* width */ View.MeasureSpec.makeMeasureSpec(3000, View.MeasureSpec.EXACTLY),
-            /* height */ View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY)
+            /* height */ View.MeasureSpec.makeMeasureSpec(1000, View.MeasureSpec.EXACTLY),
         )
         qsPanel.layout(0, 0, qsPanel.measuredWidth, qsPanel.measuredHeight)
 
@@ -147,7 +150,7 @@
         val padding = 10
         themedContext.orCreateTestableResources.addOverride(
             R.dimen.qs_panel_padding_bottom,
-            padding
+            padding,
         )
         qsPanel.updatePadding()
         assertThat(qsPanel.paddingBottom).isEqualTo(padding)
@@ -160,7 +163,7 @@
         themedContext.orCreateTestableResources.addOverride(R.dimen.qs_panel_padding_top, padding)
         themedContext.orCreateTestableResources.addOverride(
             R.dimen.qs_panel_padding_top,
-            paddingCombined
+            paddingCombined,
         )
 
         qsPanel.updatePadding()
@@ -267,6 +270,62 @@
         assertThat(qsPanel.tileLayout!!.maxColumns).isEqualTo(2)
     }
 
+    @Test
+    fun noPendingConfigChangesAtBeginning() {
+        assertThat(qsPanel.hadConfigurationChangeWhileDetached()).isFalse()
+    }
+
+    @Test
+    fun configChangesWhileDetached_pendingConfigChanges() {
+        ViewUtils.detachView(qsPanel)
+
+        qsPanel.onConfigurationChanged(Configuration())
+
+        assertThat(qsPanel.hadConfigurationChangeWhileDetached()).isTrue()
+    }
+
+    @Test
+    fun configChangesWhileDetached_reattach_pendingConfigChanges() {
+        ViewUtils.detachView(qsPanel)
+
+        qsPanel.onConfigurationChanged(Configuration())
+        testableLooper.runWithLooper { ViewUtils.attachView(qsPanel) }
+
+        assertThat(qsPanel.hadConfigurationChangeWhileDetached()).isTrue()
+    }
+
+    @Test
+    fun configChangesWhileDetached_reattach_detach_pendingConfigChanges_reset() {
+        ViewUtils.detachView(qsPanel)
+
+        qsPanel.onConfigurationChanged(Configuration())
+
+        testableLooper.runWithLooper { ViewUtils.attachView(qsPanel) }
+        ViewUtils.detachView(qsPanel)
+
+        assertThat(qsPanel.hadConfigurationChangeWhileDetached()).isFalse()
+    }
+
+    @Test
+    fun configChangeWhileAttached_noPendingConfigChanges() {
+        qsPanel.onConfigurationChanged(Configuration())
+
+        assertThat(qsPanel.hadConfigurationChangeWhileDetached()).isFalse()
+    }
+
+    @Test
+    fun configChangeWhileAttachedWithPending_doesntResetPending() {
+        ViewUtils.detachView(qsPanel)
+
+        qsPanel.onConfigurationChanged(Configuration())
+
+        testableLooper.runWithLooper { ViewUtils.attachView(qsPanel) }
+
+        qsPanel.onConfigurationChanged(Configuration())
+
+        assertThat(qsPanel.hadConfigurationChangeWhileDetached()).isTrue()
+    }
+
     companion object {
         @Parameters(name = "{0}") @JvmStatic fun getParams() = parameterizeSceneContainerFlag()
     }