Merge "A new shade pull down animation" into sc-dev

This commit is contained in:
Lucas Dupin
2021-04-25 01:03:18 +00:00
committed by Android (Google) Code Review
20 changed files with 527 additions and 117 deletions

View File

@@ -14,7 +14,6 @@
package com.android.systemui.plugins.qs;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
@@ -57,7 +56,6 @@ public interface QS extends FragmentBase {
void setQsExpansion(float qsExpansionFraction, float headerTranslation);
void setHeaderListening(boolean listening);
void notifyCustomizeChanged();
void setContainer(ViewGroup container);
void setExpandClickListener(OnClickListener onClickListener);
@@ -75,6 +73,16 @@ public interface QS extends FragmentBase {
return isShowingDetail();
}
/**
* If QS should translate as we pull it down, or if it should be static.
*/
void setTranslateWhileExpanding(boolean shouldTranslate);
/**
* A rounded corner clipping that makes QS feel as if it were behind everything.
*/
void setFancyClipping(int top, int bottom, int cornerRadius, boolean visible);
@ProvidesInterface(version = HeightListener.VERSION)
interface HeightListener {
int VERSION = 1;

View File

@@ -43,7 +43,7 @@
android:visibility="invisible" />
</com.android.systemui.statusbar.BackDropView>
<com.android.systemui.statusbar.ScrimView
<com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_behind"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -51,7 +51,7 @@
sysui:ignoreRightInset="true"
/>
<com.android.systemui.statusbar.ScrimView
<com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_notifications"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -72,7 +72,7 @@
<include layout="@layout/brightness_mirror_container" />
<com.android.systemui.statusbar.ScrimView
<com.android.systemui.scrim.ScrimView
android:id="@+id/scrim_in_front"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -16,6 +16,7 @@
package com.android.keyguard;
import android.graphics.Rect;
import android.os.UserHandle;
import android.util.Slog;
@@ -48,6 +49,7 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
private final ConfigurationController mConfigurationController;
private final DozeParameters mDozeParameters;
private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
private final Rect mClipBounds = new Rect();
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
@@ -299,4 +301,17 @@ public class KeyguardStatusViewController extends ViewController<KeyguardStatusV
mView.updateLogoutView(shouldShowLogout());
}
};
/**
* Rect that specifies how KSV should be clipped, on its parent's coordinates.
*/
public void setClipBounds(Rect clipBounds) {
if (clipBounds != null) {
mClipBounds.set(clipBounds.left, (int) (clipBounds.top - mView.getY()),
clipBounds.right, (int) (clipBounds.bottom - mView.getY()));
mView.setClipBounds(mClipBounds);
} else {
mView.setClipBounds(null);
}
}
}

View File

@@ -98,7 +98,6 @@ import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
@@ -117,6 +116,7 @@ import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.GlobalActions.GlobalActionsManager;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.scrim.ScrimDrawable;
import com.android.systemui.statusbar.NotificationShadeDepthController;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.policy.ConfigurationController;

View File

@@ -30,11 +30,11 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.internal.R;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.scrim.ScrimDrawable;
import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.ScrimController;

View File

@@ -29,6 +29,7 @@ public class NonInterceptingScrollView extends ScrollView {
private final int mTouchSlop;
private float mDownY;
private boolean mScrollEnabled = true;
public NonInterceptingScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -85,6 +86,16 @@ public class NonInterceptingScrollView extends ScrollView {
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean canScrollVertically(int direction) {
return mScrollEnabled && super.canScrollVertically(direction);
}
@Override
public boolean canScrollHorizontally(int direction) {
return mScrollEnabled && super.canScrollHorizontally(direction);
}
public int getScrollRange() {
int scrollRange = 0;
if (getChildCount() > 0) {
@@ -94,4 +105,12 @@ public class NonInterceptingScrollView extends ScrollView {
}
return scrollRange;
}
/**
* Enable scrolling for this view. Needed because the view might be clipped but still intercepts
* touches on the lockscreen.
*/
public void setScrollingEnabled(boolean enabled) {
mScrollEnabled = enabled;
}
}

View File

@@ -54,6 +54,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
public static final float EXPANDED_TILE_DELAY = .86f;
public static final float SHORT_PARALLAX_AMOUNT = 0.1f;
private static final long QQS_FADE_IN_DURATION = 200L;
// Fade out faster than fade in to finish before QQS hides.
private static final long QQS_FADE_OUT_DURATION = 50L;
@@ -101,6 +102,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
private final Executor mExecutor;
private final TunerService mTunerService;
private boolean mShowCollapsedOnKeyguard;
private boolean mTranslateWhileExpanding;
@Inject
public QSAnimator(QS qs, QuickQSPanel quickPanel, QuickStatusBarHeader quickStatusBarHeader,
@@ -242,6 +244,9 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
int width = mQs.getView() != null ? mQs.getView().getMeasuredWidth() : 0;
int heightDiff = height - mQs.getHeader().getBottom()
+ mQs.getHeader().getPaddingBottom();
if (!mTranslateWhileExpanding) {
heightDiff *= SHORT_PARALLAX_AMOUNT;
}
firstPageBuilder.addFloat(tileLayout, "translationY", heightDiff, 0);
int qqsTileHeight = 0;
@@ -570,6 +575,13 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
setCurrentPosition();
};
/**
* True whe QS will be pulled from the top, false when it will be clipped.
*/
public void setTranslateWhileExpanding(boolean shouldTranslate) {
mTranslateWhileExpanding = shouldTranslate;
}
static class HeightExpansionAnimator {
private final List<View> mViews = new ArrayList<>();
private final ValueAnimator mAnimator;

View File

@@ -20,6 +20,8 @@ import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Path;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.View;
@@ -54,6 +56,10 @@ public class QSContainerImpl extends FrameLayout {
private static final PhysicsAnimator.SpringConfig BACKGROUND_SPRING
= new PhysicsAnimator.SpringConfig(SpringForce.STIFFNESS_MEDIUM,
SpringForce.DAMPING_RATIO_LOW_BOUNCY);
private int mFancyClippingTop;
private int mFancyClippingBottom;
private final float[] mFancyClippingRadii = new float[] {0, 0, 0, 0, 0, 0, 0, 0};
private final Path mFancyClippingPath = new Path();
private int mBackgroundBottom = -1;
private int mHeightOverride = -1;
private View mQSDetail;
@@ -70,6 +76,7 @@ public class QSContainerImpl extends FrameLayout {
private int mContentPadding = -1;
private boolean mAnimateBottomOnNextLayout;
private int mNavBarInset = 0;
private boolean mClippingEnabled;
public QSContainerImpl(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -169,6 +176,15 @@ public class QSContainerImpl extends FrameLayout {
MeasureSpec.makeMeasureSpec(getDisplayHeight(), MeasureSpec.EXACTLY));
}
@Override
public void dispatchDraw(Canvas canvas) {
if (!mFancyClippingPath.isEmpty()) {
canvas.translate(0, -getTranslationY());
canvas.clipOutPath(mFancyClippingPath);
canvas.translate(0, getTranslationY());
}
super.dispatchDraw(canvas);
}
@Override
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed,
@@ -187,6 +203,7 @@ public class QSContainerImpl extends FrameLayout {
super.onLayout(changed, left, top, right, bottom);
updateExpansion(mAnimateBottomOnNextLayout /* animate */);
mAnimateBottomOnNextLayout = false;
updateClippingPath();
}
public void disable(int state1, int state2, boolean animate) {
@@ -281,6 +298,7 @@ public class QSContainerImpl extends FrameLayout {
public void setExpansion(float expansion) {
mQsExpansion = expansion;
mQSPanelContainer.setScrollingEnabled(expansion > 0.0f);
updateExpansion();
}
@@ -318,4 +336,46 @@ public class QSContainerImpl extends FrameLayout {
}
return mSizePoint.y;
}
/**
* Clip QS bottom using a concave shape.
*/
public void setFancyClipping(int top, int bottom, int radius, boolean enabled) {
boolean updatePath = false;
if (mFancyClippingRadii[0] != radius) {
mFancyClippingRadii[0] = radius;
mFancyClippingRadii[1] = radius;
mFancyClippingRadii[2] = radius;
mFancyClippingRadii[3] = radius;
updatePath = true;
}
if (mFancyClippingTop != top) {
mFancyClippingTop = top;
updatePath = true;
}
if (mFancyClippingBottom != bottom) {
mFancyClippingBottom = bottom;
updatePath = true;
}
if (mClippingEnabled != enabled) {
mClippingEnabled = enabled;
updatePath = true;
}
if (updatePath) {
updateClippingPath();
}
}
private void updateClippingPath() {
mFancyClippingPath.reset();
if (!mClippingEnabled) {
invalidate();
return;
}
mFancyClippingPath.addRoundRect(0, mFancyClippingTop, getWidth(),
mFancyClippingBottom, mFancyClippingRadii, Path.Direction.CW);
invalidate();
}
}

View File

@@ -107,6 +107,11 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
private QuickQSPanelController mQuickQSPanelController;
private QSCustomizerController mQSCustomizerController;
private FeatureFlags mFeatureFlags;
/**
* When true, QS will translate from outside the screen. It will be clipped with parallax
* otherwise.
*/
private boolean mTranslateWhileExpanding;
@Inject
public QSFragment(RemoteInputQuickSettingsDisabler remoteInputQsDisabler,
@@ -254,6 +259,13 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
}
}
@Override
public void setFancyClipping(int top, int bottom, int cornerRadius, boolean visible) {
if (getView() instanceof QSContainerImpl) {
((QSContainerImpl) getView()).setFancyClipping(top, bottom, cornerRadius, visible);
}
}
private void setEditLocation(View view) {
View edit = view.findViewById(android.R.id.edit);
int[] loc = edit.getLocationOnScreen();
@@ -393,17 +405,24 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
mFooter.setListening(listening);
}
@Override
public void setTranslateWhileExpanding(boolean shouldTranslate) {
mTranslateWhileExpanding = shouldTranslate;
mQSAnimator.setTranslateWhileExpanding(shouldTranslate);
}
@Override
public void setQsExpansion(float expansion, float headerTranslation) {
if (DEBUG) Log.d(TAG, "setQSExpansion " + expansion + " " + headerTranslation);
if (mQSAnimator != null) {
final boolean showQSOnLockscreen = expansion > 0;
final boolean showQSUnlocked = headerTranslation == 0;
final boolean showQSUnlocked = headerTranslation == 0 || !mTranslateWhileExpanding;
mQSAnimator.startAlphaAnimation(showQSOnLockscreen || showQSUnlocked);
}
mContainer.setExpansion(expansion);
final float translationScaleY = expansion - 1;
final float translationScaleY = (mTranslateWhileExpanding
? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
boolean onKeyguardAndExpanded = isKeyguardShowing() && !mShowCollapsedOnKeyguard;
if (!mHeaderAnimating && !headerWillBeAnimating()) {
getView().setTranslationY(

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 The Android Open Source Project
* 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.internal.colorextraction.drawable;
package com.android.systemui.scrim;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -49,6 +49,7 @@ public class ScrimDrawable extends Drawable {
private float mCornerRadius;
private Rect mBounds;
private ConcaveInfo mConcaveInfo;
private int mBottomEdgePosition;
public ScrimDrawable() {
mPaint = new Paint();
@@ -143,21 +144,43 @@ public class ScrimDrawable extends Drawable {
* Make bottom edge concave with provided corner radius
*/
public void setBottomEdgeConcave(float radius) {
if (radius == 0) {
// Disable clipping completely when there's no radius.
mConcaveInfo = null;
return;
}
// only rounding top corners for clip out path
float[] cornerRadii = new float[]{radius, radius, radius, radius, 0, 0, 0, 0};
mConcaveInfo = new ConcaveInfo(radius, cornerRadii);
}
/**
* Location of concave edge.
* @see #setBottomEdgeConcave(float)
*/
public void setBottomEdgePosition(int y) {
if (mBottomEdgePosition == y) {
return;
}
mBottomEdgePosition = y;
if (mConcaveInfo == null) {
return;
}
updatePath();
invalidateSelf();
}
@Override
public void draw(@NonNull Canvas canvas) {
mPaint.setColor(mMainColor);
mPaint.setAlpha(mAlpha);
if (mConcaveInfo != null) {
drawConcave(canvas);
} else {
canvas.drawRoundRect(getBounds().left, getBounds().top, getBounds().right,
getBounds().bottom + mCornerRadius,
/* x radius*/ mCornerRadius, /* y radius*/ mCornerRadius, mPaint);
}
canvas.drawRoundRect(getBounds().left, getBounds().top, getBounds().right,
getBounds().bottom + mCornerRadius,
/* x radius*/ mCornerRadius, /* y radius*/ mCornerRadius, mPaint);
}
private void drawConcave(Canvas canvas) {
@@ -165,19 +188,23 @@ public class ScrimDrawable extends Drawable {
if (mBounds == null
|| getBounds().right != mBounds.right
|| getBounds().left != mBounds.left) {
mConcaveInfo.mPath.reset();
float left = getBounds().left;
float right = getBounds().right;
float top = 0f;
float bottom = mConcaveInfo.mPathOverlap;
mConcaveInfo.mPath.addRoundRect(left, top, right, bottom,
mConcaveInfo.mCornerRadii, Path.Direction.CW);
mBounds = getBounds();
updatePath();
}
mBounds = getBounds();
int translation = (int) (mBounds.bottom - mConcaveInfo.mPathOverlap);
canvas.translate(0, translation);
canvas.clipOutPath(mConcaveInfo.mPath);
canvas.translate(0, -translation);
canvas.drawRect(getBounds().left, getBounds().top, getBounds().right,
mBottomEdgePosition + mConcaveInfo.mPathOverlap, mPaint);
}
private void updatePath() {
mConcaveInfo.mPath.reset();
if (mBounds == null) {
mBounds = getBounds();
}
float top = mBottomEdgePosition;
float bottom = mBottomEdgePosition + mConcaveInfo.mPathOverlap;
mConcaveInfo.mPath.addRoundRect(mBounds.left, top, mBounds.right, bottom,
mConcaveInfo.mCornerRadii, Path.Direction.CW);
}
@VisibleForTesting

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2014 The Android Open Source Project
* 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.
@@ -11,10 +11,10 @@
* 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
* limitations under the License.
*/
package com.android.systemui.statusbar;
package com.android.systemui.scrim;
import static java.lang.Float.isNaN;
@@ -38,7 +38,6 @@ import androidx.core.graphics.ColorUtils;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.systemui.R;
import java.util.concurrent.Executor;
@@ -96,6 +95,9 @@ public class ScrimView extends View {
});
}
/**
* Needed for WM Shell, which has its own thread structure.
*/
public void setExecutor(Executor executor, Looper looper) {
mExecutor = executor;
mExecutorLooper = looper;
@@ -108,7 +110,8 @@ public class ScrimView extends View {
}
}
public void setDrawable(Drawable drawable) {
@VisibleForTesting
void setDrawable(Drawable drawable) {
executeOnExecutor(() -> {
mDrawable = drawable;
mDrawable.setCallback(this);
@@ -144,16 +147,24 @@ public class ScrimView extends View {
});
}
/**
* Sets the color of the scrim, without animating them.
*/
public void setColors(@NonNull ColorExtractor.GradientColors colors) {
setColors(colors, false);
}
/**
* Sets the scrim colors, optionally animating them.
* @param colors The colors.
* @param animated If we should animate the transition.
*/
public void setColors(@NonNull ColorExtractor.GradientColors colors, boolean animated) {
if (colors == null) {
throw new IllegalArgumentException("Colors cannot be null");
}
executeOnExecutor(() -> {
synchronized(mColorLock) {
synchronized (mColorLock) {
if (mColors.equals(colors)) {
return;
}
@@ -168,17 +179,28 @@ public class ScrimView extends View {
return mDrawable;
}
/**
* Returns current scrim colors.
*/
public ColorExtractor.GradientColors getColors() {
synchronized(mColorLock) {
synchronized (mColorLock) {
mTmpColors.set(mColors);
}
return mTmpColors;
}
/**
* Applies tint to this view, without animations.
*/
public void setTint(int color) {
setTint(color, false);
}
/**
* Tints this view, optionally animating it.
* @param color The color.
* @param animated If we should animate.
*/
public void setTint(int color, boolean animated) {
executeOnExecutor(() -> {
if (mTintColor == color) {
@@ -200,8 +222,8 @@ public class ScrimView extends View {
} else {
boolean hasAlpha = Color.alpha(mTintColor) != 0;
if (hasAlpha) {
PorterDuff.Mode targetMode = mColorFilter == null ? Mode.SRC_OVER :
mColorFilter.getMode();
PorterDuff.Mode targetMode = mColorFilter == null
? Mode.SRC_OVER : mColorFilter.getMode();
if (mColorFilter == null || mColorFilter.getColor() != mTintColor) {
mColorFilter = new PorterDuffColorFilter(mTintColor, targetMode);
}
@@ -254,6 +276,9 @@ public class ScrimView extends View {
return mViewAlpha;
}
/**
* Sets a callback that is invoked whenever the alpha, color, or tint change.
*/
public void setChangeRunnable(Runnable changeRunnable, Executor changeRunnableExecutor) {
mChangeRunnable = changeRunnable;
mChangeRunnableExecutor = changeRunnableExecutor;
@@ -276,15 +301,25 @@ public class ScrimView extends View {
* Make bottom edge concave so overlap between layers is not visible for alphas between 0 and 1
* @return height of concavity
*/
public float enableBottomEdgeConcave() {
public float enableBottomEdgeConcave(boolean clipScrim) {
if (mDrawable instanceof ScrimDrawable) {
float radius = getResources().getDimensionPixelSize(CORNER_RADIUS);
float radius = clipScrim ? getResources().getDimensionPixelSize(CORNER_RADIUS) : 0;
((ScrimDrawable) mDrawable).setBottomEdgeConcave(radius);
return radius;
}
return 0;
}
/**
* The position of the bottom of the scrim, used for clipping.
* @see #enableBottomEdgeConcave(boolean)
*/
public void setBottomEdgePosition(int y) {
if (mDrawable instanceof ScrimDrawable) {
((ScrimDrawable) mDrawable).setBottomEdgePosition(y);
}
}
/**
* Enable view to have rounded corners with radius of {@link #CORNER_RADIUS}
*/

View File

@@ -780,7 +780,7 @@ public class NotificationStackScrollLayoutController {
return mView.isLayoutRtl();
}
public float getLeft() {
public int getLeft() {
return mView.getLeft();
}

View File

@@ -515,6 +515,7 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mDelayShowingKeyguardStatusBar;
private boolean mAnimatingQS;
private final Rect mKeyguardStatusAreaClipBounds = new Rect();
private int mOldLayoutDirection;
private NotificationShelfController mNotificationShelfController;
@@ -522,6 +523,7 @@ public class NotificationPanelViewController extends PanelViewController {
private final Executor mUiExecutor;
private int mLockScreenMode = KeyguardUpdateMonitor.LOCK_SCREEN_MODE_NORMAL;
private int mScrimCornerRadius;
private View.AccessibilityDelegate mAccessibilityDelegate = new View.AccessibilityDelegate() {
@Override
@@ -628,6 +630,7 @@ public class NotificationPanelViewController extends PanelViewController {
mDozeParameters = dozeParameters;
mBiometricUnlockController = biometricUnlockController;
mScrimController = scrimController;
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
mUserManager = userManager;
mMediaDataManager = mediaDataManager;
mQuickAccessWalletClient = quickAccessWalletClient;
@@ -852,10 +855,16 @@ public class NotificationPanelViewController extends PanelViewController {
public void updateResources() {
mSplitShadeNotificationsTopPadding =
mResources.getDimensionPixelSize(R.dimen.notifications_top_padding_split_shade);
mScrimCornerRadius =
mResources.getDimensionPixelSize(R.dimen.notification_scrim_corner_radius);
int qsWidth = mResources.getDimensionPixelSize(R.dimen.qs_panel_width);
int panelWidth = mResources.getDimensionPixelSize(R.dimen.notification_panel_width);
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mFeatureFlags, mResources);
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
if (mQs != null) {
mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
}
// To change the constraints at runtime, all children of the ConstraintLayout must have ids
ensureAllViewsHaveIds(mNotificationContainerParent);
ConstraintSet constraintSet = new ConstraintSet();
@@ -2003,15 +2012,23 @@ public class NotificationPanelViewController extends PanelViewController {
mDepthController.setQsPanelExpansion(qsExpansionFraction);
}
private void setNotificationBounds(float qsExpansionFraction, int qsPanelBottomY) {
float top = 0;
float bottom = 0;
float left = 0;
float right = 0;
if (qsPanelBottomY > 0) {
// notification shade is expanding/expanded
/**
* Updates scrim bounds, QS clipping, and KSV clipping as well based on the bounds of the shade
* and QS state.
*
* @param qsFraction QS expansion fraction, from getQsExpansionFraction().
* @param qsPanelBottomY Absolute y position of the bottom of QS as it's being pulled.
*/
private void setNotificationBounds(float qsFraction, int qsPanelBottomY) {
int top = 0;
int bottom = 0;
int left = 0;
int right = 0;
boolean visible = qsFraction > 0 || qsPanelBottomY > 0;
if (visible || !mShouldUseSplitNotificationShade) {
if (!mShouldUseSplitNotificationShade) {
top = qsPanelBottomY;
float notificationTop = mAmbientState.getStackY() - mQsNotificationTopPadding;
top = (int) Math.min(qsPanelBottomY, notificationTop);
bottom = getView().getBottom();
left = getView().getLeft();
right = getView().getRight();
@@ -2022,6 +2039,17 @@ public class NotificationPanelViewController extends PanelViewController {
right = mNotificationStackScrollLayoutController.getRight();
}
}
if (!mShouldUseSplitNotificationShade) {
// Fancy clipping for quick settings
if (mQs != null) {
mQs.setFancyClipping(top, bottom, mScrimCornerRadius, visible);
}
// The padding on this area is large enough that we can use a cheaper clipping strategy
mKeyguardStatusAreaClipBounds.set(left, top, right, bottom);
mKeyguardStatusViewController.setClipBounds(visible
? mKeyguardStatusAreaClipBounds : null);
}
mScrimController.setNotificationsBounds(left, top, right, bottom);
}
@@ -2493,6 +2521,10 @@ public class NotificationPanelViewController extends PanelViewController {
float appearAmount = mNotificationStackScrollLayoutController
.calculateAppearFraction(mExpandedHeight);
float startHeight = -mQsExpansionHeight;
if (!mShouldUseSplitNotificationShade && mBarState == StatusBarState.SHADE) {
// Small parallax as we pull down and clip QS
startHeight = -mQsExpansionHeight * 0.2f;
}
if (mKeyguardBypassController.getBypassEnabled() && isOnKeyguard()
&& mNotificationStackScrollLayoutController.isPulseExpanding()) {
if (!mPulseExpansionHandler.isExpanding()
@@ -3128,8 +3160,10 @@ public class NotificationPanelViewController extends PanelViewController {
mQs.setPanelView(mHeightListener);
mQs.setExpandClickListener(mOnClickListener);
mQs.setHeaderClickable(mQsExpansionEnabled);
mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
updateQSPulseExpansion();
mQs.setOverscrolling(mStackScrollerOverscrolling);
mQs.setTranslateWhileExpanding(mShouldUseSplitNotificationShade);
// recompute internal state when qspanel height changes
mQs.getView().addOnLayoutChangeListener(
@@ -3925,7 +3959,10 @@ public class NotificationPanelViewController extends PanelViewController {
// animate out
// the top of QS
if (!mQsExpanded) {
mQs.animateHeaderSlidingOut();
// TODO(b/185683835) Nicer clipping when using new spacial model
if (mShouldUseSplitNotificationShade) {
mQs.animateHeaderSlidingOut();
}
}
} else {
mKeyguardStatusBar.setAlpha(1f);

View File

@@ -147,9 +147,6 @@ public abstract class PanelViewController {
private float mInitialTouchX;
private boolean mTouchDisabled;
// AmbientState will never be null since it provides an @Inject constructor for Dagger to call.
private AmbientState mAmbientState;
/**
* Whether or not the PanelView can be expanded or collapsed with a drag.
*/
@@ -172,6 +169,7 @@ public abstract class PanelViewController {
protected final Resources mResources;
protected final KeyguardStateController mKeyguardStateController;
protected final SysuiStatusBarStateController mStatusBarStateController;
protected final AmbientState mAmbientState;
protected void onExpandingFinished() {
mBar.onExpandingFinished();

View File

@@ -48,8 +48,8 @@ import com.android.systemui.R;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.stack.ViewState;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -96,6 +96,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
* When at least 1 scrim is fully opaque (alpha set to 1.)
*/
public static final int OPAQUE = 2;
private boolean mClipsQsScrim;
@IntDef(prefix = {"VISIBILITY_"}, value = {
TRANSPARENT,
@@ -165,6 +166,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
// Assuming the shade is expanded during initialization
private float mExpansionFraction = 1f;
private float mQsExpansion;
private boolean mQsBottomVisible;
private boolean mDarkenWhileDragging;
private boolean mExpansionAffectsAlpha = true;
@@ -183,6 +185,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
private int mInFrontTint;
private int mBehindTint;
private int mNotificationsTint;
private int mBubbleTint;
private boolean mWallpaperVisibilityTimedOut;
@@ -265,6 +268,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mScrimForBubble = scrimForBubble;
updateThemeColors();
behindScrim.enableBottomEdgeConcave(mClipsQsScrim);
mNotificationsScrim.enableRoundedCorners();
if (mScrimBehindChangeRunnable != null) {
@@ -331,14 +335,17 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
mInFrontTint = state.getFrontTint();
mBehindTint = state.getBehindTint();
mNotificationsTint = state.getNotifTint();
mBubbleTint = state.getBubbleTint();
mInFrontAlpha = state.getFrontAlpha();
mBehindAlpha = state.getBehindAlpha();
mBubbleAlpha = state.getBubbleAlpha();
if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) {
mNotificationsAlpha = state.getNotifAlpha();
if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha) || isNaN(mNotificationsAlpha)) {
throw new IllegalStateException("Scrim opacity is NaN for state: " + state + ", front: "
+ mInFrontAlpha + ", back: " + mBehindAlpha);
+ mInFrontAlpha + ", back: " + mBehindAlpha + ", notif: "
+ mNotificationsAlpha);
}
applyExpansionToAlpha();
@@ -397,7 +404,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
scheduleUpdate();
}
dispatchScrimState(mScrimBehind.getViewAlpha());
dispatchBackScrimState(mScrimBehind.getViewAlpha());
}
private boolean shouldFadeAwayWallpaper() {
@@ -491,21 +498,25 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
*/
public void setNotificationsBounds(float left, float top, float right, float bottom) {
mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
if (mClipsQsScrim) {
mScrimBehind.setBottomEdgePosition((int) top);
}
}
/**
* Current state of the QuickSettings when pulling it from the top.
*
* @param expansionFraction From 0 to 1 where 0 means collapsed and 1 expanded.
* @param qsPanelBottomY absolute Y position of qs panel bottom
* @param qsPanelBottomY Absolute Y position of qs panel bottom
*/
public void setQsPosition(float expansionFraction, int qsPanelBottomY) {
if (isNaN(expansionFraction)) {
return;
}
updateNotificationsScrimAlpha(expansionFraction, qsPanelBottomY);
if (mQsExpansion != expansionFraction) {
boolean qsBottomVisible = qsPanelBottomY > 0;
if (mQsExpansion != expansionFraction || mQsBottomVisible != qsBottomVisible) {
mQsExpansion = expansionFraction;
mQsBottomVisible = qsBottomVisible;
boolean relevantState = (mState == ScrimState.SHADE_LOCKED
|| mState == ScrimState.KEYGUARD
|| mState == ScrimState.PULSING
@@ -517,22 +528,26 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
}
private void updateNotificationsScrimAlpha(float qsExpansion, int qsPanelBottomY) {
float newAlpha = 0;
if (qsPanelBottomY > 0) {
float interpolator = 0;
if (mState == ScrimState.UNLOCKED || mState == ScrimState.SHADE_LOCKED) {
interpolator = getInterpolatedFraction();
} else {
interpolator = qsExpansion;
}
newAlpha = MathUtils.lerp(0, 1, interpolator);
/**
* If QS and notification scrims should not overlap, and should be clipped to each other's
* bounds instead.
*/
public void setClipsQsScrim(boolean clipScrim) {
if (clipScrim == mClipsQsScrim) {
return;
}
if (newAlpha != mNotificationsAlpha) {
mNotificationsAlpha = newAlpha;
// update alpha without animating
mNotificationsScrim.setViewAlpha(newAlpha);
mClipsQsScrim = clipScrim;
for (ScrimState state : ScrimState.values()) {
state.setClipQsScrim(mClipsQsScrim);
}
if (mScrimBehind != null) {
mScrimBehind.enableBottomEdgeConcave(mClipsQsScrim);
}
}
@VisibleForTesting
public boolean getClipQsScrim() {
return mClipsQsScrim;
}
private void setOrAdaptCurrentAnimation(@Nullable View scrim) {
@@ -541,7 +556,8 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
float alpha = getCurrentScrimAlpha(scrim);
if (isAnimating(scrim)) {
boolean qsScrimPullingDown = scrim == mScrimBehind && mQsBottomVisible;
if (isAnimating(scrim) && !qsScrimPullingDown) {
// Adapt current animation.
ValueAnimator previousAnimator = (ValueAnimator) scrim.getTag(TAG_KEY_ANIM);
float previousEndValue = (Float) scrim.getTag(TAG_END_ALPHA);
@@ -562,7 +578,19 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
return;
}
if (mState == ScrimState.UNLOCKED || mState == ScrimState.BUBBLE_EXPANDED) {
if (mState == ScrimState.UNLOCKED) {
// Darken scrim as you pull down the shade when unlocked
float behindFraction = getInterpolatedFraction();
behindFraction = (float) Math.pow(behindFraction, 0.8f);
if (mClipsQsScrim) {
mBehindAlpha = 1;
mNotificationsAlpha = behindFraction * mDefaultScrimAlpha;
} else {
mBehindAlpha = behindFraction * mDefaultScrimAlpha;
mNotificationsAlpha = mBehindAlpha;
}
mInFrontAlpha = 0;
} else if (mState == ScrimState.BUBBLE_EXPANDED) {
// Darken scrim as you pull down the shade when unlocked
float behindFraction = getInterpolatedFraction();
behindFraction = (float) Math.pow(behindFraction, 0.8f);
@@ -573,27 +601,45 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
// Either darken of make the scrim transparent when you
// pull down the shade
float interpolatedFract = getInterpolatedFraction();
float alphaBehind = mState.getBehindAlpha();
float stateBehind = mClipsQsScrim ? mState.getNotifAlpha() : mState.getBehindAlpha();
float backAlpha;
if (mDarkenWhileDragging) {
mBehindAlpha = MathUtils.lerp(mDefaultScrimAlpha, alphaBehind,
backAlpha = MathUtils.lerp(mDefaultScrimAlpha, stateBehind,
interpolatedFract);
mInFrontAlpha = mState.getFrontAlpha();
} else {
mBehindAlpha = MathUtils.lerp(0 /* start */, alphaBehind,
backAlpha = MathUtils.lerp(0 /* start */, stateBehind,
interpolatedFract);
mInFrontAlpha = mState.getFrontAlpha();
}
mBehindTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
mState.getBehindTint(), interpolatedFract);
mInFrontAlpha = mState.getFrontAlpha();
int backTint;
if (mClipsQsScrim) {
backTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getNotifTint(),
mState.getNotifTint(), interpolatedFract);
} else {
backTint = ColorUtils.blendARGB(ScrimState.BOUNCER.getBehindTint(),
mState.getBehindTint(), interpolatedFract);
}
if (mQsExpansion > 0) {
mBehindAlpha = MathUtils.lerp(mBehindAlpha, mDefaultScrimAlpha, mQsExpansion);
mBehindTint = ColorUtils.blendARGB(mBehindTint,
ScrimState.SHADE_LOCKED.getBehindTint(), mQsExpansion);
backAlpha = MathUtils.lerp(backAlpha, mDefaultScrimAlpha, mQsExpansion);
int stateTint = mClipsQsScrim ? ScrimState.SHADE_LOCKED.getNotifTint()
: ScrimState.SHADE_LOCKED.getBehindTint();
backTint = ColorUtils.blendARGB(backTint, stateTint, mQsExpansion);
}
if (mClipsQsScrim) {
mNotificationsAlpha = backAlpha;
mNotificationsTint = backTint;
mBehindAlpha = 1;
mBehindTint = Color.BLACK;
} else {
mBehindAlpha = backAlpha;
mNotificationsAlpha = Math.max(1.0f - getInterpolatedFraction(), mQsExpansion);
mBehindTint = backTint;
}
}
if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha)) {
if (isNaN(mBehindAlpha) || isNaN(mInFrontAlpha) || isNaN(mNotificationsAlpha)) {
throw new IllegalStateException("Scrim opacity is NaN for state: " + mState
+ ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha);
+ ", front: " + mInFrontAlpha + ", back: " + mBehindAlpha + ", notif: "
+ mNotificationsAlpha);
}
}
@@ -606,7 +652,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
setOrAdaptCurrentAnimation(mNotificationsScrim);
setOrAdaptCurrentAnimation(mScrimInFront);
setOrAdaptCurrentAnimation(mScrimForBubble);
dispatchScrimState(mScrimBehind.getViewAlpha());
dispatchBackScrimState(mScrimBehind.getViewAlpha());
// Reset wallpaper timeout if it's already timeout like expanding panel while PULSING
// and docking.
@@ -693,10 +739,10 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
&& !mBlankScreen;
mScrimInFront.setColors(mColors, animateScrimInFront);
mScrimBehind.setColors(mColors, animateScrimNotifications);
mScrimBehind.setColors(mColors, animateBehindScrim);
mNotificationsScrim.setColors(mColors, animateScrimNotifications);
dispatchScrimState(mScrimBehind.getViewAlpha());
dispatchBackScrimState(mScrimBehind.getViewAlpha());
}
// We want to override the back scrim opacity for the AOD state
@@ -723,15 +769,21 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
dispatchScrimsVisible();
}
private void dispatchScrimState(float alpha) {
private void dispatchBackScrimState(float alpha) {
// When clipping QS, the notification scrim is the one that feels behind.
// mScrimBehind will be drawing black and its opacity will always be 1.
if (mClipsQsScrim && mQsBottomVisible) {
alpha = mNotificationsAlpha;
}
mScrimStateListener.accept(mState, alpha, mScrimInFront.getColors());
}
private void dispatchScrimsVisible() {
final ScrimView backScrim = mClipsQsScrim ? mNotificationsScrim : mScrimBehind;
final int currentScrimVisibility;
if (mScrimInFront.getViewAlpha() == 1 || mScrimBehind.getViewAlpha() == 1) {
if (mScrimInFront.getViewAlpha() == 1 || backScrim.getViewAlpha() == 1) {
currentScrimVisibility = OPAQUE;
} else if (mScrimInFront.getViewAlpha() == 0 && mScrimBehind.getViewAlpha() == 0) {
} else if (mScrimInFront.getViewAlpha() == 0 && backScrim.getViewAlpha() == 0) {
currentScrimVisibility = TRANSPARENT;
} else {
currentScrimVisibility = SEMI_TRANSPARENT;
@@ -859,7 +911,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
} else if (scrim == mScrimBehind) {
return mBehindTint;
} else if (scrim == mNotificationsScrim) {
return Color.TRANSPARENT;
return mNotificationsTint;
} else if (scrim == mScrimForBubble) {
return mBubbleTint;
} else {
@@ -917,9 +969,11 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
if (mState == ScrimState.UNLOCKED) {
mInFrontTint = Color.TRANSPARENT;
mBehindTint = mState.getBehindTint();
mNotificationsTint = mState.getNotifTint();
mBubbleTint = Color.TRANSPARENT;
updateScrimColor(mScrimInFront, mInFrontAlpha, mInFrontTint);
updateScrimColor(mScrimBehind, mBehindAlpha, mBehindTint);
updateScrimColor(mNotificationsScrim, mNotificationsAlpha, mNotificationsTint);
if (mScrimForBubble != null) {
updateScrimColor(mScrimForBubble, mBubbleAlpha, mBubbleTint);
}
@@ -964,7 +1018,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, Dump
}
if (scrim == mScrimBehind) {
dispatchScrimState(alpha);
dispatchBackScrimState(alpha);
}
final boolean wantsAlphaUpdate = alpha != currentAlpha;

View File

@@ -22,7 +22,7 @@ import android.os.Trace;
import androidx.annotation.Nullable;
import com.android.systemui.dock.DockManager;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
/**
@@ -80,11 +80,16 @@ public enum ScrimState {
}
mFrontTint = Color.BLACK;
mBehindTint = Color.BLACK;
mNotifTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
mBubbleTint = Color.TRANSPARENT;
mFrontAlpha = 0;
mBehindAlpha = mScrimBehindAlphaKeyguard;
mBehindAlpha = mClipQsScrim ? 1 : mScrimBehindAlphaKeyguard;
mNotifAlpha = mClipQsScrim ? mScrimBehindAlphaKeyguard : 0;
mBubbleAlpha = 0;
if (mClipQsScrim) {
updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
}
}
},
@@ -105,7 +110,10 @@ public enum ScrimState {
BOUNCER {
@Override
public void prepare(ScrimState previousState) {
mBehindAlpha = mDefaultScrimAlpha;
mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
mBehindTint = mClipQsScrim ? Color.BLACK : Color.TRANSPARENT;
mNotifAlpha = mClipQsScrim ? mDefaultScrimAlpha : 0;
mNotifTint = Color.TRANSPARENT;
mFrontAlpha = 0f;
mBubbleAlpha = 0f;
}
@@ -126,10 +134,15 @@ public enum ScrimState {
SHADE_LOCKED {
@Override
public void prepare(ScrimState previousState) {
mBehindAlpha = mDefaultScrimAlpha;
mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
mNotifAlpha = 1f;
mBubbleAlpha = 0f;
mFrontAlpha = 0f;
mBehindTint = Color.BLACK;
if (mClipQsScrim) {
updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
}
}
// to make sure correct color is returned before "prepare" is called
@@ -224,7 +237,8 @@ public enum ScrimState {
@Override
public void prepare(ScrimState previousState) {
// State that UI will sync to.
mBehindAlpha = 0;
mBehindAlpha = mClipQsScrim ? 1 : 0;
mNotifAlpha = 0;
mFrontAlpha = 0;
mBubbleAlpha = 0;
@@ -253,6 +267,10 @@ public enum ScrimState {
mBubbleTint = Color.BLACK;
mBlankScreen = true;
}
if (mClipQsScrim) {
updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
}
}
},
@@ -279,12 +297,14 @@ public enum ScrimState {
int mFrontTint = Color.TRANSPARENT;
int mBehindTint = Color.TRANSPARENT;
int mBubbleTint = Color.TRANSPARENT;
int mNotifTint = Color.TRANSPARENT;
boolean mAnimateChange = true;
float mAodFrontScrimAlpha;
float mFrontAlpha;
float mBehindAlpha;
float mBubbleAlpha;
float mNotifAlpha;
float mScrimBehindAlphaKeyguard;
float mDefaultScrimAlpha;
@@ -301,6 +321,7 @@ public enum ScrimState {
boolean mWakeLockScreenSensorActive;
boolean mKeyguardFadingAway;
long mKeyguardFadingAwayDuration;
boolean mClipQsScrim;
public void init(ScrimView scrimInFront, ScrimView scrimBehind, ScrimView scrimForBubble,
DozeParameters dozeParameters, DockManager dockManager) {
@@ -325,6 +346,10 @@ public enum ScrimState {
return mBehindAlpha;
}
public float getNotifAlpha() {
return mNotifAlpha;
}
public float getBubbleAlpha() {
return mBubbleAlpha;
}
@@ -337,6 +362,10 @@ public enum ScrimState {
return mBehindTint;
}
public int getNotifTint() {
return mNotifTint;
}
public int getBubbleTint() {
return mBubbleTint;
}
@@ -406,4 +435,8 @@ public enum ScrimState {
mKeyguardFadingAway = fadingAway;
mKeyguardFadingAwayDuration = duration;
}
public void setClipQsScrim(boolean clipsQsScrim) {
mClipQsScrim = clipsQsScrim;
}
}

View File

@@ -21,7 +21,6 @@ import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.WindowType;
import static android.app.StatusBarManager.WindowVisibleState;
import static android.app.StatusBarManager.windowStateToString;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
import static android.view.InsetsState.containsType;
@@ -180,6 +179,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.qs.QSFragment;
import com.android.systemui.qs.QSPanelController;
import com.android.systemui.recents.ScreenPinningRequest;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.settings.brightness.BrightnessSlider;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.AutoHideUiElement;
@@ -202,7 +202,6 @@ import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.NotificationViewHierarchyManager;
import com.android.systemui.statusbar.PowerButtonReveal;
import com.android.systemui.statusbar.PulseExpansionHandler;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
import com.android.systemui.statusbar.SysuiStatusBarStateController;

View File

@@ -63,11 +63,11 @@ import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.model.SysUiState;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.notification.NotificationChannelHelper;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2017 The Android Open Source Project
* 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.
@@ -11,10 +11,10 @@
* 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
* limitations under the License.
*/
package com.android.systemui.statusbar;
package com.android.systemui.scrim;
import static junit.framework.Assert.assertEquals;
@@ -31,7 +31,6 @@ import android.view.View;
import androidx.test.filters.SmallTest;
import com.android.internal.colorextraction.ColorExtractor;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.utils.leaks.LeakCheckedTest;

View File

@@ -49,8 +49,8 @@ import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.systemui.DejankUtils;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dock.DockManager;
import com.android.systemui.scrim.ScrimView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.ScrimView;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -69,6 +69,7 @@ import org.mockito.stubbing.Answer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -91,7 +92,7 @@ public class ScrimControllerTest extends SysuiTestCase {
@Mock
private AlarmManager mAlarmManager;
@Mock
private DozeParameters mDozeParamenters;
private DozeParameters mDozeParameters;
@Mock
LightBarController mLightBarController;
@Mock
@@ -200,8 +201,8 @@ public class ScrimControllerTest extends SysuiTestCase {
return null;
}).when(mScrimBehind).postOnAnimationDelayed(any(Runnable.class), anyLong());
when(mDozeParamenters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
when(mDozeParamenters.getDisplayNeedsBlanking()).thenReturn(true);
when(mDozeParameters.getAlwaysOn()).thenAnswer(invocation -> mAlwaysOnEnabled);
when(mDozeParameters.getDisplayNeedsBlanking()).thenReturn(true);
doAnswer((Answer<Void>) invocation -> {
mScrimState = invocation.getArgument(0);
@@ -220,7 +221,7 @@ public class ScrimControllerTest extends SysuiTestCase {
when(mDockManager.isDocked()).thenReturn(false);
mScrimController = new ScrimController(mLightBarController,
mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
mDozeParameters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder,
new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor,
mDockManager, mConfigurationController, mFeatureFlags,
new FakeExecutor(new FakeSystemClock()));
@@ -238,6 +239,10 @@ public class ScrimControllerTest extends SysuiTestCase {
@After
public void tearDown() {
finishAnimationsImmediately();
Arrays.stream(ScrimState.values()).forEach((scrim) -> {
scrim.setAodFrontScrimAlpha(0f);
scrim.setClipQsScrim(false);
});
DejankUtils.setImmediate(false);
}
@@ -259,9 +264,30 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void transitionToShadeLocked() {
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
mScrimController.setQsPosition(1f, 0);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mNotificationsScrim, OPAQUE,
mScrimInFront, TRANSPARENT,
mScrimBehind, OPAQUE));
assertScrimTinted(Map.of(
mScrimInFront, false,
mScrimBehind, true,
mScrimForBubble, false
));
}
@Test
public void transitionToShadeLocked_clippingQs() {
mScrimController.setClipsQsScrim(true);
mScrimController.transitionTo(ScrimState.SHADE_LOCKED);
mScrimController.setQsPosition(1f, 0);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mNotificationsScrim, OPAQUE,
mScrimInFront, TRANSPARENT,
mScrimBehind, OPAQUE));
@@ -403,9 +429,6 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.setAodFrontScrimAlpha(0.3f);
Assert.assertEquals(ScrimState.AOD.getFrontAlpha(), mScrimInFront.getViewAlpha(), 0.001f);
Assert.assertNotEquals(0.3f, mScrimInFront.getViewAlpha(), 0.001f);
// Reset value since enums are static.
mScrimController.setAodFrontScrimAlpha(0f);
}
@Test
@@ -500,11 +523,34 @@ public class ScrimControllerTest extends SysuiTestCase {
// Back scrim should be visible without tint
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, TRANSPARENT,
mScrimBehind, OPAQUE));
assertScrimTinted(Map.of(
mScrimInFront, false,
mScrimBehind, false,
mNotificationsScrim, false,
mScrimForBubble, false
));
}
@Test
public void transitionToKeyguardBouncer_clippingQs() {
mScrimController.setClipsQsScrim(true);
mScrimController.transitionTo(ScrimState.BOUNCER);
finishAnimationsImmediately();
// Front scrim should be transparent
// Back scrim should be clipping QS
// Notif scrim should be visible without tint
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, OPAQUE,
mScrimBehind, OPAQUE));
assertScrimTinted(Map.of(
mScrimInFront, false,
mScrimBehind, true,
mNotificationsScrim, false,
mScrimForBubble, false
));
}
@@ -530,9 +576,11 @@ public class ScrimControllerTest extends SysuiTestCase {
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, TRANSPARENT,
mScrimBehind, TRANSPARENT));
assertScrimTinted(Map.of(
mNotificationsScrim, false,
mScrimInFront, false,
mScrimBehind, true,
mScrimForBubble, false
@@ -542,6 +590,7 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.setPanelExpansion(0.5f);
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mNotificationsScrim, SEMI_TRANSPARENT,
mScrimBehind, SEMI_TRANSPARENT));
}
@@ -616,6 +665,32 @@ public class ScrimControllerTest extends SysuiTestCase {
mNotificationsScrim, OPAQUE));
}
@Test
public void qsExpansion_clippingQs() {
reset(mScrimBehind);
mScrimController.setClipsQsScrim(true);
mScrimController.setQsPosition(1f, 999 /* value doesn't matter */);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mScrimBehind, OPAQUE,
mNotificationsScrim, OPAQUE));
}
@Test
public void qsExpansion_half_clippingQs() {
reset(mScrimBehind);
mScrimController.setClipsQsScrim(true);
mScrimController.setQsPosition(0.5f, 999 /* value doesn't matter */);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimInFront, TRANSPARENT,
mScrimBehind, OPAQUE,
mNotificationsScrim, SEMI_TRANSPARENT));
}
@Test
public void panelExpansionAffectsAlpha() {
mScrimController.setPanelExpansion(0f);
@@ -919,13 +994,13 @@ public class ScrimControllerTest extends SysuiTestCase {
@Test
public void testAnimatesTransitionToAod() {
when(mDozeParamenters.shouldControlScreenOff()).thenReturn(false);
when(mDozeParameters.shouldControlScreenOff()).thenReturn(false);
ScrimState.AOD.prepare(ScrimState.KEYGUARD);
Assert.assertFalse("No animation when ColorFade kicks in",
ScrimState.AOD.getAnimateChange());
reset(mDozeParamenters);
when(mDozeParamenters.shouldControlScreenOff()).thenReturn(true);
reset(mDozeParameters);
when(mDozeParameters.shouldControlScreenOff()).thenReturn(true);
ScrimState.AOD.prepare(ScrimState.KEYGUARD);
Assert.assertTrue("Animate scrims when ColorFade won't be triggered",
ScrimState.AOD.getAnimateChange());
@@ -977,6 +1052,7 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimController.setPanelExpansion(0.5f);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0, 300);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimBehind, SEMI_TRANSPARENT,
@@ -984,6 +1060,21 @@ public class ScrimControllerTest extends SysuiTestCase {
mScrimInFront, TRANSPARENT));
}
@Test
public void testScrimsVisible_whenShadeVisible_clippingQs() {
mScrimController.setClipsQsScrim(true);
mScrimController.transitionTo(ScrimState.UNLOCKED);
mScrimController.setPanelExpansion(0.5f);
// notifications scrim alpha change require calling setQsPosition
mScrimController.setQsPosition(0.5f, 300);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
mScrimBehind, OPAQUE,
mNotificationsScrim, SEMI_TRANSPARENT,
mScrimInFront, TRANSPARENT));
}
@Test
public void testScrimsVisible_whenShadeVisibleOnLockscreen() {
mScrimController.transitionTo(ScrimState.KEYGUARD);
@@ -1008,8 +1099,6 @@ public class ScrimControllerTest extends SysuiTestCase {
}
private void assertScrimTinted(Map<ScrimView, Boolean> scrimToTint) {
// notifications scrim should have always transparent tint
assertScrimTint(mNotificationsScrim, false);
scrimToTint.forEach((scrim, hasTint) -> assertScrimTint(scrim, hasTint));
}
@@ -1047,6 +1136,12 @@ public class ScrimControllerTest extends SysuiTestCase {
}
scrimToAlpha.forEach((scrimView, alpha) -> assertScrimAlpha(scrimView, alpha));
// When clipping, QS scrim should not affect combined visibility.
if (mScrimController.getClipQsScrim() && scrimToAlpha.get(mScrimBehind) == OPAQUE) {
scrimToAlpha = new HashMap<>(scrimToAlpha);
scrimToAlpha.remove(mScrimBehind);
}
// Check combined scrim visibility.
final int visibility;
if (scrimToAlpha.values().contains(OPAQUE)) {