Merge "Showing action buttons in collapsed QS in split shade" into sc-v2-dev am: bdf4297921

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15482450

Change-Id: I09d4920f3bded7034f7d0da78ed2cfbca5cea292
diff --git a/packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
similarity index 96%
rename from packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml
rename to packages/SystemUI/res-keyguard/layout/footer_actions.xml
index 181ba07..dfc3e63 100644
--- a/packages/SystemUI/res-keyguard/layout/qs_footer_actions.xml
+++ b/packages/SystemUI/res-keyguard/layout/footer_actions.xml
@@ -14,9 +14,10 @@
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 -->
-<com.android.systemui.qs.QSFooterActionsView
+
+<!-- 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"
-    android:id="@+id/qs_footer_actions_container"
     android:layout_width="match_parent"
     android:layout_height="48dp"
     android:gravity="center_vertical">
@@ -101,4 +102,4 @@
 
     </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
-</com.android.systemui.qs.QSFooterActionsView>
\ No newline at end of file
+</com.android.systemui.qs.FooterActionsView>
\ 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 fe0b14a..e70084b 100644
--- a/packages/SystemUI/res/layout/qs_footer_impl.xml
+++ b/packages/SystemUI/res/layout/qs_footer_impl.xml
@@ -68,7 +68,8 @@
 
         </LinearLayout>
 
-        <include layout="@layout/qs_footer_actions"/>
+        <include layout="@layout/footer_actions"
+            android:id="@+id/qs_footer_actions"/>
 
     </LinearLayout>
 
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 df02730..6b14c96 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -56,7 +56,18 @@
             android:clipToPadding="false"
             android:focusable="true"
             android:paddingBottom="24dp"
-            android:importantForAccessibility="yes" />
+            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="16dp"
+                android:layout_marginStart="@dimen/qs_footer_margin"
+                android:layout_marginEnd="@dimen/qs_footer_margin"
+                />
+        </com.android.systemui.qs.QuickQSPanel>
     </RelativeLayout>
 
 </com.android.systemui.qs.QuickStatusBarHeader>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
similarity index 75%
rename from packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt
rename to packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
index dbf62a4..bedb330 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsController.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.content.Intent
@@ -16,6 +32,8 @@
 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.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.phone.SettingsButton
@@ -27,8 +45,13 @@
 import javax.inject.Inject
 import javax.inject.Named
 
-class QSFooterActionsController @Inject constructor(
-    view: QSFooterActionsView,
+/**
+ * Manages [FooterActionsView] behaviour, both when it's placed in QS or QQS (split shade).
+ * Main difference between QS and QQS behaviour is condition when buttons should be visible,
+ * determined by [buttonsVisibleState]
+ */
+class FooterActionsController @Inject constructor(
+    view: FooterActionsView,
     private val qsPanelController: QSPanelController,
     private val activityStarter: ActivityStarter,
     private val userManager: UserManager,
@@ -40,15 +63,20 @@
     private val tunerService: TunerService,
     private val globalActionsDialog: GlobalActionsDialogLite,
     private val uiEventLogger: UiEventLogger,
-    @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean
-) : ViewController<QSFooterActionsView>(view) {
+    @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
+    private val buttonsVisibleState: ExpansionState
+) : ViewController<FooterActionsView>(view) {
+
+    enum class ExpansionState { COLLAPSED, EXPANDED }
 
     private var listening: Boolean = false
+
     var expanded = false
         set(value) {
-            field = value
-            mView.setExpanded(value, isTunerEnabled(),
-                    multiUserSwitchController.isMultiUserEnabled)
+            if (field != value) {
+                field = value
+                updateView()
+            }
         }
 
     private val settingsButton: SettingsButton = view.findViewById(R.id.settings_button)
@@ -64,7 +92,7 @@
     private val onClickListener = View.OnClickListener { v ->
         // Don't do anything until views are unhidden. Don't do anything if the tap looks
         // suspicious.
-        if (!expanded || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
+        if (!buttonsVisible() || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
             return@OnClickListener
         }
         if (v === settingsButton) {
@@ -98,10 +126,26 @@
         }
     }
 
+    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 startSettingsActivity() {
         val animationController = settingsButtonContainer?.let {
             ActivityLaunchAnimator.Controller.fromView(
@@ -128,7 +172,12 @@
             activityStarter.postQSRunnableDismissingKeyguard { qsPanelController.showEdit(view) }
         })
 
-        mView.updateEverything(isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
+        updateView()
+    }
+
+    private fun updateView() {
+        mView.updateEverything(buttonsVisible(), isTunerEnabled(),
+                multiUserSwitchController.isMultiUserEnabled)
     }
 
     override fun onViewDetached() {
@@ -148,7 +197,8 @@
     }
 
     fun disable(state2: Int) {
-        mView.disable(state2, isTunerEnabled(), multiUserSwitchController.isMultiUserEnabled)
+        mView.disable(buttonsVisible(), state2, isTunerEnabled(),
+                multiUserSwitchController.isMultiUserEnabled)
     }
 
     fun setExpansion(headerExpansionFraction: Float) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt
new file mode 100644
index 0000000..fcfa72a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsControllerBuilder.kt
@@ -0,0 +1,67 @@
+/*
+ * 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.UserManager
+import com.android.internal.logging.MetricsLogger
+import com.android.internal.logging.UiEventLogger
+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.statusbar.phone.MultiUserSwitchController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.UserInfoController
+import com.android.systemui.tuner.TunerService
+import javax.inject.Inject
+import javax.inject.Named
+
+class FooterActionsControllerBuilder @Inject constructor(
+    private val qsPanelController: QSPanelController,
+    private val activityStarter: ActivityStarter,
+    private val userManager: UserManager,
+    private val userInfoController: UserInfoController,
+    private val multiUserSwitchController: MultiUserSwitchController,
+    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 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, qsPanelController, activityStarter, userManager,
+                userInfoController, multiUserSwitchController, deviceProvisionedController,
+                falsingManager, metricsLogger, tunerService, globalActionsDialog, uiEventLogger,
+                showPMLiteButton, buttonsVisibleState)
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
similarity index 84%
rename from packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt
rename to packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
index 66a29a3..941e54a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterActionsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FooterActionsView.kt
@@ -37,7 +37,7 @@
  * in split shade mode visible also in collapsed state. May contain up to 5 buttons: settings,
  * edit tiles, power off and conditionally: user switch and tuner
  */
-class QSFooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
+class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
     private lateinit var settingsContainer: View
     private lateinit var settingsButton: SettingsButton
     private lateinit var multiUserSwitch: MultiUserSwitch
@@ -48,7 +48,6 @@
     private var settingsCogAnimator: TouchAnimator? = null
 
     private var qsDisabled = false
-    private var isExpanded = false
     private var expansionAmount = 0f
 
     override fun onFinishInflate() {
@@ -102,27 +101,30 @@
         setExpansion(expansionAmount)
     }
 
-    fun setExpanded(expanded: Boolean, isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
-        if (isExpanded == expanded) return
-        isExpanded = expanded
-        updateEverything(isTunerEnabled, multiUserEnabled)
-    }
-
     fun setExpansion(headerExpansionFraction: Float) {
         expansionAmount = headerExpansionFraction
         if (settingsCogAnimator != null) settingsCogAnimator!!.setPosition(headerExpansionFraction)
     }
 
-    fun disable(state2: Int, isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+    fun disable(
+        buttonsVisible: Boolean,
+        state2: Int,
+        isTunerEnabled: Boolean,
+        multiUserEnabled: Boolean
+    ) {
         val disabled = state2 and StatusBarManager.DISABLE2_QUICK_SETTINGS != 0
         if (disabled == qsDisabled) return
         qsDisabled = disabled
-        updateEverything(isTunerEnabled, multiUserEnabled)
+        updateEverything(buttonsVisible, isTunerEnabled, multiUserEnabled)
     }
 
-    fun updateEverything(isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+    fun updateEverything(
+        buttonsVisible: Boolean,
+        isTunerEnabled: Boolean,
+        multiUserEnabled: Boolean
+    ) {
         post {
-            updateVisibilities(isTunerEnabled, multiUserEnabled)
+            updateVisibilities(buttonsVisible, isTunerEnabled, multiUserEnabled)
             updateClickabilities()
             isClickable = false
         }
@@ -134,16 +136,16 @@
         settingsButton.isClickable = settingsButton.visibility == VISIBLE
     }
 
-    private fun updateVisibilities(isTunerEnabled: Boolean, multiUserEnabled: Boolean) {
+    private fun updateVisibilities(
+        buttonsVisible: Boolean,
+        isTunerEnabled: Boolean,
+        multiUserEnabled: Boolean
+    ) {
         settingsContainer.visibility = if (qsDisabled) GONE else VISIBLE
         tunerIcon.visibility = if (isTunerEnabled) VISIBLE else INVISIBLE
-        multiUserSwitch.visibility = if (showUserSwitcher(multiUserEnabled)) VISIBLE else GONE
+        multiUserSwitch.visibility = if (buttonsVisible && multiUserEnabled) VISIBLE else GONE
         val isDemo = UserManager.isDeviceInDemoMode(context)
-        settingsButton.visibility = if (isDemo || !isExpanded) INVISIBLE else VISIBLE
-    }
-
-    private fun showUserSwitcher(multiUserEnabled: Boolean): Boolean {
-        return isExpanded && multiUserEnabled
+        settingsButton.visibility = if (isDemo || !buttonsVisible) INVISIBLE else VISIBLE
     }
 
     fun onUserInfoChanged(picture: Drawable?, isGuestUser: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 4fcd46c..8659b8b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -14,6 +14,9 @@
 
 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;
@@ -43,6 +46,7 @@
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 /** */
 @QSScope
@@ -67,13 +71,15 @@
      * position to the normal QS panel. These views will only show once the animation is complete,
      * to prevent overlapping of semi transparent views
      */
-    private final ArrayList<View> mQuickQsViews = new ArrayList<>();
+    private final ArrayList<View> mAnimatedQsViews = new ArrayList<>();
     private final QuickQSPanel mQuickQsPanel;
     private final QSPanelController mQsPanelController;
     private final QuickQSPanelController mQuickQSPanelController;
     private final QuickStatusBarHeader mQuickStatusBarHeader;
     private final QSSecurityFooter mSecurityFooter;
     private final QS mQs;
+    private final View mQSFooterActions;
+    private final View mQQSFooterActions;
 
     private PagedTileLayout mPagedLayout;
 
@@ -88,6 +94,7 @@
     // This animates fading of SecurityFooter and media divider
     private TouchAnimator mAllPagesDelayedAnimator;
     private TouchAnimator mBrightnessAnimator;
+    private TouchAnimator mQQSFooterActionsAnimator;
     private HeightExpansionAnimator mQQSTileHeightAnimator;
     private HeightExpansionAnimator mOtherTilesExpandAnimator;
 
@@ -110,12 +117,16 @@
             QSPanelController qsPanelController,
             QuickQSPanelController quickQSPanelController, QSTileHost qsTileHost,
             QSSecurityFooter securityFooter, @Main Executor executor, TunerService tunerService,
-            QSExpansionPathInterpolator qsExpansionPathInterpolator) {
+            QSExpansionPathInterpolator qsExpansionPathInterpolator,
+            @Named(QS_FOOTER) FooterActionsView qsFooterActionsView,
+            @Named(QQS_FOOTER) FooterActionsView qqsFooterActionsView) {
         mQs = qs;
         mQuickQsPanel = quickPanel;
         mQsPanelController = qsPanelController;
         mQuickQSPanelController = quickQSPanelController;
         mQuickStatusBarHeader = quickStatusBarHeader;
+        mQQSFooterActions = qqsFooterActionsView;
+        mQSFooterActions = qsFooterActionsView;
         mSecurityFooter = securityFooter;
         mHost = qsTileHost;
         mExecutor = executor;
@@ -262,7 +273,7 @@
 
         clearAnimationState();
         mAllViews.clear();
-        mQuickQsViews.clear();
+        mAnimatedQsViews.clear();
         mQQSTileHeightAnimator = null;
         mOtherTilesExpandAnimator = null;
 
@@ -360,7 +371,7 @@
 
                     firstPageBuilder.addFloat(quickTileView.getSecondaryLabel(), "alpha", 0, 1);
 
-                    mQuickQsViews.add(tileView);
+                    mAnimatedQsViews.add(tileView);
                     mAllViews.add(quickTileView);
                     mAllViews.add(quickTileView.getSecondaryLabel());
                 } else if (mFullRows && isIconInAnimatedRow(count)) {
@@ -417,6 +428,13 @@
                     .addFloat(tileLayout, "alpha", 0, 1);
             mFirstPageDelayedAnimator = builder.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 = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
             builder.addFloat(mSecurityFooter.getView(), "alpha", 0, 1);
@@ -452,6 +470,20 @@
                 .addFloat(tileLayout, "alpha", 0, 1).build();
     }
 
+    private void updateQQSFooterAnimation() {
+        int[] qsPosition = new int[2];
+        int[] qqsPosition = new int[2];
+        View commonView = mQs.getView();
+        getRelativePositionInt(qsPosition, mQSFooterActions, commonView);
+        getRelativePositionInt(qqsPosition, mQQSFooterActions, commonView);
+        int translationY = (qsPosition[1] - qqsPosition[1])
+                - mQuickStatusBarHeader.getOffsetTranslation();
+        mQQSFooterActionsAnimator = new TouchAnimator.Builder()
+                .addFloat(mQQSFooterActions, "translationY", 0, translationY)
+                .build();
+        mAnimatedQsViews.add(mQSFooterActions);
+    }
+
     private boolean isIconInAnimatedRow(int count) {
         if (mPagedLayout == null) {
             return false;
@@ -521,6 +553,9 @@
             if (mBrightnessAnimator != null) {
                 mBrightnessAnimator.setPosition(position);
             }
+            if (mQQSFooterActionsAnimator != null) {
+                mQQSFooterActionsAnimator.setPosition(position);
+            }
         }
     }
 
@@ -532,9 +567,9 @@
     @Override
     public void onAnimationAtEnd() {
         mQuickQsPanel.setVisibility(View.INVISIBLE);
-        final int N = mQuickQsViews.size();
+        final int N = mAnimatedQsViews.size();
         for (int i = 0; i < N; i++) {
-            mQuickQsViews.get(i).setVisibility(View.VISIBLE);
+            mAnimatedQsViews.get(i).setVisibility(View.VISIBLE);
         }
     }
 
@@ -542,9 +577,9 @@
     public void onAnimationStarted() {
         updateQQSVisibility();
         if (mOnFirstPage) {
-            final int N = mQuickQsViews.size();
+            final int N = mAnimatedQsViews.size();
             for (int i = 0; i < N; i++) {
-                mQuickQsViews.get(i).setVisibility(View.INVISIBLE);
+                mAnimatedQsViews.get(i).setVisibility(View.INVISIBLE);
             }
         }
     }
@@ -569,9 +604,9 @@
         if (mOtherTilesExpandAnimator != null) {
             mOtherTilesExpandAnimator.resetViewsHeights();
         }
-        final int N2 = mQuickQsViews.size();
+        final int N2 = mAnimatedQsViews.size();
         for (int i = 0; i < N2; i++) {
-            mQuickQsViews.get(i).setVisibility(View.VISIBLE);
+            mAnimatedQsViews.get(i).setVisibility(View.VISIBLE);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index 7db13bd..4d23958 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -41,7 +41,7 @@
 
 /**
  * Footer of expanded Quick Settings, tiles page indicator, (optionally) build number and
- * {@link QSFooterActionsView}
+ * {@link FooterActionsView}
  */
 public class QSFooterView extends FrameLayout {
     private PageIndicator mPageIndicator;
@@ -75,7 +75,7 @@
     protected void onFinishInflate() {
         super.onFinishInflate();
         mPageIndicator = findViewById(R.id.footer_page_indicator);
-        mActionsContainer = requireViewById(R.id.qs_footer_actions_container);
+        mActionsContainer = requireViewById(R.id.qs_footer_actions);
         mBuildText = findViewById(R.id.build);
 
         updateResources();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
index c8ae590..e7c06e3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterViewController.java
@@ -16,6 +16,8 @@
 
 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;
@@ -29,6 +31,7 @@
 import com.android.systemui.util.ViewController;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 /**
  * Controller for {@link QSFooterView}.
@@ -39,7 +42,7 @@
     private final UserTracker mUserTracker;
     private final QSPanelController mQsPanelController;
     private final QuickQSPanelController mQuickQSPanelController;
-    private final QSFooterActionsController mQsFooterActionsController;
+    private final FooterActionsController mFooterActionsController;
     private final TextView mBuildText;
     private final PageIndicator mPageIndicator;
 
@@ -48,12 +51,12 @@
             UserTracker userTracker,
             QSPanelController qsPanelController,
             QuickQSPanelController quickQSPanelController,
-            QSFooterActionsController qsFooterActionsController) {
+            @Named(QS_FOOTER) FooterActionsController footerActionsController) {
         super(view);
         mUserTracker = userTracker;
         mQsPanelController = qsPanelController;
         mQuickQSPanelController = quickQSPanelController;
-        mQsFooterActionsController = qsFooterActionsController;
+        mFooterActionsController = footerActionsController;
 
         mBuildText = mView.findViewById(R.id.build);
         mPageIndicator = mView.findViewById(R.id.footer_page_indicator);
@@ -62,7 +65,7 @@
     @Override
     protected void onInit() {
         super.onInit();
-        mQsFooterActionsController.init();
+        mFooterActionsController.init();
     }
 
     @Override
@@ -70,7 +73,7 @@
         mView.addOnLayoutChangeListener(
                 (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
                     mView.updateExpansion();
-                    mQsFooterActionsController.updateAnimator(right - left,
+                    mFooterActionsController.updateAnimator(right - left,
                             mQuickQSPanelController.getNumQuickTiles());
                 }
         );
@@ -104,25 +107,25 @@
 
     @Override
     public void setExpanded(boolean expanded) {
-        mQsFooterActionsController.setExpanded(expanded);
+        mFooterActionsController.setExpanded(expanded);
         mView.setExpanded(expanded);
     }
 
     @Override
     public void setExpansion(float expansion) {
         mView.setExpansion(expansion);
-        mQsFooterActionsController.setExpansion(expansion);
+        mFooterActionsController.setExpansion(expansion);
     }
 
     @Override
     public void setListening(boolean listening) {
-        mQsFooterActionsController.setListening(listening);
+        mFooterActionsController.setListening(listening);
     }
 
     @Override
     public void setKeyguardShowing(boolean keyguardShowing) {
         mView.setKeyguardShowing();
-        mQsFooterActionsController.setKeyguardShowing();
+        mFooterActionsController.setKeyguardShowing();
     }
 
     /** */
@@ -134,6 +137,6 @@
     @Override
     public void disable(int state1, int state2, boolean animate) {
         mView.disable(state2);
-        mQsFooterActionsController.disable(state2);
+        mFooterActionsController.disable(state2);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index 8c7a2cd..921ee35 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -17,6 +17,7 @@
 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;
@@ -53,6 +54,7 @@
     // 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,
@@ -61,12 +63,14 @@
             @Named(QUICK_QS_PANEL) MediaHost mediaHost,
             MetricsLogger metricsLogger, UiEventLogger uiEventLogger, QSLogger qsLogger,
             DumpManager dumpManager,
-            QuickQSBrightnessController quickQSBrightnessController
+            QuickQSBrightnessController quickQSBrightnessController,
+            @Named(QQS_FOOTER) FooterActionsController footerActionsController
     ) {
         super(view, qsTileHost, qsCustomizerController, usingMediaPlayer, mediaHost, metricsLogger,
                 uiEventLogger, qsLogger, dumpManager);
         mBrightnessController = quickQSBrightnessController;
         mBrightnessMirrorHandler = new BrightnessMirrorHandler(mBrightnessController);
+        mFooterActionsController = footerActionsController;
     }
 
     @Override
@@ -76,6 +80,8 @@
         mMediaHost.setShowsOnlyActiveMedia(true);
         mMediaHost.init(MediaHierarchyManager.LOCATION_QQS);
         mBrightnessController.init(mShouldUseSplitNotificationShade);
+        mFooterActionsController.init();
+        refreshFooterVisibility();
     }
 
     @Override
@@ -96,12 +102,21 @@
     void setListening(boolean listening) {
         super.setListening(listening);
         mBrightnessController.setListening(listening);
+        mFooterActionsController.setListening(listening);
     }
 
     public boolean isListening() {
         return mView.isListening();
     }
 
+    private void refreshFooterVisibility() {
+        if (mShouldUseSplitNotificationShade) {
+            mFooterActionsController.showFooter();
+        } else {
+            mFooterActionsController.hideFooter();
+        }
+    }
+
     private void setMaxTiles(int parseNumTiles) {
         mView.setMaxTiles(parseNumTiles);
         setTiles();
@@ -116,6 +131,7 @@
     @Override
     protected void onScreenRotated() {
         mBrightnessController.refreshVisibility(mShouldUseSplitNotificationShade);
+        refreshFooterVisibility();
     }
 
     @Override
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 2de2d04..386769c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/dagger/QSFragmentModule.java
@@ -26,9 +26,12 @@
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.dagger.qualifiers.RootView;
 import com.android.systemui.plugins.qs.QS;
+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;
-import com.android.systemui.qs.QSFooterActionsView;
 import com.android.systemui.qs.QSFooterView;
 import com.android.systemui.qs.QSFooterViewController;
 import com.android.systemui.qs.QSFragment;
@@ -50,6 +53,8 @@
 @Module
 public interface QSFragmentModule {
     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";
 
     /**
@@ -123,8 +128,40 @@
 
     /** */
     @Provides
-    static QSFooterActionsView providesQSFooterActionsView(@RootView View view) {
-        return view.findViewById(R.id.qs_footer_actions_container);
+    @Named(QS_FOOTER)
+    static FooterActionsView providesQSFooterActionsView(@RootView View view) {
+        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();
     }
 
     /** */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
similarity index 87%
rename from packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
index 9378b2b..e54a6ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterActionsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FooterActionsControllerTest.kt
@@ -12,6 +12,7 @@
 import com.android.systemui.classifier.FalsingManagerFake
 import com.android.systemui.globalactions.GlobalActionsDialogLite
 import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.qs.FooterActionsController.ExpansionState
 import com.android.systemui.statusbar.phone.MultiUserSwitchController
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.statusbar.policy.UserInfoController
@@ -29,7 +30,7 @@
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
-class QSFooterActionsControllerTest : LeakCheckedTest() {
+class FooterActionsControllerTest : LeakCheckedTest() {
     @Mock
     private lateinit var userManager: UserManager
     @Mock
@@ -47,10 +48,10 @@
     @Mock
     private lateinit var uiEventLogger: UiEventLogger
     @Mock
-    private lateinit var controller: QSFooterActionsController
+    private lateinit var controller: FooterActionsController
 
     private val metricsLogger: MetricsLogger = FakeMetricsLogger()
-    private lateinit var view: QSFooterActionsView
+    private lateinit var view: FooterActionsView
     private val falsingManager: FalsingManagerFake = FalsingManagerFake()
 
     @Before
@@ -60,12 +61,13 @@
         val fakeTunerService = Dependency.get(TunerService::class.java) as FakeTunerService
 
         view = LayoutInflater.from(context)
-                .inflate(R.layout.qs_footer_actions, null) as QSFooterActionsView
+                .inflate(R.layout.footer_actions, null) as FooterActionsView
 
-        controller = QSFooterActionsController(view, qsPanelController, activityStarter,
+        controller = FooterActionsController(view, qsPanelController, activityStarter,
                 userManager, userInfoController, multiUserSwitchController,
                 deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
-                globalActionsDialog, uiEventLogger, showPMLiteButton = true)
+                globalActionsDialog, uiEventLogger, showPMLiteButton = true,
+                buttonsVisibleState = ExpansionState.EXPANDED)
         controller.init()
         controller.onViewAttached()
     }
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 8c6c358..8b19c50 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterViewControllerTest.java
@@ -59,7 +59,7 @@
     @Mock
     private TextView mBuildText;
     @Mock
-    private QSFooterActionsController mQSFooterActionsController;
+    private FooterActionsController mFooterActionsController;
 
     private QSFooterViewController mController;
 
@@ -79,7 +79,7 @@
         when(mView.findViewById(R.id.build)).thenReturn(mBuildText);
 
         mController = new QSFooterViewController(mView, mUserTracker, mQSPanelController,
-                mQuickQSPanelController, mQSFooterActionsController);
+                mQuickQSPanelController, mFooterActionsController);
 
         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 66a006f..912bea2f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelControllerTest.kt
@@ -68,6 +68,8 @@
     private lateinit var featureFlags: FeatureFlags
     @Mock
     private lateinit var quickQsBrightnessController: QuickQSBrightnessController
+    @Mock
+    private lateinit var footerActionsController: FooterActionsController
 
     private lateinit var controller: QuickQSPanelController
 
@@ -90,7 +92,8 @@
                 uiEventLogger,
                 qsLogger,
                 dumpManager,
-                quickQsBrightnessController
+                quickQsBrightnessController,
+                footerActionsController
         )
 
         controller.init()