Merge "Fixing bottom part of QS not getting any touches in split shade" into sc-v2-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
3b59f276f5
@@ -16,7 +16,6 @@ package com.android.systemui.plugins.qs;
|
|||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import com.android.systemui.plugins.FragmentBase;
|
import com.android.systemui.plugins.FragmentBase;
|
||||||
import com.android.systemui.plugins.annotations.DependsOn;
|
import com.android.systemui.plugins.annotations.DependsOn;
|
||||||
@@ -56,7 +55,7 @@ public interface QS extends FragmentBase {
|
|||||||
void setQsExpansion(float qsExpansionFraction, float headerTranslation);
|
void setQsExpansion(float qsExpansionFraction, float headerTranslation);
|
||||||
void setHeaderListening(boolean listening);
|
void setHeaderListening(boolean listening);
|
||||||
void notifyCustomizeChanged();
|
void notifyCustomizeChanged();
|
||||||
void setContainer(ViewGroup container);
|
void setContainerController(QSContainerController controller);
|
||||||
void setExpandClickListener(OnClickListener onClickListener);
|
void setExpandClickListener(OnClickListener onClickListener);
|
||||||
|
|
||||||
View getHeader();
|
View getHeader();
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package com.android.systemui.plugins.qs
|
||||||
|
|
||||||
|
interface QSContainerController {
|
||||||
|
fun setCustomizerAnimating(animating: Boolean)
|
||||||
|
|
||||||
|
fun setCustomizerShowing(showing: Boolean)
|
||||||
|
|
||||||
|
fun setDetailShowing(showing: Boolean)
|
||||||
|
}
|
||||||
@@ -26,7 +26,6 @@ import android.graphics.Point;
|
|||||||
import android.graphics.PointF;
|
import android.graphics.PointF;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.WindowInsets;
|
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
@@ -58,7 +57,6 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
|
|||||||
private int mSideMargins;
|
private int mSideMargins;
|
||||||
private boolean mQsDisabled;
|
private boolean mQsDisabled;
|
||||||
private int mContentPadding = -1;
|
private int mContentPadding = -1;
|
||||||
private int mNavBarInset = 0;
|
|
||||||
private boolean mClippingEnabled;
|
private boolean mClippingEnabled;
|
||||||
|
|
||||||
public QSContainerImpl(Context context, AttributeSet attrs) {
|
public QSContainerImpl(Context context, AttributeSet attrs) {
|
||||||
@@ -94,25 +92,14 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
|
||||||
mNavBarInset = insets.getInsets(WindowInsets.Type.navigationBars()).bottom;
|
|
||||||
mQSPanelContainer.setPaddingRelative(
|
|
||||||
mQSPanelContainer.getPaddingStart(),
|
|
||||||
mQSPanelContainer.getPaddingTop(),
|
|
||||||
mQSPanelContainer.getPaddingEnd(),
|
|
||||||
mNavBarInset
|
|
||||||
);
|
|
||||||
return super.onApplyWindowInsets(insets);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||||
// QSPanel will show as many rows as it can (up to TileLayout.MAX_ROWS) such that the
|
// QSPanel will show as many rows as it can (up to TileLayout.MAX_ROWS) such that the
|
||||||
// bottom and footer are inside the screen.
|
// bottom and footer are inside the screen.
|
||||||
MarginLayoutParams layoutParams = (MarginLayoutParams) mQSPanelContainer.getLayoutParams();
|
MarginLayoutParams layoutParams = (MarginLayoutParams) mQSPanelContainer.getLayoutParams();
|
||||||
|
|
||||||
int maxQs = getDisplayHeight() - layoutParams.topMargin - layoutParams.bottomMargin
|
int availableHeight = View.MeasureSpec.getSize(heightMeasureSpec);
|
||||||
|
int maxQs = availableHeight - layoutParams.topMargin - layoutParams.bottomMargin
|
||||||
- getPaddingBottom();
|
- getPaddingBottom();
|
||||||
int padding = mPaddingLeft + mPaddingRight + layoutParams.leftMargin
|
int padding = mPaddingLeft + mPaddingRight + layoutParams.leftMargin
|
||||||
+ layoutParams.rightMargin;
|
+ layoutParams.rightMargin;
|
||||||
@@ -122,11 +109,11 @@ public class QSContainerImpl extends FrameLayout implements Dumpable {
|
|||||||
MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
|
MeasureSpec.makeMeasureSpec(maxQs, MeasureSpec.AT_MOST));
|
||||||
int width = mQSPanelContainer.getMeasuredWidth() + padding;
|
int width = mQSPanelContainer.getMeasuredWidth() + padding;
|
||||||
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
||||||
MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
|
MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.EXACTLY));
|
||||||
// QSCustomizer will always be the height of the screen, but do this after
|
// QSCustomizer will always be the height of the screen, but do this after
|
||||||
// other measuring to avoid changing the height of the QS.
|
// other measuring to avoid changing the height of the QS.
|
||||||
mQSCustomizer.measure(widthMeasureSpec,
|
mQSCustomizer.measure(widthMeasureSpec,
|
||||||
MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
|
MeasureSpec.makeMeasureSpec(availableHeight, MeasureSpec.EXACTLY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ import com.android.systemui.R;
|
|||||||
import com.android.systemui.plugins.ActivityStarter;
|
import com.android.systemui.plugins.ActivityStarter;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.plugins.qs.DetailAdapter;
|
import com.android.systemui.plugins.qs.DetailAdapter;
|
||||||
|
import com.android.systemui.plugins.qs.QSContainerController;
|
||||||
import com.android.systemui.statusbar.CommandQueue;
|
import com.android.systemui.statusbar.CommandQueue;
|
||||||
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
|
|
||||||
|
|
||||||
public class QSDetail extends LinearLayout {
|
public class QSDetail extends LinearLayout {
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ public class QSDetail extends LinearLayout {
|
|||||||
private boolean mSwitchState;
|
private boolean mSwitchState;
|
||||||
private QSFooter mFooter;
|
private QSFooter mFooter;
|
||||||
|
|
||||||
private NotificationsQuickSettingsContainer mContainer;
|
private QSContainerController mQsContainerController;
|
||||||
|
|
||||||
public QSDetail(Context context, @Nullable AttributeSet attrs) {
|
public QSDetail(Context context, @Nullable AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
@@ -120,8 +120,8 @@ public class QSDetail extends LinearLayout {
|
|||||||
mClipper = new QSDetailClipper(this);
|
mClipper = new QSDetailClipper(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContainer(NotificationsQuickSettingsContainer container) {
|
public void setContainerController(QSContainerController controller) {
|
||||||
mContainer = container;
|
mQsContainerController = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@@ -262,8 +262,8 @@ public class QSDetail extends LinearLayout {
|
|||||||
}
|
}
|
||||||
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
||||||
animateDetailVisibleDiff(x, y, visibleDiff, listener);
|
animateDetailVisibleDiff(x, y, visibleDiff, listener);
|
||||||
if (mContainer != null) {
|
if (mQsContainerController != null) {
|
||||||
mContainer.setDetailShowing(showingDetail);
|
mQsContainerController.setDetailShowing(showingDetail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import com.android.systemui.dump.DumpManager;
|
|||||||
import com.android.systemui.media.MediaHost;
|
import com.android.systemui.media.MediaHost;
|
||||||
import com.android.systemui.plugins.FalsingManager;
|
import com.android.systemui.plugins.FalsingManager;
|
||||||
import com.android.systemui.plugins.qs.QS;
|
import com.android.systemui.plugins.qs.QS;
|
||||||
|
import com.android.systemui.plugins.qs.QSContainerController;
|
||||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||||
import com.android.systemui.qs.customize.QSCustomizerController;
|
import com.android.systemui.qs.customize.QSCustomizerController;
|
||||||
import com.android.systemui.qs.dagger.QSFragmentComponent;
|
import com.android.systemui.qs.dagger.QSFragmentComponent;
|
||||||
@@ -50,7 +51,6 @@ import com.android.systemui.statusbar.CommandQueue;
|
|||||||
import com.android.systemui.statusbar.StatusBarState;
|
import com.android.systemui.statusbar.StatusBarState;
|
||||||
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
|
||||||
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
import com.android.systemui.statusbar.phone.KeyguardBypassController;
|
||||||
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
|
|
||||||
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
|
import com.android.systemui.statusbar.policy.BrightnessMirrorController;
|
||||||
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
|
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
|
||||||
import com.android.systemui.util.InjectionInflationController;
|
import com.android.systemui.util.InjectionInflationController;
|
||||||
@@ -336,11 +336,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setContainer(ViewGroup container) {
|
public void setContainerController(QSContainerController controller) {
|
||||||
if (container instanceof NotificationsQuickSettingsContainer) {
|
mQSCustomizerController.setContainerController(controller);
|
||||||
mQSCustomizerController.setContainer((NotificationsQuickSettingsContainer) container);
|
mQSDetail.setContainerController(controller);
|
||||||
mQSDetail.setContainer((NotificationsQuickSettingsContainer) container);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
|
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.plugins.qs.QS;
|
import com.android.systemui.plugins.qs.QS;
|
||||||
|
import com.android.systemui.plugins.qs.QSContainerController;
|
||||||
import com.android.systemui.qs.QSDetailClipper;
|
import com.android.systemui.qs.QSDetailClipper;
|
||||||
import com.android.systemui.statusbar.phone.LightBarController;
|
import com.android.systemui.statusbar.phone.LightBarController;
|
||||||
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows full-screen customization of QS, through show() and hide().
|
* Allows full-screen customization of QS, through show() and hide().
|
||||||
@@ -54,7 +54,7 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
private boolean isShown;
|
private boolean isShown;
|
||||||
private final RecyclerView mRecyclerView;
|
private final RecyclerView mRecyclerView;
|
||||||
private boolean mCustomizing;
|
private boolean mCustomizing;
|
||||||
private NotificationsQuickSettingsContainer mNotifQsContainer;
|
private QSContainerController mQsContainerController;
|
||||||
private QS mQs;
|
private QS mQs;
|
||||||
private int mX;
|
private int mX;
|
||||||
private int mY;
|
private int mY;
|
||||||
@@ -103,8 +103,8 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
lightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown);
|
lightBarController.setQsCustomizing(mIsShowingNavBackdrop && isShown);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setContainer(NotificationsQuickSettingsContainer notificationsQsContainer) {
|
public void setContainerController(QSContainerController controller) {
|
||||||
mNotifQsContainer = notificationsQsContainer;
|
mQsContainerController = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setQs(QS qs) {
|
public void setQs(QS qs) {
|
||||||
@@ -123,8 +123,8 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
mOpening = true;
|
mOpening = true;
|
||||||
setVisibility(View.VISIBLE);
|
setVisibility(View.VISIBLE);
|
||||||
mClipper.animateCircularClip(mX, mY, true, new ExpandAnimatorListener(tileAdapter));
|
mClipper.animateCircularClip(mX, mY, true, new ExpandAnimatorListener(tileAdapter));
|
||||||
mNotifQsContainer.setCustomizerAnimating(true);
|
mQsContainerController.setCustomizerAnimating(true);
|
||||||
mNotifQsContainer.setCustomizerShowing(true);
|
mQsContainerController.setCustomizerShowing(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,8 +136,8 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
mClipper.showBackground();
|
mClipper.showBackground();
|
||||||
isShown = true;
|
isShown = true;
|
||||||
setCustomizing(true);
|
setCustomizing(true);
|
||||||
mNotifQsContainer.setCustomizerAnimating(false);
|
mQsContainerController.setCustomizerAnimating(false);
|
||||||
mNotifQsContainer.setCustomizerShowing(true);
|
mQsContainerController.setCustomizerShowing(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,8 +154,8 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
} else {
|
} else {
|
||||||
setVisibility(View.GONE);
|
setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
mNotifQsContainer.setCustomizerAnimating(animate);
|
mQsContainerController.setCustomizerAnimating(animate);
|
||||||
mNotifQsContainer.setCustomizerShowing(false);
|
mQsContainerController.setCustomizerShowing(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
setCustomizing(true);
|
setCustomizing(true);
|
||||||
}
|
}
|
||||||
mOpening = false;
|
mOpening = false;
|
||||||
mNotifQsContainer.setCustomizerAnimating(false);
|
mQsContainerController.setCustomizerAnimating(false);
|
||||||
mRecyclerView.setAdapter(mTileAdapter);
|
mRecyclerView.setAdapter(mTileAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
public void onAnimationCancel(Animator animation) {
|
public void onAnimationCancel(Animator animation) {
|
||||||
mOpening = false;
|
mOpening = false;
|
||||||
mQs.notifyCustomizeChanged();
|
mQs.notifyCustomizeChanged();
|
||||||
mNotifQsContainer.setCustomizerAnimating(false);
|
mQsContainerController.setCustomizerAnimating(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
if (!isShown) {
|
if (!isShown) {
|
||||||
setVisibility(View.GONE);
|
setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
mNotifQsContainer.setCustomizerAnimating(false);
|
mQsContainerController.setCustomizerAnimating(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -219,7 +219,7 @@ public class QSCustomizer extends LinearLayout {
|
|||||||
if (!isShown) {
|
if (!isShown) {
|
||||||
setVisibility(View.GONE);
|
setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
mNotifQsContainer.setCustomizerAnimating(false);
|
mQsContainerController.setCustomizerAnimating(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,13 +35,13 @@ import androidx.recyclerview.widget.RecyclerView;
|
|||||||
import com.android.internal.logging.UiEventLogger;
|
import com.android.internal.logging.UiEventLogger;
|
||||||
import com.android.systemui.R;
|
import com.android.systemui.R;
|
||||||
import com.android.systemui.keyguard.ScreenLifecycle;
|
import com.android.systemui.keyguard.ScreenLifecycle;
|
||||||
|
import com.android.systemui.plugins.qs.QSContainerController;
|
||||||
import com.android.systemui.plugins.qs.QSTile;
|
import com.android.systemui.plugins.qs.QSTile;
|
||||||
import com.android.systemui.qs.QSEditEvent;
|
import com.android.systemui.qs.QSEditEvent;
|
||||||
import com.android.systemui.qs.QSFragment;
|
import com.android.systemui.qs.QSFragment;
|
||||||
import com.android.systemui.qs.QSTileHost;
|
import com.android.systemui.qs.QSTileHost;
|
||||||
import com.android.systemui.qs.dagger.QSScope;
|
import com.android.systemui.qs.dagger.QSScope;
|
||||||
import com.android.systemui.statusbar.phone.LightBarController;
|
import com.android.systemui.statusbar.phone.LightBarController;
|
||||||
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
|
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController;
|
import com.android.systemui.statusbar.policy.ConfigurationController;
|
||||||
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
|
import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
|
||||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||||
@@ -233,8 +233,8 @@ public class QSCustomizerController extends ViewController<QSCustomizer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
public void setContainer(NotificationsQuickSettingsContainer container) {
|
public void setContainerController(QSContainerController controller) {
|
||||||
mView.setContainer(container);
|
mView.setContainerController(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isShown() {
|
public boolean isShown() {
|
||||||
|
|||||||
@@ -310,6 +310,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
private KeyguardStatusViewController mKeyguardStatusViewController;
|
private KeyguardStatusViewController mKeyguardStatusViewController;
|
||||||
private LockIconViewController mLockIconViewController;
|
private LockIconViewController mLockIconViewController;
|
||||||
private NotificationsQuickSettingsContainer mNotificationContainerParent;
|
private NotificationsQuickSettingsContainer mNotificationContainerParent;
|
||||||
|
private NotificationsQSContainerController mNotificationsQSContainerController;
|
||||||
private boolean mAnimateNextPositionUpdate;
|
private boolean mAnimateNextPositionUpdate;
|
||||||
private float mQuickQsOffsetHeight;
|
private float mQuickQsOffsetHeight;
|
||||||
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
|
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
|
||||||
@@ -653,6 +654,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
ConversationNotificationManager conversationNotificationManager,
|
ConversationNotificationManager conversationNotificationManager,
|
||||||
MediaHierarchyManager mediaHierarchyManager,
|
MediaHierarchyManager mediaHierarchyManager,
|
||||||
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
|
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
|
||||||
|
NotificationsQSContainerController notificationsQSContainerController,
|
||||||
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
|
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
|
||||||
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
|
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
|
||||||
KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory,
|
KeyguardQsUserSwitchComponent.Factory keyguardQsUserSwitchComponentFactory,
|
||||||
@@ -708,6 +710,8 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
|
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
|
||||||
mMediaHierarchyManager = mediaHierarchyManager;
|
mMediaHierarchyManager = mediaHierarchyManager;
|
||||||
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
|
mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
|
||||||
|
mNotificationsQSContainerController = notificationsQSContainerController;
|
||||||
|
mNotificationsQSContainerController.init();
|
||||||
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
|
mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
|
||||||
mGroupManager = groupManager;
|
mGroupManager = groupManager;
|
||||||
mNotificationIconAreaController = notificationIconAreaController;
|
mNotificationIconAreaController = notificationIconAreaController;
|
||||||
@@ -1005,7 +1009,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
constraintSet.setMargin(R.id.notification_stack_scroller, TOP, topMargin);
|
constraintSet.setMargin(R.id.notification_stack_scroller, TOP, topMargin);
|
||||||
constraintSet.setMargin(R.id.qs_frame, TOP, topMargin);
|
constraintSet.setMargin(R.id.qs_frame, TOP, topMargin);
|
||||||
constraintSet.applyTo(mNotificationContainerParent);
|
constraintSet.applyTo(mNotificationContainerParent);
|
||||||
mNotificationContainerParent.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
|
mNotificationsQSContainerController.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
|
||||||
|
|
||||||
updateKeyguardStatusViewAlignment(/* animate= */false);
|
updateKeyguardStatusViewAlignment(/* animate= */false);
|
||||||
|
|
||||||
@@ -2106,7 +2110,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
|||||||
requestPanelHeightUpdate();
|
requestPanelHeightUpdate();
|
||||||
mFalsingCollector.setQsExpanded(expanded);
|
mFalsingCollector.setQsExpanded(expanded);
|
||||||
mStatusBar.setQsExpanded(expanded);
|
mStatusBar.setQsExpanded(expanded);
|
||||||
mNotificationContainerParent.setQsExpanded(expanded);
|
mNotificationsQSContainerController.setQsExpanded(expanded);
|
||||||
mPulseExpansionHandler.setQsExpanded(expanded);
|
mPulseExpansionHandler.setQsExpanded(expanded);
|
||||||
mKeyguardBypassController.setQSExpanded(expanded);
|
mKeyguardBypassController.setQSExpanded(expanded);
|
||||||
mStatusBarKeyguardViewManager.setQsExpanded(expanded);
|
mStatusBarKeyguardViewManager.setQsExpanded(expanded);
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package com.android.systemui.statusbar.phone
|
||||||
|
|
||||||
|
import android.view.WindowInsets
|
||||||
|
import com.android.systemui.navigationbar.NavigationModeController
|
||||||
|
import com.android.systemui.plugins.qs.QS
|
||||||
|
import com.android.systemui.plugins.qs.QSContainerController
|
||||||
|
import com.android.systemui.recents.OverviewProxyService
|
||||||
|
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
|
||||||
|
import com.android.systemui.shared.system.QuickStepContract
|
||||||
|
import com.android.systemui.util.ViewController
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class NotificationsQSContainerController @Inject constructor(
|
||||||
|
view: NotificationsQuickSettingsContainer,
|
||||||
|
private val navigationModeController: NavigationModeController,
|
||||||
|
private val overviewProxyService: OverviewProxyService
|
||||||
|
) : ViewController<NotificationsQuickSettingsContainer>(view), QSContainerController {
|
||||||
|
|
||||||
|
var qsExpanded = false
|
||||||
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
field = value
|
||||||
|
mView.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var splitShadeEnabled = false
|
||||||
|
set(value) {
|
||||||
|
if (field != value) {
|
||||||
|
field = value
|
||||||
|
// in case device configuration changed while showing QS details/customizer
|
||||||
|
updateBottomSpacing()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isQSDetailShowing = false
|
||||||
|
private var isQSCustomizing = false
|
||||||
|
private var isQSCustomizerAnimating = false
|
||||||
|
|
||||||
|
private var notificationsBottomMargin = 0
|
||||||
|
private var bottomStableInsets = 0
|
||||||
|
private var bottomCutoutInsets = 0
|
||||||
|
|
||||||
|
private var isGestureNavigation = true
|
||||||
|
private var taskbarVisible = false
|
||||||
|
private val taskbarVisibilityListener: OverviewProxyListener = object : OverviewProxyListener {
|
||||||
|
override fun onTaskbarStatusUpdated(visible: Boolean, stashed: Boolean) {
|
||||||
|
taskbarVisible = visible
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val windowInsetsListener: Consumer<WindowInsets> = Consumer { insets ->
|
||||||
|
// when taskbar is visible, stableInsetBottom will include its height
|
||||||
|
bottomStableInsets = insets.stableInsetBottom
|
||||||
|
bottomCutoutInsets = insets.displayCutout?.safeInsetBottom ?: 0
|
||||||
|
updateBottomSpacing()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onInit() {
|
||||||
|
val currentMode: Int = navigationModeController.addListener { mode: Int ->
|
||||||
|
isGestureNavigation = QuickStepContract.isGesturalMode(mode)
|
||||||
|
}
|
||||||
|
isGestureNavigation = QuickStepContract.isGesturalMode(currentMode)
|
||||||
|
}
|
||||||
|
|
||||||
|
public override fun onViewAttached() {
|
||||||
|
notificationsBottomMargin = mView.defaultNotificationsMarginBottom
|
||||||
|
overviewProxyService.addCallback(taskbarVisibilityListener)
|
||||||
|
mView.setInsetsChangedListener(windowInsetsListener)
|
||||||
|
mView.setQSFragmentAttachedListener { qs: QS -> qs.setContainerController(this) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onViewDetached() {
|
||||||
|
overviewProxyService.removeCallback(taskbarVisibilityListener)
|
||||||
|
mView.removeOnInsetsChangedListener()
|
||||||
|
mView.removeQSFragmentAttachedListener()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setCustomizerAnimating(animating: Boolean) {
|
||||||
|
if (isQSCustomizerAnimating != animating) {
|
||||||
|
isQSCustomizerAnimating = animating
|
||||||
|
mView.invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setCustomizerShowing(showing: Boolean) {
|
||||||
|
isQSCustomizing = showing
|
||||||
|
updateBottomSpacing()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setDetailShowing(showing: Boolean) {
|
||||||
|
isQSDetailShowing = showing
|
||||||
|
updateBottomSpacing()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateBottomSpacing() {
|
||||||
|
val (containerPadding, notificationsMargin) = calculateBottomSpacing()
|
||||||
|
var qsScrollPaddingBottom = 0
|
||||||
|
if (!(splitShadeEnabled || isQSCustomizing || isQSDetailShowing || isGestureNavigation ||
|
||||||
|
taskbarVisible)) {
|
||||||
|
// no taskbar, portrait, navigation buttons enabled:
|
||||||
|
// padding is needed so QS can scroll up over bottom insets - to reach the point when
|
||||||
|
// the whole QS is above bottom insets
|
||||||
|
qsScrollPaddingBottom = bottomStableInsets
|
||||||
|
}
|
||||||
|
mView.setPadding(0, 0, 0, containerPadding)
|
||||||
|
mView.setNotificationsMarginBottom(notificationsMargin)
|
||||||
|
mView.setQSScrollPaddingBottom(qsScrollPaddingBottom)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun calculateBottomSpacing(): Pair<Int, Int> {
|
||||||
|
val containerPadding: Int
|
||||||
|
var stackScrollMargin = notificationsBottomMargin
|
||||||
|
if (splitShadeEnabled) {
|
||||||
|
if (isGestureNavigation) {
|
||||||
|
// only default cutout padding, taskbar always hides
|
||||||
|
containerPadding = bottomCutoutInsets
|
||||||
|
} else if (taskbarVisible) {
|
||||||
|
// navigation buttons + visible taskbar means we're NOT on homescreen
|
||||||
|
containerPadding = bottomStableInsets
|
||||||
|
} else {
|
||||||
|
// navigation buttons + hidden taskbar means we're on homescreen
|
||||||
|
containerPadding = 0
|
||||||
|
// we need extra margin for notifications as navigation buttons are below them
|
||||||
|
stackScrollMargin = bottomStableInsets + notificationsBottomMargin
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isQSCustomizing || isQSDetailShowing) {
|
||||||
|
// Clear out bottom paddings/margins so the qs customization can be full height.
|
||||||
|
containerPadding = 0
|
||||||
|
stackScrollMargin = 0
|
||||||
|
} else if (isGestureNavigation) {
|
||||||
|
containerPadding = bottomCutoutInsets
|
||||||
|
} else if (taskbarVisible) {
|
||||||
|
containerPadding = bottomStableInsets
|
||||||
|
} else {
|
||||||
|
containerPadding = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return containerPadding to stackScrollMargin
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,7 @@ import com.android.systemui.statusbar.notification.AboveShelfObserver;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The container with notification stack scroller and quick settings inside.
|
* The container with notification stack scroller and quick settings inside.
|
||||||
@@ -43,17 +44,15 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
|
|||||||
private View mQsFrame;
|
private View mQsFrame;
|
||||||
private View mStackScroller;
|
private View mStackScroller;
|
||||||
private View mKeyguardStatusBar;
|
private View mKeyguardStatusBar;
|
||||||
private boolean mQsExpanded;
|
|
||||||
private boolean mCustomizerAnimating;
|
|
||||||
private boolean mCustomizing;
|
|
||||||
private boolean mDetailShowing;
|
|
||||||
|
|
||||||
private int mBottomPadding;
|
|
||||||
private int mStackScrollerMargin;
|
private int mStackScrollerMargin;
|
||||||
private ArrayList<View> mDrawingOrderedChildren = new ArrayList<>();
|
private ArrayList<View> mDrawingOrderedChildren = new ArrayList<>();
|
||||||
private ArrayList<View> mLayoutDrawingOrder = new ArrayList<>();
|
private ArrayList<View> mLayoutDrawingOrder = new ArrayList<>();
|
||||||
private final Comparator<View> mIndexComparator = Comparator.comparingInt(this::indexOfChild);
|
private final Comparator<View> mIndexComparator = Comparator.comparingInt(this::indexOfChild);
|
||||||
private boolean mSplitShadeEnabled;
|
private Consumer<WindowInsets> mInsetsChangedListener = insets -> {};
|
||||||
|
private Consumer<QS> mQSFragmentAttachedListener = qs -> {};
|
||||||
|
private QS mQs;
|
||||||
|
private View mQSScrollView;
|
||||||
|
|
||||||
public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
|
public NotificationsQuickSettingsContainer(Context context, AttributeSet attrs) {
|
||||||
super(context, attrs);
|
super(context, attrs);
|
||||||
@@ -68,6 +67,59 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
|
|||||||
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
|
mKeyguardStatusBar = findViewById(R.id.keyguard_header);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFragmentViewCreated(String tag, Fragment fragment) {
|
||||||
|
mQs = (QS) fragment;
|
||||||
|
mQSFragmentAttachedListener.accept(mQs);
|
||||||
|
mQSScrollView = mQs.getView().findViewById(R.id.expanded_qs_scroll_view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf) {
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNotificationsMarginBottom(int margin) {
|
||||||
|
LayoutParams params = (LayoutParams) mStackScroller.getLayoutParams();
|
||||||
|
params.bottomMargin = margin;
|
||||||
|
mStackScroller.setLayoutParams(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQSScrollPaddingBottom(int paddingBottom) {
|
||||||
|
if (mQSScrollView != null) {
|
||||||
|
mQSScrollView.setPaddingRelative(
|
||||||
|
mQSScrollView.getPaddingLeft(),
|
||||||
|
mQSScrollView.getPaddingTop(),
|
||||||
|
mQSScrollView.getPaddingRight(),
|
||||||
|
paddingBottom
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDefaultNotificationsMarginBottom() {
|
||||||
|
return mStackScrollerMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInsetsChangedListener(Consumer<WindowInsets> onInsetsChangedListener) {
|
||||||
|
mInsetsChangedListener = onInsetsChangedListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeOnInsetsChangedListener() {
|
||||||
|
mInsetsChangedListener = insets -> {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQSFragmentAttachedListener(Consumer<QS> qsFragmentAttachedListener) {
|
||||||
|
mQSFragmentAttachedListener = qsFragmentAttachedListener;
|
||||||
|
// listener might be attached after fragment is attached
|
||||||
|
if (mQs != null) {
|
||||||
|
mQSFragmentAttachedListener.accept(mQs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeQSFragmentAttachedListener() {
|
||||||
|
mQSFragmentAttachedListener = qs -> {};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onAttachedToWindow() {
|
protected void onAttachedToWindow() {
|
||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
@@ -82,8 +134,7 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||||
mBottomPadding = insets.getStableInsetBottom();
|
mInsetsChangedListener.accept(insets);
|
||||||
setPadding(0, 0, 0, mBottomPadding);
|
|
||||||
return insets;
|
return insets;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,66 +170,4 @@ public class NotificationsQuickSettingsContainer extends ConstraintLayout
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFragmentViewCreated(String tag, Fragment fragment) {
|
|
||||||
QS container = (QS) fragment;
|
|
||||||
container.setContainer(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setQsExpanded(boolean expanded) {
|
|
||||||
if (mQsExpanded != expanded) {
|
|
||||||
mQsExpanded = expanded;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCustomizerAnimating(boolean isAnimating) {
|
|
||||||
if (mCustomizerAnimating != isAnimating) {
|
|
||||||
mCustomizerAnimating = isAnimating;
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCustomizerShowing(boolean isShowing) {
|
|
||||||
mCustomizing = isShowing;
|
|
||||||
updateBottomMargin();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDetailShowing(boolean isShowing) {
|
|
||||||
mDetailShowing = isShowing;
|
|
||||||
updateBottomMargin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets if split shade is enabled and adjusts margins/paddings depending on QS details and
|
|
||||||
* customizer state
|
|
||||||
*/
|
|
||||||
public void setSplitShadeEnabled(boolean splitShadeEnabled) {
|
|
||||||
mSplitShadeEnabled = splitShadeEnabled;
|
|
||||||
// in case device was rotated while showing QS details/customizer
|
|
||||||
updateBottomMargin();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateBottomMargin() {
|
|
||||||
// in split shade, QS state changes should not influence notifications panel
|
|
||||||
if (!mSplitShadeEnabled && (mCustomizing || mDetailShowing)) {
|
|
||||||
// Clear out bottom paddings/margins so the qs customization can be full height.
|
|
||||||
setPadding(0, 0, 0, 0);
|
|
||||||
setBottomMargin(mStackScroller, 0);
|
|
||||||
} else {
|
|
||||||
setPadding(0, 0, 0, mBottomPadding);
|
|
||||||
setBottomMargin(mStackScroller, mStackScrollerMargin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setBottomMargin(View v, int bottomMargin) {
|
|
||||||
LayoutParams params = (LayoutParams) v.getLayoutParams();
|
|
||||||
params.bottomMargin = bottomMargin;
|
|
||||||
v.setLayoutParams(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onHasViewsAboveShelfChanged(boolean hasViewsAboveShelf) {
|
|
||||||
invalidate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,9 @@ import com.android.systemui.statusbar.NotificationShelf;
|
|||||||
import com.android.systemui.statusbar.NotificationShelfController;
|
import com.android.systemui.statusbar.NotificationShelfController;
|
||||||
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
|
import com.android.systemui.statusbar.notification.row.dagger.NotificationShelfComponent;
|
||||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
|
||||||
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
|
|
||||||
import com.android.systemui.statusbar.phone.NotificationPanelView;
|
import com.android.systemui.statusbar.phone.NotificationPanelView;
|
||||||
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
|
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
|
||||||
|
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
|
||||||
import com.android.systemui.statusbar.phone.TapAgainView;
|
import com.android.systemui.statusbar.phone.TapAgainView;
|
||||||
import com.android.systemui.util.InjectionInflationController;
|
import com.android.systemui.util.InjectionInflationController;
|
||||||
|
|
||||||
@@ -67,8 +67,8 @@ public abstract class StatusBarViewModule {
|
|||||||
@Provides
|
@Provides
|
||||||
@StatusBarComponent.StatusBarScope
|
@StatusBarComponent.StatusBarScope
|
||||||
public static NotificationStackScrollLayout providesNotificationStackScrollLayout(
|
public static NotificationStackScrollLayout providesNotificationStackScrollLayout(
|
||||||
NotificationStackScrollLayoutController notificationStackScrollLayoutController) {
|
NotificationShadeWindowView notificationShadeWindowView) {
|
||||||
return notificationStackScrollLayoutController.getView();
|
return notificationShadeWindowView.findViewById(R.id.notification_stack_scroller);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** */
|
/** */
|
||||||
@@ -149,4 +149,12 @@ public abstract class StatusBarViewModule {
|
|||||||
public static TapAgainView getTapAgainView(NotificationPanelView npv) {
|
public static TapAgainView getTapAgainView(NotificationPanelView npv) {
|
||||||
return npv.getTapAgainView();
|
return npv.getTapAgainView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** */
|
||||||
|
@Provides
|
||||||
|
@StatusBarComponent.StatusBarScope
|
||||||
|
public static NotificationsQuickSettingsContainer getNotificationsQuickSettingsContainer(
|
||||||
|
NotificationShadeWindowView notificationShadeWindowView) {
|
||||||
|
return notificationShadeWindowView.findViewById(R.id.notification_container_parent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -300,6 +300,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
|
|||||||
private LockscreenGestureLogger mLockscreenGestureLogger;
|
private LockscreenGestureLogger mLockscreenGestureLogger;
|
||||||
@Mock
|
@Mock
|
||||||
private DumpManager mDumpManager;
|
private DumpManager mDumpManager;
|
||||||
|
@Mock
|
||||||
|
private NotificationsQSContainerController mNotificationsQSContainerController;
|
||||||
|
|
||||||
private SysuiStatusBarStateController mStatusBarStateController;
|
private SysuiStatusBarStateController mStatusBarStateController;
|
||||||
private NotificationPanelViewController mNotificationPanelViewController;
|
private NotificationPanelViewController mNotificationPanelViewController;
|
||||||
@@ -414,6 +416,7 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
|
|||||||
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
|
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
|
||||||
mConversationNotificationManager, mMediaHiearchyManager,
|
mConversationNotificationManager, mMediaHiearchyManager,
|
||||||
mStatusBarKeyguardViewManager,
|
mStatusBarKeyguardViewManager,
|
||||||
|
mNotificationsQSContainerController,
|
||||||
mNotificationStackScrollLayoutController,
|
mNotificationStackScrollLayoutController,
|
||||||
mKeyguardStatusViewComponentFactory,
|
mKeyguardStatusViewComponentFactory,
|
||||||
mKeyguardQsUserSwitchComponentFactory,
|
mKeyguardQsUserSwitchComponentFactory,
|
||||||
|
|||||||
@@ -0,0 +1,254 @@
|
|||||||
|
package com.android.systemui.statusbar.phone
|
||||||
|
|
||||||
|
import android.testing.AndroidTestingRunner
|
||||||
|
import android.testing.TestableLooper
|
||||||
|
import android.view.WindowInsets
|
||||||
|
import android.view.WindowManagerPolicyConstants
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.android.systemui.navigationbar.NavigationModeController
|
||||||
|
import com.android.systemui.navigationbar.NavigationModeController.ModeChangedListener
|
||||||
|
import com.android.systemui.recents.OverviewProxyService
|
||||||
|
import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mockito.ArgumentCaptor
|
||||||
|
import org.mockito.Captor
|
||||||
|
import org.mockito.Mock
|
||||||
|
import org.mockito.Mockito
|
||||||
|
import org.mockito.Mockito.RETURNS_DEEP_STUBS
|
||||||
|
import org.mockito.Mockito.anyInt
|
||||||
|
import org.mockito.Mockito.doNothing
|
||||||
|
import org.mockito.Mockito.eq
|
||||||
|
import org.mockito.Mockito.mock
|
||||||
|
import org.mockito.Mockito.verify
|
||||||
|
import org.mockito.MockitoAnnotations
|
||||||
|
import java.util.function.Consumer
|
||||||
|
import org.mockito.Mockito.`when` as whenever
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
@RunWith(AndroidTestingRunner::class)
|
||||||
|
@TestableLooper.RunWithLooper
|
||||||
|
class NotificationQSContainerControllerTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val STABLE_INSET_BOTTOM = 100
|
||||||
|
const val CUTOUT_HEIGHT = 50
|
||||||
|
const val GESTURES_NAVIGATION = WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL
|
||||||
|
const val BUTTONS_NAVIGATION = WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON
|
||||||
|
const val NOTIFICATIONS_MARGIN = 50
|
||||||
|
}
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private lateinit var navigationModeController: NavigationModeController
|
||||||
|
@Mock
|
||||||
|
private lateinit var overviewProxyService: OverviewProxyService
|
||||||
|
@Mock
|
||||||
|
private lateinit var notificationsQSContainer: NotificationsQuickSettingsContainer
|
||||||
|
@Captor
|
||||||
|
lateinit var navigationModeCaptor: ArgumentCaptor<ModeChangedListener>
|
||||||
|
@Captor
|
||||||
|
lateinit var taskbarVisibilityCaptor: ArgumentCaptor<OverviewProxyListener>
|
||||||
|
@Captor
|
||||||
|
lateinit var windowInsetsCallbackCaptor: ArgumentCaptor<Consumer<WindowInsets>>
|
||||||
|
|
||||||
|
private lateinit var notificationsQSContainerController: NotificationsQSContainerController
|
||||||
|
private lateinit var navigationModeCallback: ModeChangedListener
|
||||||
|
private lateinit var taskbarVisibilityCallback: OverviewProxyListener
|
||||||
|
private lateinit var windowInsetsCallback: Consumer<WindowInsets>
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
MockitoAnnotations.initMocks(this)
|
||||||
|
notificationsQSContainerController = NotificationsQSContainerController(
|
||||||
|
notificationsQSContainer,
|
||||||
|
navigationModeController,
|
||||||
|
overviewProxyService
|
||||||
|
)
|
||||||
|
whenever(notificationsQSContainer.defaultNotificationsMarginBottom)
|
||||||
|
.thenReturn(NOTIFICATIONS_MARGIN)
|
||||||
|
whenever(navigationModeController.addListener(navigationModeCaptor.capture()))
|
||||||
|
.thenReturn(GESTURES_NAVIGATION)
|
||||||
|
doNothing().`when`(overviewProxyService).addCallback(taskbarVisibilityCaptor.capture())
|
||||||
|
doNothing().`when`(notificationsQSContainer)
|
||||||
|
.setInsetsChangedListener(windowInsetsCallbackCaptor.capture())
|
||||||
|
|
||||||
|
notificationsQSContainerController.init()
|
||||||
|
notificationsQSContainerController.onViewAttached()
|
||||||
|
|
||||||
|
navigationModeCallback = navigationModeCaptor.value
|
||||||
|
taskbarVisibilityCallback = taskbarVisibilityCaptor.value
|
||||||
|
windowInsetsCallback = windowInsetsCallbackCaptor.value
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testTaskbarVisibleInSplitShade() {
|
||||||
|
notificationsQSContainerController.splitShadeEnabled = true
|
||||||
|
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 testTaskbarNotVisibleInSplitShade() {
|
||||||
|
// when taskbar is not visible, it means we're on the home screen
|
||||||
|
notificationsQSContainerController.splitShadeEnabled = true
|
||||||
|
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 testTaskbarNotVisibleInSplitShadeWithCutout() {
|
||||||
|
notificationsQSContainerController.splitShadeEnabled = true
|
||||||
|
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 testTaskbarVisibleInSinglePaneShade() {
|
||||||
|
notificationsQSContainerController.splitShadeEnabled = 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 testTaskbarNotVisibleInSinglePaneShade() {
|
||||||
|
notificationsQSContainerController.splitShadeEnabled = false
|
||||||
|
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)
|
||||||
|
// 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() {
|
||||||
|
notificationsQSContainerController.splitShadeEnabled = false
|
||||||
|
notificationsQSContainerController.setDetailShowing(true)
|
||||||
|
// 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 testDetailShowingInSplitShade() {
|
||||||
|
notificationsQSContainerController.splitShadeEnabled = true
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun given(
|
||||||
|
taskbarVisible: Boolean,
|
||||||
|
navigationMode: Int,
|
||||||
|
insets: WindowInsets
|
||||||
|
) {
|
||||||
|
Mockito.clearInvocations(notificationsQSContainer)
|
||||||
|
taskbarVisibilityCallback.onTaskbarStatusUpdated(taskbarVisible, false)
|
||||||
|
navigationModeCallback.onNavigationModeChanged(navigationMode)
|
||||||
|
windowInsetsCallback.accept(insets)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun then(
|
||||||
|
expectedContainerPadding: Int,
|
||||||
|
expectedNotificationsMargin: Int = NOTIFICATIONS_MARGIN,
|
||||||
|
expectedQsPadding: Int = 0
|
||||||
|
) {
|
||||||
|
verify(notificationsQSContainer)
|
||||||
|
.setPadding(anyInt(), anyInt(), anyInt(), eq(expectedContainerPadding))
|
||||||
|
verify(notificationsQSContainer).setNotificationsMarginBottom(expectedNotificationsMargin)
|
||||||
|
verify(notificationsQSContainer).setQSScrollPaddingBottom(expectedQsPadding)
|
||||||
|
Mockito.clearInvocations(notificationsQSContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun windowInsets() = mock(WindowInsets::class.java, RETURNS_DEEP_STUBS)
|
||||||
|
|
||||||
|
private fun emptyInsets() = mock(WindowInsets::class.java)
|
||||||
|
|
||||||
|
private fun WindowInsets.withCutout(): WindowInsets {
|
||||||
|
whenever(displayCutout.safeInsetBottom).thenReturn(CUTOUT_HEIGHT)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun WindowInsets.withStableBottom(): WindowInsets {
|
||||||
|
whenever(stableInsetBottom).thenReturn(STABLE_INSET_BOTTOM)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user