Merge changes from topic "216302612"

* changes:
  Change footer action buttons
  Pin footer actions to bottom of QSContainerImpl
  Remove QQS Footer Actions
diff --git a/packages/SystemUI/res-keyguard/layout/footer_actions.xml b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
index ecb3cb3..339cab4 100644
--- a/packages/SystemUI/res-keyguard/layout/footer_actions.xml
+++ b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
@@ -19,8 +19,10 @@
 <com.android.systemui.qs.FooterActionsView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="48dp"
-    android:gravity="center_vertical">
+    android:layout_height="@dimen/qs_footer_height"
+    android:gravity="center_vertical"
+    android:layout_gravity="bottom"
+>
 
     <com.android.systemui.statusbar.phone.MultiUserSwitch
         android:id="@+id/multi_user_switch"
diff --git a/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml b/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml
new file mode 100644
index 0000000..95bdd89
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/new_footer_actions.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+** Copyright 2022, 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.
+-->
+
+<!-- Action buttons for footer in QS/QQS, containing settings button, power off button etc -->
+<com.android.systemui.qs.FooterActionsView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/qs_footer_height"
+    android:gravity="center_vertical"
+    android:layout_gravity="bottom"
+>
+
+    <View
+        android:layout_height="1dp"
+        android:layout_width="0dp"
+        android:layout_weight="1"
+        />
+
+    <LinearLayout
+        android:layout_height="match_parent"
+        android:layout_width="wrap_content"
+        >
+
+        <com.android.systemui.statusbar.phone.MultiUserSwitch
+            android:id="@+id/multi_user_switch"
+            android:layout_width="@dimen/qs_footer_action_button_size"
+            android:layout_height="@dimen/qs_footer_action_button_size"
+            android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+            android:background="@drawable/qs_footer_action_circle"
+            android:focusable="true">
+
+            <ImageView
+                android:id="@+id/multi_user_avatar"
+                android:layout_width="@dimen/multi_user_avatar_expanded_size"
+                android:layout_height="@dimen/multi_user_avatar_expanded_size"
+                android:layout_gravity="center"
+                android:scaleType="centerInside" />
+        </com.android.systemui.statusbar.phone.MultiUserSwitch>
+
+        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+            android:id="@+id/settings_button_container"
+            android:layout_width="@dimen/qs_footer_action_button_size"
+            android:layout_height="@dimen/qs_footer_action_button_size"
+            android:layout_marginEnd="@dimen/qs_tile_margin_horizontal"
+            android:background="@drawable/qs_footer_action_circle"
+            android:clipChildren="false"
+            android:clipToPadding="false">
+
+            <com.android.systemui.statusbar.phone.SettingsButton
+                android:id="@+id/settings_button"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/qs_footer_action_button_size"
+                android:layout_gravity="center"
+                android:background="@android:color/transparent"
+                android:contentDescription="@string/accessibility_quick_settings_settings"
+                android:padding="@dimen/qs_footer_icon_padding"
+                android:scaleType="centerInside"
+                android:src="@drawable/ic_settings"
+                android:tint="?android:attr/textColorPrimary" />
+
+            <com.android.systemui.statusbar.AlphaOptimizedImageView
+                android:id="@+id/tuner_icon"
+                android:layout_width="8dp"
+                android:layout_height="8dp"
+                android:layout_gravity="center_horizontal|bottom"
+                android:layout_marginBottom="@dimen/qs_footer_icon_padding"
+                android:src="@drawable/tuner"
+                android:tint="?android:attr/textColorTertiary"
+                android:visibility="invisible" />
+
+        </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:id="@+id/pm_lite"
+            android:layout_width="@dimen/qs_footer_action_button_size"
+            android:layout_height="@dimen/qs_footer_action_button_size"
+            android:background="@drawable/qs_footer_action_circle_color"
+            android:clickable="true"
+            android:clipToPadding="false"
+            android:focusable="true"
+            android:padding="@dimen/qs_footer_icon_padding"
+            android:src="@*android:drawable/ic_lock_power_off"
+            android:contentDescription="@string/accessibility_quick_settings_power_menu"
+            android:tint="?androidprv:attr/textColorOnAccent" />
+
+    </LinearLayout>
+</com.android.systemui.qs.FooterActionsView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
new file mode 100644
index 0000000..f54c30f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetTop="@dimen/qs_footer_action_inset"
+    android:insetBottom="@dimen/qs_footer_action_inset"
+    android:insetLeft="@dimen/qs_footer_action_inset"
+    android:insetRight="@dimen/qs_footer_action_inset">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item android:id="@android:id/mask">
+            <shape android:shape="oval">
+                <solid android:color="@android:color/white"/>
+            </shape>
+        </item>
+        <item>
+            <shape android:shape="oval">
+                <solid android:color="?attr/offStateColor"/>
+            </shape>
+        </item>
+
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
new file mode 100644
index 0000000..1a323bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable/qs_footer_action_circle_color.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetTop="@dimen/qs_footer_action_inset"
+    android:insetBottom="@dimen/qs_footer_action_inset"
+    android:insetLeft="@dimen/qs_footer_action_inset"
+    android:insetRight="@dimen/qs_footer_action_inset">
+    <ripple
+        android:color="?android:attr/colorControlHighlight">
+        <item android:id="@android:id/mask">
+            <shape android:shape="oval">
+                <solid android:color="@android:color/white"/>
+            </shape>
+        </item>
+        <item>
+            <shape android:shape="oval">
+                <solid android:color="?android:attr/colorAccent"/>
+            </shape>
+        </item>
+
+    </ripple>
+</inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml
index 5cd9e94..b6e3499 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -19,7 +19,7 @@
 <com.android.systemui.qs.QSFooterView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/qs_footer"
     android:layout_width="match_parent"
-    android:layout_height="@dimen/qs_footer_height"
+    android:layout_height="wrap_content"
     android:layout_marginStart="@dimen/qs_footer_margin"
     android:layout_marginEnd="@dimen/qs_footer_margin"
     android:layout_marginBottom="@dimen/qs_footers_margin_bottom"
@@ -36,7 +36,7 @@
 
         <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="48dp"
+            android:layout_height="@dimen/qs_footer_height"
             android:layout_gravity="center_vertical">
 
             <TextView
@@ -80,8 +80,13 @@
 
         </LinearLayout>
 
-        <include layout="@layout/footer_actions"
-            android:id="@+id/qs_footer_actions"/>
+        <ViewStub
+            android:id="@+id/footer_stub"
+            android:inflatedId="@+id/qs_footer_actions"
+            android:layout="@layout/footer_actions"
+            android:layout_height="@dimen/qs_footer_height"
+            android:layout_width="match_parent"
+        />
 
     </LinearLayout>
 
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index f5c6036..22abd0c 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -51,6 +51,15 @@
         android:id="@+id/qs_detail"
         layout="@layout/qs_detail" />
 
+    <ViewStub
+        android:id="@+id/container_stub"
+        android:inflatedId="@+id/qs_footer_actions"
+        android:layout="@layout/new_footer_actions"
+        android:layout_height="@dimen/qs_footer_height"
+        android:layout_width="match_parent"
+        android:layout_gravity="bottom"
+        />
+
     <include
         android:id="@+id/qs_customize"
         layout="@layout/qs_customize_panel"
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 10a2f4c..2c29f07 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -57,16 +57,6 @@
             android:focusable="true"
             android:paddingBottom="24dp"
             android:importantForAccessibility="yes">
-
-            <include
-                layout="@layout/footer_actions"
-                android:id="@+id/qqs_footer_actions"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginTop="@dimen/qqs_layout_margin_top"
-                android:layout_marginStart="@dimen/qs_footer_margin"
-                android:layout_marginEnd="@dimen/qs_footer_margin"
-                />
         </com.android.systemui.qs.QuickQSPanel>
     </RelativeLayout>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 74bb9e4..dba7290 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -327,7 +327,7 @@
 
     <!-- The height of the quick settings footer that holds the user switcher, settings icon,
          etc. -->
-    <dimen name="qs_footer_height">96dp</dimen>
+    <dimen name="qs_footer_height">48dp</dimen>
 
     <!-- The size of each of the icon buttons in the QS footer -->
     <dimen name="qs_footer_action_button_size">48dp</dimen>
@@ -491,7 +491,7 @@
     <dimen name="qs_tile_text_size">14sp</dimen>
     <dimen name="qs_panel_padding">16dp</dimen>
     <dimen name="qs_dual_tile_padding_horizontal">6dp</dimen>
-    <dimen name="qs_panel_padding_bottom">0dp</dimen>
+    <dimen name="qs_panel_padding_bottom">@dimen/qs_footer_height</dimen>
     <dimen name="qs_panel_padding_top">48dp</dimen>
     <dimen name="qs_detail_header_padding">0dp</dimen>
     <dimen name="qs_detail_image_width">56dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index c894b70..357a68f 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -107,6 +107,8 @@
     public static final ResourceBooleanFlag QS_USER_DETAIL_SHORTCUT =
             new ResourceBooleanFlag(503, R.bool.flag_lockscreen_qs_user_detail_shortcut);
 
+    public static final BooleanFlag NEW_FOOTER = new BooleanFlag(504, false);
+
     /***************************************/
     // 600- status bar
     public static final BooleanFlag COMBINED_STATUS_BAR_SIGNAL_ICONS =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index 7ac9205..4aedbc9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -29,14 +29,16 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.internal.logging.nano.MetricsProto
 import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.animation.ActivityLaunchAnimator
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.globalactions.GlobalActionsDialogLite
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.qs.FooterActionsController.ExpansionState.COLLAPSED
-import com.android.systemui.qs.FooterActionsController.ExpansionState.EXPANDED
 import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED
+import com.android.systemui.qs.dagger.QSScope
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.phone.SettingsButton
@@ -54,13 +56,14 @@
  * Main difference between QS and QQS behaviour is condition when buttons should be visible,
  * determined by [buttonsVisibleState]
  */
+@QSScope
 class FooterActionsController @Inject constructor(
     view: FooterActionsView,
+    multiUserSwitchControllerFactory: MultiUserSwitchController.Factory,
     private val activityStarter: ActivityStarter,
     private val userManager: UserManager,
     private val userTracker: UserTracker,
     private val userInfoController: UserInfoController,
-    private val multiUserSwitchController: MultiUserSwitchController,
     private val deviceProvisionedController: DeviceProvisionedController,
     private val falsingManager: FalsingManager,
     private val metricsLogger: MetricsLogger,
@@ -68,20 +71,34 @@
     private val globalActionsDialog: GlobalActionsDialogLite,
     private val uiEventLogger: UiEventLogger,
     @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
-    private val buttonsVisibleState: ExpansionState,
     private val globalSetting: GlobalSettings,
-    private val handler: Handler
+    private val handler: Handler,
+    private val featureFlags: FeatureFlags
 ) : ViewController<FooterActionsView>(view) {
 
-    enum class ExpansionState { COLLAPSED, EXPANDED }
-
+    private var lastExpansion = -1f
     private var listening: Boolean = false
 
-    var expanded = false
+    private val alphaAnimator = TouchAnimator.Builder()
+            .addFloat(mView, "alpha", 0f, 1f)
+            .setStartDelay(0.9f)
+            .build()
+
+    var visible = true
+        set(value) {
+            field = value
+            updateVisibility()
+        }
+
+    init {
+        view.elevation = resources.displayMetrics.density * 4f
+        view.setBackgroundColor(Utils.getColorAttrDefaultColor(context, R.attr.underSurfaceColor))
+    }
 
     private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button)
     private val settingsButtonContainer: View? = view.findViewById(R.id.settings_button_container)
     private val powerMenuLite: View = view.findViewById(R.id.pm_lite)
+    private val multiUserSwitchController = multiUserSwitchControllerFactory.create(view)
 
     private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ ->
         val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser())
@@ -99,9 +116,8 @@
             }
 
     private val onClickListener = View.OnClickListener { v ->
-        // Don't do anything until views are unhidden. Don't do anything if the tap looks
-        // suspicious.
-        if (!buttonsVisible() || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+        // Don't do anything if the tap looks suspicious.
+        if (!visible || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
             return@OnClickListener
         }
         if (v === settingsButton) {
@@ -110,9 +126,7 @@
                 activityStarter.postQSRunnableDismissingKeyguard {}
                 return@OnClickListener
             }
-            metricsLogger.action(
-                    if (expanded) MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH
-                    else MetricsProto.MetricsEvent.ACTION_QS_COLLAPSED_SETTINGS_LAUNCH)
+            metricsLogger.action(MetricsProto.MetricsEvent.ACTION_QS_EXPANDED_SETTINGS_LAUNCH)
             if (settingsButton.isTunerClick) {
                 activityStarter.postQSRunnableDismissingKeyguard {
                     if (isTunerEnabled()) {
@@ -135,24 +149,14 @@
         }
     }
 
-    private fun buttonsVisible(): Boolean {
-        return when (buttonsVisibleState) {
-            EXPANDED -> expanded
-            COLLAPSED -> !expanded
-        }
-    }
-
     override fun onInit() {
         multiUserSwitchController.init()
     }
 
-    fun hideFooter() {
-        mView.visibility = View.GONE
-    }
-
-    fun showFooter() {
-        mView.visibility = View.VISIBLE
-        updateView()
+    private fun updateVisibility() {
+        val previousVisibility = mView.visibility
+        mView.visibility = if (visible) View.VISIBLE else View.INVISIBLE
+        if (previousVisibility != mView.visibility) updateView()
     }
 
     private fun startSettingsActivity() {
@@ -204,24 +208,23 @@
     }
 
     fun setExpansion(headerExpansionFraction: Float) {
-        mView.setExpansion(headerExpansionFraction)
-    }
-
-    fun updateAnimator(width: Int, numTiles: Int) {
-        mView.updateAnimator(width, numTiles)
-    }
-
-    fun setKeyguardShowing() {
-        mView.setKeyguardShowing()
-    }
-
-    fun refreshVisibility(shouldBeVisible: Boolean) {
-        if (shouldBeVisible) {
-            showFooter()
+        if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
+            if (headerExpansionFraction != lastExpansion) {
+                if (headerExpansionFraction >= 1f) {
+                    mView.animate().alpha(1f).setDuration(500L).start()
+                } else if (lastExpansion >= 1f && headerExpansionFraction < 1f) {
+                    mView.animate().alpha(0f).setDuration(250L).start()
+                }
+                lastExpansion = headerExpansionFraction
+            }
         } else {
-            hideFooter()
+            alphaAnimator.setPosition(headerExpansionFraction)
         }
     }
 
+    fun setKeyguardShowing(showing: Boolean) {
+        setExpansion(lastExpansion)
+    }
+
     private fun isTunerEnabled() = tunerService.isTunerEnabled
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt
deleted file mode 100644
index 7694be5..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2021 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.qs
-
-import android.os.Handler
-import android.os.UserManager
-import com.android.internal.logging.MetricsLogger
-import com.android.internal.logging.UiEventLogger
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.globalactions.GlobalActionsDialogLite
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.qs.FooterActionsController.ExpansionState
-import com.android.systemui.qs.dagger.QSFlagsModule
-import com.android.systemui.settings.UserTracker
-import com.android.systemui.statusbar.phone.MultiUserSwitchController
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.UserInfoController
-import com.android.systemui.tuner.TunerService
-import com.android.systemui.util.settings.GlobalSettings
-import javax.inject.Inject
-import javax.inject.Named
-
-class FooterActionsControllerBuilder @Inject constructor(
-    private val activityStarter: ActivityStarter,
-    private val userManager: UserManager,
-    private val userTracker: UserTracker,
-    private val userInfoController: UserInfoController,
-    private val multiUserSwitchControllerFactory: MultiUserSwitchController.Factory,
-    private val deviceProvisionedController: DeviceProvisionedController,
-    private val falsingManager: FalsingManager,
-    private val metricsLogger: MetricsLogger,
-    private val tunerService: TunerService,
-    private val globalActionsDialog: GlobalActionsDialogLite,
-    private val uiEventLogger: UiEventLogger,
-    @Named(QSFlagsModule.PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
-    private val globalSettings: GlobalSettings,
-    @Main private val handler: Handler
-) {
-    private lateinit var view: FooterActionsView
-    private lateinit var buttonsVisibleState: ExpansionState
-
-    fun withView(view: FooterActionsView): FooterActionsControllerBuilder {
-        this.view = view
-        return this
-    }
-
-    fun withButtonsVisibleWhen(state: ExpansionState): FooterActionsControllerBuilder {
-        buttonsVisibleState = state
-        return this
-    }
-
-    fun build(): FooterActionsController {
-        return FooterActionsController(view, activityStarter, userManager,
-                userTracker, userInfoController, multiUserSwitchControllerFactory.create(view),
-                deviceProvisionedController, falsingManager, metricsLogger, tunerService,
-                globalActionsDialog, uiEventLogger, showPMLiteButton, buttonsVisibleState,
-                globalSettings, handler)
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
index e6fa2ae..18e0cfa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
@@ -44,8 +44,6 @@
     private lateinit var multiUserAvatar: ImageView
     private lateinit var tunerIcon: View
 
-    private var settingsCogAnimator: TouchAnimator? = null
-
     private var qsDisabled = false
     private var expansionAmount = 0f
 
@@ -66,19 +64,6 @@
         importantForAccessibility = View.IMPORTANT_FOR_ACCESSIBILITY_YES
     }
 
-    fun updateAnimator(width: Int, numTiles: Int) {
-        val size = (mContext.resources.getDimensionPixelSize(R.dimen.qs_quick_tile_size) -
-                mContext.resources.getDimensionPixelSize(R.dimen.qs_tile_padding))
-        val remaining = (width - numTiles * size) / (numTiles - 1)
-        val defSpace = mContext.resources.getDimensionPixelOffset(R.dimen.default_gear_space)
-        val translation = if (isLayoutRtl) (remaining - defSpace) else -(remaining - defSpace)
-        settingsCogAnimator = TouchAnimator.Builder()
-                .addFloat(settingsButton, "translationX", translation.toFloat(), 0f)
-                .addFloat(settingsButton, "rotation", -120f, 0f)
-                .build()
-        setExpansion(expansionAmount)
-    }
-
     override fun onConfigurationChanged(newConfig: Configuration) {
         super.onConfigurationChanged(newConfig)
         updateResources()
@@ -95,15 +80,6 @@
         tunerIcon.translationX = if (isLayoutRtl) (-tunerIconTranslation) else tunerIconTranslation
     }
 
-    fun setKeyguardShowing() {
-        setExpansion(expansionAmount)
-    }
-
-    fun setExpansion(headerExpansionFraction: Float) {
-        expansionAmount = headerExpansionFraction
-        if (settingsCogAnimator != null) settingsCogAnimator!!.setPosition(headerExpansionFraction)
-    }
-
     fun disable(
         state2: Int,
         isTunerEnabled: Boolean,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index ded6ae0..d1b569f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,9 +14,6 @@
 
 package com.android.systemui.qs;
 
-import static com.android.systemui.qs.dagger.QSFragmentModule.QQS_FOOTER;
-import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FOOTER;
-
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.util.Log;
@@ -49,7 +46,6 @@
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
-import javax.inject.Named;
 
 /** */
 @QSScope
@@ -88,8 +84,6 @@
     private final QSFgsManagerFooter mFgsManagerFooter;
     private final QSSecurityFooter mSecurityFooter;
     private final QS mQs;
-    private final View mQSFooterActions;
-    private final View mQQSFooterActions;
 
     @Nullable
     private PagedTileLayout mPagedLayout;
@@ -154,16 +148,12 @@
             QuickQSPanelController quickQSPanelController, QSTileHost qsTileHost,
             QSFgsManagerFooter fgsManagerFooter, QSSecurityFooter securityFooter,
             @Main Executor executor, TunerService tunerService,
-            QSExpansionPathInterpolator qsExpansionPathInterpolator,
-            @Named(QS_FOOTER) FooterActionsView qsFooterActionsView,
-            @Named(QQS_FOOTER) FooterActionsView qqsFooterActionsView) {
+            QSExpansionPathInterpolator qsExpansionPathInterpolator) {
         mQs = qs;
         mQuickQsPanel = quickPanel;
         mQsPanelController = qsPanelController;
         mQuickQSPanelController = quickQSPanelController;
         mQuickStatusBarHeader = quickStatusBarHeader;
-        mQQSFooterActions = qqsFooterActionsView;
-        mQSFooterActions = qsFooterActionsView;
         mFgsManagerFooter = fgsManagerFooter;
         mSecurityFooter = securityFooter;
         mHost = qsTileHost;
@@ -476,12 +466,6 @@
                     .setListener(this)
                     .build();
 
-            if (mQQSFooterActions.getVisibility() != View.GONE) {
-                // only when qqs footer is present (which means split shade mode) it needs to
-                // be animated
-                updateQQSFooterAnimation();
-            }
-
             // Fade in the security footer and the divider as we reach the final position
             Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
             builder.addFloat(mFgsManagerFooter.getView(), "alpha", 0, 1);
@@ -627,14 +611,6 @@
         }
     }
 
-    private void updateQQSFooterAnimation() {
-        int translationY = getRelativeTranslationY(mQSFooterActions, mQQSFooterActions);
-        mQQSFooterActionsAnimator = new TouchAnimator.Builder()
-                .addFloat(mQQSFooterActions, "translationY", 0, translationY)
-                .build();
-        mAnimatedQsViews.add(mQSFooterActions);
-    }
-
     private int getRelativeTranslationY(View view1, View view2) {
         int[] qsPosition = new int[2];
         int[] qqsPosition = new int[2];
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index e230e1b..7800027 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -19,10 +19,8 @@
 import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
 
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Path;
-import android.graphics.Point;
 import android.graphics.PointF;
 import android.util.AttributeSet;
 import android.view.View;
@@ -41,7 +39,6 @@
  */
 public class QSContainerImpl extends FrameLayout implements Dumpable {
 
-    private final Point mSizePoint = new Point();
     private int mFancyClippingTop;
     private int mFancyClippingBottom;
     private final float[] mFancyClippingRadii = new float[] {0, 0, 0, 0, 0, 0, 0, 0};
@@ -78,12 +75,6 @@
     }
 
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        mSizePoint.set(0, 0); // Will be retrieved on next measure pass.
-    }
-
-    @Override
     public boolean performClick() {
         // Want to receive clicks so missing QQS tiles doesn't cause collapse, but
         // don't want to do anything with them.
@@ -152,10 +143,10 @@
     void updateResources(QSPanelController qsPanelController,
             QuickStatusBarHeaderController quickStatusBarHeaderController) {
         mQSPanelContainer.setPaddingRelative(
-                getPaddingStart(),
+                mQSPanelContainer.getPaddingStart(),
                 Utils.getQsHeaderSystemIconsAreaHeight(mContext),
-                getPaddingEnd(),
-                getPaddingBottom()
+                mQSPanelContainer.getPaddingEnd(),
+                mQSPanelContainer.getPaddingBottom()
         );
 
         int sideMargins = getResources().getDimensionPixelSize(R.dimen.notification_side_paddings);
@@ -241,13 +232,6 @@
         }
     }
 
-    private int getDisplayHeight() {
-        if (mSizePoint.y == 0) {
-            getDisplay().getRealSize(mSizePoint);
-        }
-        return mSizePoint.y;
-    }
-
     /**
      * Clip QS bottom using a concave shape.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 0e0681b..aac5672 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -42,11 +42,6 @@
      */
     void setExpansion(float expansion);
 
-    /**
-     * Sets whether or not this footer should set itself to listen for changes in any callbacks
-     * that it has implemented.
-     */
-    void setListening(boolean listening);
 
     /**
      * Sets whether or not the keyguard is currently being shown.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index 4622660..6c0ca49 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -46,7 +46,6 @@
 public class QSFooterView extends FrameLayout {
     private PageIndicator mPageIndicator;
     private TextView mBuildText;
-    private View mActionsContainer;
     private View mEditButton;
 
     @Nullable
@@ -78,7 +77,6 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mPageIndicator = findViewById(R.id.footer_page_indicator);
-        mActionsContainer = requireViewById(R.id.qs_footer_actions);
         mBuildText = findViewById(R.id.build);
         mEditButton = findViewById(android.R.id.edit);
 
@@ -105,10 +103,6 @@
         }
     }
 
-    void updateExpansion() {
-        setExpansion(mExpansionAmount);
-    }
-
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
@@ -129,7 +123,6 @@
     @Nullable
     private TouchAnimator createFooterAnimator() {
         TouchAnimator.Builder builder = new TouchAnimator.Builder()
-                .addFloat(mActionsContainer, "alpha", 0, 1)
                 .addFloat(mPageIndicator, "alpha", 0, 1)
                 .addFloat(mBuildText, "alpha", 0, 1)
                 .addFloat(mEditButton, "alpha", 0, 1)
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index 5327b7e..bef4f43 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.qs;
 
-import static com.android.systemui.qs.dagger.QSFragmentModule.QS_FOOTER;
-
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.text.TextUtils;
@@ -33,7 +31,6 @@
 import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
-import javax.inject.Named;
 
 /**
  * Controller for {@link QSFooterView}.
@@ -43,8 +40,6 @@
 
     private final UserTracker mUserTracker;
     private final QSPanelController mQsPanelController;
-    private final QuickQSPanelController mQuickQSPanelController;
-    private final FooterActionsController mFooterActionsController;
     private final TextView mBuildText;
     private final PageIndicator mPageIndicator;
     private final View mEditButton;
@@ -56,14 +51,10 @@
             UserTracker userTracker,
             FalsingManager falsingManager,
             ActivityStarter activityStarter,
-            QSPanelController qsPanelController,
-            QuickQSPanelController quickQSPanelController,
-            @Named(QS_FOOTER) FooterActionsController footerActionsController) {
+            QSPanelController qsPanelController) {
         super(view);
         mUserTracker = userTracker;
         mQsPanelController = qsPanelController;
-        mQuickQSPanelController = quickQSPanelController;
-        mFooterActionsController = footerActionsController;
         mFalsingManager = falsingManager;
         mActivityStarter = activityStarter;
 
@@ -73,21 +64,7 @@
     }
 
     @Override
-    protected void onInit() {
-        super.onInit();
-        mFooterActionsController.init();
-    }
-
-    @Override
     protected void onViewAttached() {
-        mView.addOnLayoutChangeListener(
-                (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
-                    mView.updateExpansion();
-                    mFooterActionsController.updateAnimator(right - left,
-                            mQuickQSPanelController.getNumQuickTiles());
-                }
-        );
-
         mBuildText.setOnLongClickListener(view -> {
             CharSequence buildText = mBuildText.getText();
             if (!TextUtils.isEmpty(buildText)) {
@@ -114,9 +91,7 @@
     }
 
     @Override
-    protected void onViewDetached() {
-        setListening(false);
-    }
+    protected void onViewDetached() {}
 
     @Override
     public void setVisibility(int visibility) {
@@ -126,25 +101,17 @@
 
     @Override
     public void setExpanded(boolean expanded) {
-        mFooterActionsController.setExpanded(expanded);
         mView.setExpanded(expanded);
     }
 
     @Override
     public void setExpansion(float expansion) {
         mView.setExpansion(expansion);
-        mFooterActionsController.setExpansion(expansion);
-    }
-
-    @Override
-    public void setListening(boolean listening) {
-        mFooterActionsController.setListening(listening);
     }
 
     @Override
     public void setKeyguardShowing(boolean keyguardShowing) {
         mView.setKeyguardShowing();
-        mFooterActionsController.setKeyguardShowing();
     }
 
     /** */
@@ -156,6 +123,5 @@
     @Override
     public void disable(int state1, int state2, boolean animate) {
         mView.disable(state2);
-        mFooterActionsController.disable(state2);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 259b786..50952bd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -118,6 +118,7 @@
     private QSPanelController mQSPanelController;
     private QuickQSPanelController mQuickQSPanelController;
     private QSCustomizerController mQSCustomizerController;
+    private FooterActionsController mQSFooterActionController;
     @Nullable
     private ScrollListener mScrollListener;
     /**
@@ -188,9 +189,11 @@
         QSFragmentComponent qsFragmentComponent = mQsComponentFactory.create(this);
         mQSPanelController = qsFragmentComponent.getQSPanelController();
         mQuickQSPanelController = qsFragmentComponent.getQuickQSPanelController();
+        mQSFooterActionController = qsFragmentComponent.getQSFooterActionController();
 
         mQSPanelController.init();
         mQuickQSPanelController.init();
+        mQSFooterActionController.init();
 
         mQSPanelScrollView = view.findViewById(R.id.expanded_qs_scroll_view);
         mQSPanelScrollView.addOnLayoutChangeListener(
@@ -380,6 +383,7 @@
         mContainer.disable(state1, state2, animate);
         mHeader.disable(state1, state2, animate);
         mFooter.disable(state1, state2, animate);
+        mQSFooterActionController.disable(state2);
         updateQsState();
     }
 
@@ -396,10 +400,10 @@
                 : View.INVISIBLE);
         mHeader.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
                 || (expanded && !mStackScrollerOverscrolling), mQuickQSPanelController);
-        mFooter.setVisibility(!mQsDisabled && (expanded || !keyguardShowing || mHeaderAnimating
-                || mShowCollapsedOnKeyguard)
-                ? View.VISIBLE
-                : View.INVISIBLE);
+        boolean footerVisible = !mQsDisabled && (expanded || !keyguardShowing || mHeaderAnimating
+                || mShowCollapsedOnKeyguard);
+        mFooter.setVisibility(footerVisible ? View.VISIBLE : View.INVISIBLE);
+        mQSFooterActionController.setVisible(footerVisible);
         mFooter.setExpanded((keyguardShowing && !mHeaderAnimating && !mShowCollapsedOnKeyguard)
                 || (expanded && !mStackScrollerOverscrolling));
         mQSPanelController.setVisibility(
@@ -465,6 +469,7 @@
         }
 
         mFooter.setKeyguardShowing(keyguardShowing);
+        mQSFooterActionController.setKeyguardShowing(keyguardShowing);
         updateQsState();
     }
 
@@ -480,14 +485,13 @@
         if (DEBUG) Log.d(TAG, "setListening " + listening);
         mListening = listening;
         mQSContainerImplController.setListening(listening);
-        mFooter.setListening(listening);
+        mQSFooterActionController.setListening(listening);
         mQSPanelController.setListening(mListening, mQsExpanded);
     }
 
     @Override
     public void setHeaderListening(boolean listening) {
         mQSContainerImplController.setListening(listening);
-        mFooter.setListening(listening);
     }
 
     @Override
@@ -561,6 +565,7 @@
             }
         }
         mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
+        mQSFooterActionController.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
         mQSPanelController.setRevealExpansion(expansion);
         mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
         mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
@@ -711,6 +716,7 @@
         boolean customizing = isCustomizing();
         mQSPanelScrollView.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
         mFooter.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
+        mQSFooterActionController.setVisible(!customizing);
         mHeader.setVisibility(!customizing ? View.VISIBLE : View.INVISIBLE);
         // Let the panel know the position changed and it needs to update where notifications
         // and whatnot are.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 92690c7d..2d2fa1f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -17,7 +17,6 @@
 package com.android.systemui.qs;
 
 import static com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL;
-import static com.android.systemui.qs.dagger.QSFragmentModule.QQS_FOOTER;
 import static com.android.systemui.qs.dagger.QSFragmentModule.QS_USING_MEDIA_PLAYER;
 
 import com.android.internal.logging.MetricsLogger;
@@ -54,7 +53,6 @@
     // brightness is visible only in split shade
     private final QuickQSBrightnessController mBrightnessController;
     private final BrightnessMirrorHandler mBrightnessMirrorHandler;
-    private final FooterActionsController mFooterActionsController;
 
     @Inject
     QuickQSPanelController(QuickQSPanel view, QSTileHost qsTileHost,
@@ -63,14 +61,12 @@
             @Named(QUICK_QS_PANEL) MediaHost mediaHost,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
             DumpManager dumpManager,
-            QuickQSBrightnessController quickQSBrightnessController,
-            @Named(QQS_FOOTER) FooterActionsController footerActionsController
+            QuickQSBrightnessController quickQSBrightnessController
     ) {
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
                 uiEventLogger, qsLogger, dumpManager);
         mBrightnessController = quickQSBrightnessController;
         mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
-        mFooterActionsController = footerActionsController;
     }
 
     @Override
@@ -80,8 +76,6 @@
         mMediaHost.setShowsOnlyActiveMedia(true);
         mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
         mBrightnessController.init(mShouldUseSplitNotificationShade);
-        mFooterActionsController.init();
-        mFooterActionsController.refreshVisibility(mShouldUseSplitNotificationShade);
     }
 
     @Override
@@ -102,7 +96,6 @@
     void setListening(boolean listening) {
         super.setListening(listening);
         mBrightnessController.setListening(listening);
-        mFooterActionsController.setListening(listening);
     }
 
     public boolean isListening() {
@@ -123,7 +116,6 @@
     @Override
     protected void onConfigurationChanged() {
         mBrightnessController.refreshVisibility(mShouldUseSplitNotificationShade);
-        mFooterActionsController.refreshVisibility(mShouldUseSplitNotificationShade);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
index 63cbc21..594f4f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentComponent.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.qs.dagger;
 
+import com.android.systemui.qs.FooterActionsController;
 import com.android.systemui.qs.QSAnimator;
 import com.android.systemui.qs.QSContainerImplController;
 import com.android.systemui.qs.QSFooter;
@@ -61,4 +62,7 @@
 
     /** Construct a {@link QSSquishinessController}. */
     QSSquishinessController getQSSquishinessController();
+
+    /** Construct a {@link FooterActionsController}. */
+    FooterActionsController getQSFooterActionController();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
index 1958caf..776ee10 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -21,15 +21,15 @@
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewStub;
 
 import com.android.systemui.R;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.dagger.qualifiers.RootView;
+import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.privacy.OngoingPrivacyChip;
-import com.android.systemui.qs.FooterActionsController;
-import com.android.systemui.qs.FooterActionsController.ExpansionState;
-import com.android.systemui.qs.FooterActionsControllerBuilder;
 import com.android.systemui.qs.FooterActionsView;
 import com.android.systemui.qs.QSContainerImpl;
 import com.android.systemui.qs.QSFooter;
@@ -55,8 +55,6 @@
 public interface QSFragmentModule {
     String QS_FGS_MANAGER_FOOTER_VIEW = "qs_fgs_manager_footer";
     String QS_SECURITY_FOOTER_VIEW = "qs_security_footer";
-    String QQS_FOOTER = "qqs_footer";
-    String QS_FOOTER = "qs_footer";
     String QS_USING_MEDIA_PLAYER = "qs_using_media_player";
 
     /**
@@ -122,46 +120,26 @@
         return view.findViewById(R.id.qs_footer);
     }
 
-    /** */
+    /**
+     * Provides a {@link FooterActionsView}.
+     *
+     * This will replace a ViewStub either in {@link QSFooterView} or in {@link QSContainerImpl}.
+     */
     @Provides
-    @Named(QS_FOOTER)
-    static FooterActionsView providesQSFooterActionsView(@RootView View view) {
+    static FooterActionsView providesQSFooterActionsView(@RootView View view,
+            FeatureFlags featureFlags) {
+        ViewStub stub;
+        if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
+            stub = view.requireViewById(R.id.container_stub);
+        } else {
+            stub = view.requireViewById(R.id.footer_stub);
+        }
+        stub.inflate();
         return view.findViewById(R.id.qs_footer_actions);
     }
 
     /** */
     @Provides
-    @Named(QQS_FOOTER)
-    static FooterActionsView providesQQSFooterActionsView(@RootView View view) {
-        return view.findViewById(R.id.qqs_footer_actions);
-    }
-
-    /** */
-    @Provides
-    @Named(QQS_FOOTER)
-    static FooterActionsController providesQQSFooterActionsController(
-            FooterActionsControllerBuilder footerActionsControllerBuilder,
-            @Named(QQS_FOOTER) FooterActionsView qqsFooterActionsView) {
-        return footerActionsControllerBuilder
-                .withView(qqsFooterActionsView)
-                .withButtonsVisibleWhen(ExpansionState.COLLAPSED)
-                .build();
-    }
-
-    /** */
-    @Provides
-    @Named(QS_FOOTER)
-    static FooterActionsController providesQSFooterActionsController(
-            FooterActionsControllerBuilder footerActionsControllerBuilder,
-            @Named(QS_FOOTER) FooterActionsView qsFooterActionsView) {
-        return footerActionsControllerBuilder
-                .withView(qsFooterActionsView)
-                .withButtonsVisibleWhen(ExpansionState.EXPANDED)
-                .build();
-    }
-
-    /** */
-    @Provides
     @QSScope
     static QSFooter providesQSFooter(QSFooterViewController qsFooterViewController) {
         qsFooterViewController.init();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
index 1a88533..b457ebf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQSContainerController.kt
@@ -1,6 +1,8 @@
 package com.android.systemui.statusbar.phone
 
 import android.view.WindowInsets
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.navigationbar.NavigationModeController
 import com.android.systemui.plugins.qs.QS
 import com.android.systemui.plugins.qs.QSContainerController
@@ -14,7 +16,8 @@
 class NotificationsQSContainerController @Inject constructor(
     view: NotificationsQuickSettingsContainer,
     private val navigationModeController: NavigationModeController,
-    private val overviewProxyService: OverviewProxyService
+    private val overviewProxyService: OverviewProxyService,
+    private val featureFlags: FeatureFlags
 ) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController {
 
     var qsExpanded = false
@@ -108,7 +111,11 @@
         }
         mView.setPadding(0, 0, 0, containerPadding)
         mView.setNotificationsMarginBottom(notificationsMargin)
-        mView.setQSScrollPaddingBottom(qsScrollPaddingBottom)
+        if (featureFlags.isEnabled(Flags.NEW_FOOTER)) {
+            mView.setQSContainerPaddingBottom(notificationsMargin)
+        } else {
+            mView.setQSScrollPaddingBottom(qsScrollPaddingBottom)
+        }
     }
 
     private fun calculateBottomSpacing(): Pair<Int, Int> {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index cecbcdb..95e3b70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -52,6 +52,7 @@
     private Consumer<QS> mQSFragmentAttachedListener = qs -> {};
     private QS mQs;
     private View mQSScrollView;
+    private View mQSContainer;
 
     public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -70,6 +71,7 @@
         mQs = (QS) fragment;
         mQSFragmentAttachedListener.accept(mQs);
         mQSScrollView = mQs.getView().findViewById(R.id.expanded_qs_scroll_view);
+        mQSContainer = mQs.getView().findViewById(R.id.quick_settings_container);
     }
 
     @Override
@@ -89,6 +91,16 @@
                     mQSScrollView.getPaddingLeft(),
                     mQSScrollView.getPaddingTop(),
                     mQSScrollView.getPaddingRight(),
+                    paddingBottom);
+        }
+    }
+
+    public void setQSContainerPaddingBottom(int paddingBottom) {
+        if (mQSContainer != null) {
+            mQSContainer.setPadding(
+                    mQSContainer.getPaddingLeft(),
+                    mQSContainer.getPaddingTop(),
+                    mQSContainer.getPaddingRight(),
                     paddingBottom
             );
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index 354bb51..f5fa0d0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -15,9 +15,10 @@
 import com.android.systemui.Dependency
 import com.android.systemui.R
 import com.android.systemui.classifier.FalsingManagerFake
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.globalactions.GlobalActionsDialogLite
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.qs.FooterActionsController.ExpansionState
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
@@ -54,12 +55,16 @@
     @Mock
     private lateinit var userInfoController: UserInfoController
     @Mock
+    private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory
+    @Mock
     private lateinit var multiUserSwitchController: MultiUserSwitchController
     @Mock
     private lateinit var globalActionsDialog: GlobalActionsDialogLite
     @Mock
     private lateinit var uiEventLogger: UiEventLogger
     @Mock
+    private lateinit var featureFlags: FeatureFlags
+
     private lateinit var controller: FooterActionsController
 
     private val metricsLogger: MetricsLogger = FakeMetricsLogger()
@@ -76,15 +81,18 @@
         injectLeakCheckedDependencies(*LeakCheckedTest.ALL_SUPPORTED_CLASSES)
         val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
 
+        whenever(multiUserSwitchControllerFactory.create(any()))
+                .thenReturn(multiUserSwitchController)
+        whenever(featureFlags.isEnabled(Flags.NEW_FOOTER)).thenReturn(false)
+
         view = LayoutInflater.from(context)
                 .inflate(R.layout.footer_actions, null) as FooterActionsView
 
-        controller = FooterActionsController(view, activityStarter,
-                userManager, userTracker, userInfoController, multiUserSwitchController,
+        controller = FooterActionsController(view, multiUserSwitchControllerFactory,
+                activityStarter, userManager, userTracker, userInfoController,
                 deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
-                globalActionsDialog, uiEventLogger, showPMLiteButton = true,
-                buttonsVisibleState = ExpansionState.EXPANDED, fakeSettings,
-                Handler(testableLooper.looper))
+                globalActionsDialog, uiEventLogger, showPMLiteButton = true, fakeSettings,
+                Handler(testableLooper.looper), featureFlags)
         controller.init()
         ViewUtils.attachView(view)
         // View looper is the testable looper associated with the test
@@ -98,7 +106,7 @@
 
     @Test
     fun testLogPowerMenuClick() {
-        controller.expanded = true
+        controller.visible = true
         falsingManager.setFalseTap(false)
 
         view.findViewById<View>(R.id.pm_lite).performClick()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
index f43e68f..26aa37d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -61,12 +61,8 @@
     @Mock
     private ClipboardManager mClipboardManager;
     @Mock
-    private QuickQSPanelController mQuickQSPanelController;
-    @Mock
     private TextView mBuildText;
     @Mock
-    private FooterActionsController mFooterActionsController;
-    @Mock
     private FalsingManager mFalsingManager;
     @Mock
     private ActivityStarter mActivityStarter;
@@ -93,8 +89,7 @@
         when(mView.findViewById(android.R.id.edit)).thenReturn(mEditButton);
 
         mController = new QSFooterViewController(mView, mUserTracker, mFalsingManager,
-                mActivityStarter, mQSPanelController, mQuickQSPanelController,
-                mFooterActionsController);
+                mActivityStarter, mQSPanelController);
 
         mController.init();
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
index 59948d3..09c6d9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -68,8 +68,6 @@
     private lateinit var tileView: QSTileView
     @Mock
     private lateinit var quickQsBrightnessController: QuickQSBrightnessController
-    @Mock
-    private lateinit var footerActionsController: FooterActionsController
     @Captor
     private lateinit var captor: ArgumentCaptor<QSPanel.OnConfigurationChangedListener>
 
@@ -95,8 +93,7 @@
                 uiEventLogger,
                 qsLogger,
                 dumpManager,
-                quickQsBrightnessController,
-                footerActionsController
+                quickQsBrightnessController
         )
 
         controller.init()
@@ -128,14 +125,12 @@
     }
 
     @Test
-    fun testBrightnessAndFooterVisibilityRefreshedWhenConfigurationChanged() {
+    fun testBrightnessRefreshedWhenConfigurationChanged() {
         // times(2) because both controller and base controller are registering their listeners
         verify(quickQSPanel, times(2)).addOnConfigurationChangedListener(captor.capture())
 
         captor.allValues.forEach { it.onConfigurationChange(Configuration.EMPTY) }
 
         verify(quickQsBrightnessController).refreshVisibility(anyBoolean())
-        // times(2) because footer visibility is also refreshed on controller init
-        verify(footerActionsController, times(2)).refreshVisibility(anyBoolean())
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
index 77e9025..bbb2346 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationQSContainerControllerTest.kt
@@ -6,6 +6,8 @@
 import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.navigationbar.NavigationModeController
 import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener
 import com.android.systemui.recents.OverviewProxyService
@@ -46,6 +48,8 @@
     private lateinit var overviewProxyService: OverviewProxyService
     @Mock
     private lateinit var notificationsQSContainer: NotificationsQuickSettingsContainer
+    @Mock
+    private lateinit var featureFlags: FeatureFlags
     @Captor
     lateinit var navigationModeCaptor: ArgumentCaptor<ModeChangedListener>
     @Captor
@@ -64,7 +68,8 @@
         notificationsQSContainerController = NotificationsQSContainerController(
                 notificationsQSContainer,
                 navigationModeController,
-                overviewProxyService
+                overviewProxyService,
+                featureFlags
         )
         whenever(notificationsQSContainer.defaultNotificationsMarginBottom)
                 .thenReturn(NOTIFICATIONS_MARGIN)
@@ -85,6 +90,26 @@
     @Test
     fun testTaskbarVisibleInSplitShade() {
         notificationsQSContainerController.splitShadeEnabled = true
+        useNewFooter(false)
+
+        given(taskbarVisible = true,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = 0, // taskbar should disappear when shade is expanded
+                expectedNotificationsMargin = NOTIFICATIONS_MARGIN)
+
+        given(taskbarVisible = true,
+                navigationMode = BUTTONS_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = STABLE_INSET_BOTTOM,
+                expectedNotificationsMargin = NOTIFICATIONS_MARGIN)
+    }
+
+    @Test
+    fun testTaskbarVisibleInSplitShade_newFooter() {
+        notificationsQSContainerController.splitShadeEnabled = true
+        useNewFooter(true)
+
         given(taskbarVisible = true,
                 navigationMode = GESTURES_NAVIGATION,
                 insets = windowInsets().withStableBottom())
@@ -102,6 +127,26 @@
     fun testTaskbarNotVisibleInSplitShade() {
         // when taskbar is not visible, it means we're on the home screen
         notificationsQSContainerController.splitShadeEnabled = true
+        useNewFooter(false)
+
+        given(taskbarVisible = false,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = 0)
+
+        given(taskbarVisible = false,
+                navigationMode = BUTTONS_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = 0, // qs goes full height as it's not obscuring nav buttons
+                expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN)
+    }
+
+    @Test
+    fun testTaskbarNotVisibleInSplitShade_newFooter() {
+        // when taskbar is not visible, it means we're on the home screen
+        notificationsQSContainerController.splitShadeEnabled = true
+        useNewFooter(true)
+
         given(taskbarVisible = false,
                 navigationMode = GESTURES_NAVIGATION,
                 insets = windowInsets().withStableBottom())
@@ -117,6 +162,25 @@
     @Test
     fun testTaskbarNotVisibleInSplitShadeWithCutout() {
         notificationsQSContainerController.splitShadeEnabled = true
+        useNewFooter(false)
+
+        given(taskbarVisible = false,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = windowInsets().withCutout())
+        then(expectedContainerPadding = CUTOUT_HEIGHT)
+
+        given(taskbarVisible = false,
+                navigationMode = BUTTONS_NAVIGATION,
+                insets = windowInsets().withCutout().withStableBottom())
+        then(expectedContainerPadding = 0,
+                expectedNotificationsMargin = STABLE_INSET_BOTTOM + NOTIFICATIONS_MARGIN)
+    }
+
+    @Test
+    fun testTaskbarNotVisibleInSplitShadeWithCutout_newFooter() {
+        notificationsQSContainerController.splitShadeEnabled = true
+        useNewFooter(true)
+
         given(taskbarVisible = false,
                 navigationMode = GESTURES_NAVIGATION,
                 insets = windowInsets().withCutout())
@@ -132,6 +196,24 @@
     @Test
     fun testTaskbarVisibleInSinglePaneShade() {
         notificationsQSContainerController.splitShadeEnabled = false
+        useNewFooter(false)
+
+        given(taskbarVisible = true,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = 0)
+
+        given(taskbarVisible = true,
+                navigationMode = BUTTONS_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = STABLE_INSET_BOTTOM)
+    }
+
+    @Test
+    fun testTaskbarVisibleInSinglePaneShade_newFooter() {
+        notificationsQSContainerController.splitShadeEnabled = false
+        useNewFooter(true)
+
         given(taskbarVisible = true,
                 navigationMode = GESTURES_NAVIGATION,
                 insets = windowInsets().withStableBottom())
@@ -146,6 +228,8 @@
     @Test
     fun testTaskbarNotVisibleInSinglePaneShade() {
         notificationsQSContainerController.splitShadeEnabled = false
+        useNewFooter(false)
+
         given(taskbarVisible = false,
                 navigationMode = GESTURES_NAVIGATION,
                 insets = emptyInsets())
@@ -159,14 +243,56 @@
         given(taskbarVisible = false,
                 navigationMode = BUTTONS_NAVIGATION,
                 insets = windowInsets().withStableBottom())
-        then(expectedContainerPadding = 0,
-                expectedQsPadding = STABLE_INSET_BOTTOM)
+        then(expectedContainerPadding = 0, expectedQsPadding = STABLE_INSET_BOTTOM)
+    }
+
+    @Test
+    fun testTaskbarNotVisibleInSinglePaneShade_newFooter() {
+        notificationsQSContainerController.splitShadeEnabled = false
+        useNewFooter(true)
+
+        given(taskbarVisible = false,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = emptyInsets())
+        then(expectedContainerPadding = 0)
+
+        given(taskbarVisible = false,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = windowInsets().withCutout().withStableBottom())
+        then(expectedContainerPadding = CUTOUT_HEIGHT)
+
+        given(taskbarVisible = false,
+                navigationMode = BUTTONS_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = 0, expectedQsPadding = STABLE_INSET_BOTTOM)
     }
 
     @Test
     fun testCustomizingInSinglePaneShade() {
         notificationsQSContainerController.splitShadeEnabled = false
         notificationsQSContainerController.setCustomizerShowing(true)
+        useNewFooter(false)
+
+        // always sets spacings to 0
+        given(taskbarVisible = false,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = 0,
+                expectedNotificationsMargin = 0)
+
+        given(taskbarVisible = false,
+                navigationMode = BUTTONS_NAVIGATION,
+                insets = emptyInsets())
+        then(expectedContainerPadding = 0,
+                expectedNotificationsMargin = 0)
+    }
+
+    @Test
+    fun testCustomizingInSinglePaneShade_newFooter() {
+        notificationsQSContainerController.splitShadeEnabled = false
+        notificationsQSContainerController.setCustomizerShowing(true)
+        useNewFooter(true)
+
         // always sets spacings to 0
         given(taskbarVisible = false,
                 navigationMode = GESTURES_NAVIGATION,
@@ -185,6 +311,28 @@
     fun testDetailShowingInSinglePaneShade() {
         notificationsQSContainerController.splitShadeEnabled = false
         notificationsQSContainerController.setDetailShowing(true)
+        useNewFooter(false)
+
+        // always sets spacings to 0
+        given(taskbarVisible = false,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = 0,
+                expectedNotificationsMargin = 0)
+
+        given(taskbarVisible = false,
+                navigationMode = BUTTONS_NAVIGATION,
+                insets = emptyInsets())
+        then(expectedContainerPadding = 0,
+                expectedNotificationsMargin = 0)
+    }
+
+    @Test
+    fun testDetailShowingInSinglePaneShade_newFooter() {
+        notificationsQSContainerController.splitShadeEnabled = false
+        notificationsQSContainerController.setDetailShowing(true)
+        useNewFooter(true)
+
         // always sets spacings to 0
         given(taskbarVisible = false,
                 navigationMode = GESTURES_NAVIGATION,
@@ -202,6 +350,26 @@
     @Test
     fun testDetailShowingInSplitShade() {
         notificationsQSContainerController.splitShadeEnabled = true
+        useNewFooter(false)
+
+        given(taskbarVisible = false,
+                navigationMode = GESTURES_NAVIGATION,
+                insets = windowInsets().withStableBottom())
+        then(expectedContainerPadding = 0)
+
+        notificationsQSContainerController.setDetailShowing(true)
+        // should not influence spacing
+        given(taskbarVisible = false,
+                navigationMode = BUTTONS_NAVIGATION,
+                insets = emptyInsets())
+        then(expectedContainerPadding = 0)
+    }
+
+    @Test
+    fun testDetailShowingInSplitShade_newFooter() {
+        notificationsQSContainerController.splitShadeEnabled = true
+        useNewFooter(true)
+
         given(taskbarVisible = false,
                 navigationMode = GESTURES_NAVIGATION,
                 insets = windowInsets().withStableBottom())
@@ -246,7 +414,13 @@
         verify(notificationsQSContainer)
                 .setPadding(anyInt(), anyInt(), anyInt(), eq(expectedContainerPadding))
         verify(notificationsQSContainer).setNotificationsMarginBottom(expectedNotificationsMargin)
-        verify(notificationsQSContainer).setQSScrollPaddingBottom(expectedQsPadding)
+        val newFooter = featureFlags.isEnabled(Flags.NEW_FOOTER)
+        if (newFooter) {
+            verify(notificationsQSContainer)
+                    .setQSContainerPaddingBottom(expectedNotificationsMargin)
+        } else {
+            verify(notificationsQSContainer).setQSScrollPaddingBottom(expectedQsPadding)
+        }
         Mockito.clearInvocations(notificationsQSContainer)
     }
 
@@ -263,4 +437,8 @@
         whenever(stableInsetBottom).thenReturn(STABLE_INSET_BOTTOM)
         return this
     }
+
+    private fun useNewFooter(useNewFooter: Boolean) {
+        whenever(featureFlags.isEnabled(Flags.NEW_FOOTER)).thenReturn(useNewFooter)
+    }
 }
\ No newline at end of file