Pin footer actions to bottom of QSContainerImpl

These pins the actions and decouples the FooterAction controller from
Footer controller. Pinning the actions is behind a flag, because the UI
is not finalized.

Fixes: 216302612
Test: atest com.android.systemui.qs com.android.systemui.statusbar.phone
Test: manual in different screen sizes

Change-Id: I0cd24596d0b900b2555202f59047ebad5c969afb
This commit is contained in:
Fabian Kozynski
2022-01-28 11:40:54 -05:00
parent 1cbf60014b
commit d2b9b7473d
19 changed files with 319 additions and 128 deletions

View File

@@ -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"

View File

@@ -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>

View File

@@ -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/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"

View File

@@ -330,7 +330,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>
@@ -490,7 +490,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>

View File

@@ -107,6 +107,8 @@ public class Flags {
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 =

View File

@@ -29,12 +29,16 @@ import com.android.internal.logging.MetricsLogger
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.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
@@ -52,6 +56,7 @@ import javax.inject.Named
* 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,
@@ -67,12 +72,28 @@ class FooterActionsController @Inject constructor(
private val uiEventLogger: UiEventLogger,
@Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
private val globalSetting: GlobalSettings,
private val handler: Handler
private val handler: Handler,
private val featureFlags: FeatureFlags
) : ViewController<FooterActionsView>(view) {
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)
@@ -96,7 +117,7 @@ class FooterActionsController @Inject constructor(
private val onClickListener = View.OnClickListener { v ->
// Don't do anything if the tap looks suspicious.
if (!expanded || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
if (!visible || falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return@OnClickListener
}
if (v === settingsButton) {
@@ -132,6 +153,12 @@ class FooterActionsController @Inject constructor(
multiUserSwitchController.init()
}
private fun updateVisibility() {
val previousVisibility = mView.visibility
mView.visibility = if (visible) View.VISIBLE else View.INVISIBLE
if (previousVisibility != mView.visibility) updateView()
}
private fun startSettingsActivity() {
val animationController = settingsButtonContainer?.let {
ActivityLaunchAnimator.Controller.fromView(
@@ -181,15 +208,22 @@ class FooterActionsController @Inject constructor(
}
fun setExpansion(headerExpansionFraction: Float) {
mView.setExpansion(headerExpansionFraction)
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 {
alphaAnimator.setPosition(headerExpansionFraction)
}
}
fun updateAnimator(width: Int, numTiles: Int) {
mView.updateAnimator(width, numTiles)
}
fun setKeyguardShowing() {
mView.setKeyguardShowing()
fun setKeyguardShowing(showing: Boolean) {
setExpansion(lastExpansion)
}
private fun isTunerEnabled() = tunerService.isTunerEnabled

View File

@@ -44,8 +44,6 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
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 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
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 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
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,

View File

@@ -19,10 +19,8 @@ package com.android.systemui.qs;
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 @@ import java.io.PrintWriter;
*/
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};
@@ -77,12 +74,6 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
return false;
}
@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
@@ -152,10 +143,10 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
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 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
}
}
private int getDisplayHeight() {
if (mSizePoint.y == 0) {
getDisplay().getRealSize(mSizePoint);
}
return mSizePoint.y;
}
/**
* Clip QS bottom using a concave shape.
*/

View File

@@ -42,11 +42,6 @@ public interface QSFooter {
*/
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.

View File

@@ -46,7 +46,6 @@ import com.android.systemui.R;
public class QSFooterView extends FrameLayout {
private PageIndicator mPageIndicator;
private TextView mBuildText;
private View mActionsContainer;
private View mEditButton;
@Nullable
@@ -78,7 +77,6 @@ public class QSFooterView extends FrameLayout {
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 @@ public class QSFooterView extends FrameLayout {
}
}
void updateExpansion() {
setExpansion(mExpansionAmount);
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -129,7 +123,6 @@ public class QSFooterView extends FrameLayout {
@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)

View File

@@ -40,8 +40,6 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
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;
@@ -53,14 +51,10 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
UserTracker userTracker,
FalsingManager falsingManager,
ActivityStarter activityStarter,
QSPanelController qsPanelController,
QuickQSPanelController quickQSPanelController,
FooterActionsController footerActionsController) {
QSPanelController qsPanelController) {
super(view);
mUserTracker = userTracker;
mQsPanelController = qsPanelController;
mQuickQSPanelController = quickQSPanelController;
mFooterActionsController = footerActionsController;
mFalsingManager = falsingManager;
mActivityStarter = activityStarter;
@@ -69,22 +63,8 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
mEditButton = mView.findViewById(android.R.id.edit);
}
@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)) {
@@ -111,9 +91,7 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
}
@Override
protected void onViewDetached() {
setListening(false);
}
protected void onViewDetached() {}
@Override
public void setVisibility(int visibility) {
@@ -123,25 +101,17 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
@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();
}
/** */
@@ -153,6 +123,5 @@ public class QSFooterViewController extends ViewController<QSFooterView> impleme
@Override
public void disable(int state1, int state2, boolean animate) {
mView.disable(state2);
mFooterActionsController.disable(state2);
}
}

View File

@@ -118,6 +118,7 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private QSPanelController mQSPanelController;
private QuickQSPanelController mQuickQSPanelController;
private QSCustomizerController mQSCustomizerController;
private FooterActionsController mQSFooterActionController;
@Nullable
private ScrollListener mScrollListener;
/**
@@ -188,9 +189,11 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
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 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mContainer.disable(state1, state2, animate);
mHeader.disable(state1, state2, animate);
mFooter.disable(state1, state2, animate);
mQSFooterActionController.disable(state2);
updateQsState();
}
@@ -396,10 +400,10 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
: 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 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
mFooter.setKeyguardShowing(keyguardShowing);
mQSFooterActionController.setKeyguardShowing(keyguardShowing);
updateQsState();
}
@@ -480,14 +485,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
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 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
}
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 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
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.

View File

@@ -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 @@ public interface QSFragmentComponent {
/** Construct a {@link QSSquishinessController}. */
QSSquishinessController getQSSquishinessController();
/** Construct a {@link FooterActionsController}. */
FooterActionsController getQSFooterActionController();
}

View File

@@ -21,10 +21,13 @@ import static com.android.systemui.util.Utils.useQsMediaPlayer;
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.FooterActionsView;
@@ -117,9 +120,21 @@ public interface QSFragmentModule {
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
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);
}

View File

@@ -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 @@ import javax.inject.Inject
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
@@ -104,7 +107,11 @@ class NotificationsQSContainerController @Inject constructor(
}
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> {

View File

@@ -53,6 +53,7 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
private Consumer<QS> mQSFragmentAttachedListener = qs -> {};
private QS mQs;
private View mQSScrollView;
private View mQSContainer;
public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -72,6 +73,7 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
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
@@ -91,6 +93,16 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
mQSScrollView.getPaddingLeft(),
mQSScrollView.getPaddingTop(),
mQSScrollView.getPaddingRight(),
paddingBottom);
}
}
public void setQSContainerPaddingBottom(int paddingBottom) {
if (mQSContainer != null) {
mQSContainer.setPadding(
mQSContainer.getPaddingLeft(),
mQSContainer.getPaddingTop(),
mQSContainer.getPaddingRight(),
paddingBottom
);
}

View File

@@ -15,6 +15,8 @@ import com.android.internal.logging.testing.FakeMetricsLogger
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.settings.UserTracker
@@ -61,6 +63,8 @@ class FooterActionsControllerTest : LeakCheckedTest() {
@Mock
private lateinit var uiEventLogger: UiEventLogger
@Mock
private lateinit var featureFlags: FeatureFlags
private lateinit var controller: FooterActionsController
private val metricsLogger: MetricsLogger = FakeMetricsLogger()
@@ -79,6 +83,7 @@ class FooterActionsControllerTest : LeakCheckedTest() {
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
@@ -87,7 +92,7 @@ class FooterActionsControllerTest : LeakCheckedTest() {
activityStarter, userManager, userTracker, userInfoController,
deviceProvisionedController, falsingManager, metricsLogger, fakeTunerService,
globalActionsDialog, uiEventLogger, showPMLiteButton = true, fakeSettings,
Handler(testableLooper.looper))
Handler(testableLooper.looper), featureFlags)
controller.init()
ViewUtils.attachView(view)
// View looper is the testable looper associated with the test
@@ -101,7 +106,7 @@ class FooterActionsControllerTest : LeakCheckedTest() {
@Test
fun testLogPowerMenuClick() {
controller.expanded = true
controller.visible = true
falsingManager.setFalseTap(false)
view.findViewById<View>(R.id.pm_lite).performClick()

View File

@@ -61,12 +61,8 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
@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 @@ public class QSFooterViewControllerTest extends LeakCheckedTest {
when(mView.findViewById(android.R.id.edit)).thenReturn(mEditButton);
mController = new QSFooterViewController(mView, mUserTracker, mFalsingManager,
mActivityStarter, mQSPanelController, mQuickQSPanelController,
mFooterActionsController);
mActivityStarter, mQSPanelController);
mController.init();
}

View File

@@ -6,6 +6,8 @@ import android.view.WindowInsets
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 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
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 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
notificationsQSContainerController = NotificationsQSContainerController(
notificationsQSContainer,
navigationModeController,
overviewProxyService
overviewProxyService,
featureFlags
)
whenever(notificationsQSContainer.defaultNotificationsMarginBottom)
.thenReturn(NOTIFICATIONS_MARGIN)
@@ -85,6 +90,26 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@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 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
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 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@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 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@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 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@Test
fun testTaskbarNotVisibleInSinglePaneShade() {
notificationsQSContainerController.splitShadeEnabled = false
useNewFooter(false)
given(taskbarVisible = false,
navigationMode = GESTURES_NAVIGATION,
insets = emptyInsets())
@@ -159,14 +243,56 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
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 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
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 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
@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())
@@ -234,7 +402,13 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
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)
}
@@ -251,4 +425,8 @@ class NotificationQSContainerControllerTest : SysuiTestCase() {
whenever(stableInsetBottom).thenReturn(STABLE_INSET_BOTTOM)
return this
}
private fun useNewFooter(useNewFooter: Boolean) {
whenever(featureFlags.isEnabled(Flags.NEW_FOOTER)).thenReturn(useNewFooter)
}
}