Apply insets (nav bar)

This is applied to QS, as well as passed down to the RecyclerView so it
can show content behind the nav bar.

Test: atest QSScenAdapterImplTest
Fixes: 316571756
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: I3761a32675dec05b002231df73a199b4f8893c36
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 1cbc992..46554a4 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -29,10 +29,13 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.WindowInsets
+import androidx.compose.foundation.layout.asPaddingValues
 import androidx.compose.foundation.layout.fillMaxHeight
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.navigationBars
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.rememberScrollState
@@ -125,6 +128,9 @@
             remember(lifecycleOwner, viewModel) {
                 viewModel.getFooterActionsViewModel(lifecycleOwner)
             }
+
+        // ############## SCROLLING ################
+
         val scrollState = rememberScrollState()
         // When animating into the scene, we don't want it to be able to scroll, as it could mess
         // up with the expansion animation.
@@ -142,6 +148,18 @@
             }
         }
 
+        // ############# NAV BAR paddings ###############
+
+        val navBarBottomHeight =
+            WindowInsets.navigationBars.asPaddingValues().calculateBottomPadding()
+        val density = LocalDensity.current
+
+        LaunchedEffect(navBarBottomHeight, density) {
+            with(density) {
+                viewModel.qsSceneAdapter.applyBottomNavBarPadding(navBarBottomHeight.roundToPx())
+            }
+        }
+
         // This is the background for the whole scene, as the elements don't necessarily provide
         // a background that extends to the edges.
         Spacer(
@@ -154,8 +172,13 @@
             horizontalAlignment = Alignment.CenterHorizontally,
             modifier =
                 Modifier.fillMaxSize()
-                    // bottom should be tied to insets
-                    .padding(bottom = 16.dp)
+                    .then(
+                        if (isCustomizing) {
+                            Modifier.padding(top = 48.dp)
+                        } else {
+                            Modifier.padding(bottom = navBarBottomHeight)
+                        }
+                    )
         ) {
             Box(modifier = Modifier.fillMaxSize().weight(1f)) {
                 val shadeHeaderAndQuickSettingsModifier =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
index cae20d0..f8573cc2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/ui/adapter/QSSceneAdapterImplTest.kt
@@ -414,4 +414,56 @@
             verify(qsImpl!!).onConfigurationChanged(configuration)
             verify(qsImpl!!.view).dispatchConfigurationChanged(configuration)
         }
+
+    @Test
+    fun dispatchNavBarSize_beforeInflation() =
+        testScope.runTest {
+            runCurrent()
+            val navBarHeight = 171
+
+            val qsImpl by collectLastValue(underTest.qsImpl)
+
+            underTest.applyBottomNavBarPadding(navBarHeight)
+            underTest.inflate(context)
+            runCurrent()
+
+            verify(qsImpl!!).applyBottomNavBarToCustomizerPadding(navBarHeight)
+        }
+
+    @Test
+    fun dispatchNavBarSize_afterInflation() =
+        testScope.runTest {
+            runCurrent()
+            val navBarHeight = 171
+
+            val qsImpl by collectLastValue(underTest.qsImpl)
+
+            underTest.inflate(context)
+            runCurrent()
+
+            underTest.applyBottomNavBarPadding(navBarHeight)
+            runCurrent()
+
+            verify(qsImpl!!).applyBottomNavBarToCustomizerPadding(navBarHeight)
+        }
+
+    @Test
+    fun dispatchNavBarSize_reinflation() =
+        testScope.runTest {
+            runCurrent()
+            val navBarHeight = 171
+
+            val qsImpl by collectLastValue(underTest.qsImpl)
+
+            underTest.inflate(context)
+            runCurrent()
+
+            underTest.applyBottomNavBarPadding(navBarHeight)
+            runCurrent()
+
+            underTest.inflate(context)
+            runCurrent()
+
+            verify(qsImpl!!).applyBottomNavBarToCustomizerPadding(navBarHeight)
+        }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
index 4d55714..8ff0e36 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSImpl.java
@@ -992,6 +992,15 @@
         return mContainer.getQsHeight();
     }
 
+    /**
+     * Pass the size of the navbar when it's at the bottom of the device so it can be used as
+     * padding
+     * @param padding size of the bottom nav bar in px
+     */
+    public void applyBottomNavBarToCustomizerPadding(int padding) {
+        mQSCustomizerController.applyBottomNavBarSizeToRecyclerViewPadding(padding);
+    }
+
     @NeverCompile
     @Override
     public void dump(PrintWriter pw, String[] args) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 07705f3..f8d4080 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -65,6 +65,8 @@
     private boolean mOpening;
     private boolean mIsShowingNavBackdrop;
 
+    private boolean mSceneContainerEnabled;
+
     public QSCustomizer(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -88,6 +90,28 @@
         updateTransparentViewHeight();
     }
 
+    void applyBottomNavBarToPadding(int padding) {
+        mRecyclerView.setPadding(
+                /* left= */ mRecyclerView.getPaddingLeft(),
+                /* top= */ mRecyclerView.getPaddingTop(),
+                /* right= */ mRecyclerView.getPaddingRight(),
+                /* bottom= */ padding
+        );
+    }
+
+    void setSceneContainerEnabled(boolean enabled) {
+        if (enabled != mSceneContainerEnabled) {
+            mSceneContainerEnabled = enabled;
+            updateTransparentViewHeight();
+            if (mSceneContainerEnabled) {
+                findViewById(R.id.nav_bar_background).setVisibility(View.GONE);
+            } else {
+                findViewById(R.id.nav_bar_background)
+                        .setVisibility(mIsShowingNavBackdrop ? View.VISIBLE : View.GONE);
+            }
+        }
+    }
+
     void updateResources() {
         updateTransparentViewHeight();
         mRecyclerView.getAdapter().notifyItemChanged(0);
@@ -98,7 +122,8 @@
         mIsShowingNavBackdrop = newConfig.smallestScreenWidthDp >= 600
                 || newConfig.orientation != Configuration.ORIENTATION_LANDSCAPE;
         if (navBackdrop != null) {
-            navBackdrop.setVisibility(mIsShowingNavBackdrop ? View.VISIBLE : View.GONE);
+            navBackdrop.setVisibility(
+                    mIsShowingNavBackdrop && !mSceneContainerEnabled ? View.VISIBLE : View.GONE);
         }
         updateNavColors(lightBarController);
     }
@@ -275,7 +300,7 @@
 
     private void updateTransparentViewHeight() {
         LayoutParams lp = (LayoutParams) mTransparentView.getLayoutParams();
-        lp.height = QSUtils.getQsHeaderSystemIconsAreaHeight(mContext);
+        lp.height = mSceneContainerEnabled ? 0 : QSUtils.getQsHeaderSystemIconsAreaHeight(mContext);
         mTransparentView.setLayoutParams(lp);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
index c28371c..34b1b2d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -42,6 +42,7 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.res.R;
+import com.android.systemui.scene.shared.flag.SceneContainerFlags;
 import com.android.systemui.statusbar.phone.LightBarController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
@@ -106,7 +107,8 @@
     protected QSCustomizerController(QSCustomizer view, TileQueryHelper tileQueryHelper,
             QSHost qsHost, TileAdapter tileAdapter, ScreenLifecycle screenLifecycle,
             KeyguardStateController keyguardStateController, LightBarController lightBarController,
-            ConfigurationController configurationController, UiEventLogger uiEventLogger) {
+            ConfigurationController configurationController, UiEventLogger uiEventLogger,
+            SceneContainerFlags sceneContainerFlags) {
         super(view);
         mTileQueryHelper = tileQueryHelper;
         mQsHost = qsHost;
@@ -116,10 +118,14 @@
         mLightBarController = lightBarController;
         mConfigurationController = configurationController;
         mUiEventLogger = uiEventLogger;
+        view.setSceneContainerEnabled(sceneContainerFlags.isEnabled());
 
         mToolbar = mView.findViewById(com.android.internal.R.id.action_bar);
     }
 
+    public void applyBottomNavBarSizeToRecyclerViewPadding(int padding) {
+        mView.applyBottomNavBarToPadding(padding);
+    }
 
     @Override
     protected void onViewAttached() {
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 3d12eed..6e4f72d 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
@@ -39,10 +39,13 @@
 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.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.launch
@@ -69,6 +72,9 @@
     /** Set the current state for QS. [state]. */
     fun setState(state: State)
 
+    /** Propagates the bottom nav bar size to [QSImpl] to be used as necessary. */
+    suspend fun applyBottomNavBarPadding(padding: Int)
+
     /** The current height of QQS in the current [qsView], or 0 if there's no view. */
     val qqsHeight: Int
 
@@ -123,6 +129,11 @@
         ::AsyncLayoutInflater,
     )
 
+    private val bottomNavBarSize =
+        MutableSharedFlow<Int>(
+            extraBufferCapacity = 1,
+            onBufferOverflow = BufferOverflow.DROP_OLDEST,
+        )
     private val state = MutableStateFlow<QSSceneAdapter.State>(QSSceneAdapter.State.CLOSED)
     private val _isCustomizing: MutableStateFlow<Boolean> = MutableStateFlow(false)
     override val isCustomizing = _isCustomizing.asStateFlow()
@@ -168,6 +179,11 @@
                     }
                 }
             }
+            launch {
+                combine(bottomNavBarSize, qsImpl.filterNotNull(), ::Pair).collect {
+                    it.second.applyBottomNavBarToCustomizerPadding(it.first)
+                }
+            }
         }
     }
 
@@ -208,6 +224,10 @@
         this.state.value = state
     }
 
+    override suspend fun applyBottomNavBarPadding(padding: Int) {
+        bottomNavBarSize.emit(padding)
+    }
+
     private fun QSImpl.applyState(state: QSSceneAdapter.State) {
         setQsVisible(state.isVisible)
         setExpanded(state.isVisible)
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 8e430db..b1581d1 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
@@ -38,6 +38,9 @@
     private val _state = MutableStateFlow<QSSceneAdapter.State?>(null)
     val state = _state.filterNotNull()
 
+    private val _navBarPadding = MutableStateFlow<Int>(0)
+    val navBarPadding = _navBarPadding.asStateFlow()
+
     override suspend fun inflate(context: Context) {
         _view.value = inflateDelegate(context)
     }
@@ -51,4 +54,8 @@
     fun setCustomizing(value: Boolean) {
         _customizing.value = value
     }
+
+    override suspend fun applyBottomNavBarPadding(padding: Int) {
+        _navBarPadding.value = padding
+    }
 }