Merge "Remove stack scroller references from StatusBar"
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index e7fc3c9..2dd54aa 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -23,6 +23,7 @@
import android.os.Process;
import android.os.ServiceManager;
import android.util.ArrayMap;
+import android.util.DisplayMetrics;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
@@ -51,6 +52,7 @@
import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
import com.android.systemui.statusbar.phone.LightBarController;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.ManagedProfileController;
import com.android.systemui.statusbar.phone.ManagedProfileControllerImpl;
import com.android.systemui.statusbar.phone.StatusBarIconController;
@@ -328,6 +330,12 @@
mProviders.put(IStatusBarService.class, () -> IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE)));
+ // Single instance of DisplayMetrics, gets updated by StatusBar, but can be used
+ // anywhere it is needed.
+ mProviders.put(DisplayMetrics.class, () -> new DisplayMetrics());
+
+ mProviders.put(LockscreenGestureLogger.class, () -> new LockscreenGestureLogger());
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
index 187d2d07..7a69f2e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
@@ -43,12 +43,12 @@
return;
}
synchronized (mListeners) {
- for (StateListener listener : mListeners) {
+ for (StateListener listener : new ArraySet<>(mListeners)) {
listener.onStatePreChange(mState, state);
}
mLastState = mState;
mState = state;
- for (StateListener listener : mListeners) {
+ for (StateListener listener : new ArraySet<>(mListeners)) {
listener.onStateChanged(mState);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index b5a51d7..ed06752 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -91,7 +91,7 @@
mActivityManagerWrapper = ActivityManagerWrapper.getInstance();
mActivityManagerWrapper.registerTaskStackListener(mTaskStackListener);
- mStackScroller.setScrollingEnabled(true);
+ mNotificationPanel.setScrollingEnabled(true);
createBatteryController();
mCarBatteryController.startListening();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
index 46019e3..4c1938a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java
@@ -417,6 +417,7 @@
public void setWillBeGone(boolean willBeGone) {
mWillBeGone = willBeGone;
+ invalidate();
}
public int getMinClipTopAmount() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index b2b415c..4f554b6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -28,7 +28,9 @@
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.FloatRange;
import android.annotation.Nullable;
+import android.app.WallpaperManager;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Canvas;
@@ -40,16 +42,22 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
+import android.os.ServiceManager;
+import android.provider.Settings;
import android.service.notification.StatusBarNotification;
+
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.ColorUtils;
+
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.util.MathUtils;
import android.util.Pair;
import android.view.ContextThemeWrapper;
import android.view.InputDevice;
+import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
@@ -66,24 +74,36 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.statusbar.IStatusBarService;
import com.android.keyguard.KeyguardSliceView;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
+import com.android.systemui.SwipeHelper.Callback;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
+import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
+import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
+import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
import com.android.systemui.statusbar.notification.NotificationData;
@@ -99,10 +119,16 @@
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone.AnimationStateHandler;
+import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
+import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
+import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
@@ -119,10 +145,11 @@
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
*/
public class NotificationStackScrollLayout extends ViewGroup
- implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter,
- ExpandableView.OnHeightChangedListener, NotificationGroupManager.OnGroupChangeListener,
- NotificationMenuRowPlugin.OnMenuEventListener, VisibilityLocationProvider,
- NotificationListContainer {
+ implements Callback, ExpandHelper.Callback, ScrollAdapter,
+ OnHeightChangedListener, OnGroupChangeListener,
+ OnMenuEventListener, VisibilityLocationProvider,
+ NotificationListContainer, ConfigurationListener, DragDownCallback, AnimationStateHandler,
+ Dumpable {
public static final float BACKGROUND_ALPHA_DIMMED = 0.7f;
private static final String TAG = "StackScroller";
@@ -421,10 +448,25 @@
private float mVerticalPanelTranslation;
private final NotificationLockscreenUserManager mLockscreenUserManager =
Dependency.get(NotificationLockscreenUserManager.class);
+ private final Rect mTmpRect = new Rect();
+ private final NotificationEntryManager mEntryManager =
+ Dependency.get(NotificationEntryManager.class);
+ private final IStatusBarService mBarService = IStatusBarService.Stub.asInterface(
+ ServiceManager.getService(Context.STATUS_BAR_SERVICE));
+ private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
+ private final NotificationRemoteInputManager mRemoteInputManager =
+ Dependency.get(NotificationRemoteInputManager.class);
+ private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
+
+ private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
+ private final LockscreenGestureLogger mLockscreenGestureLogger =
+ Dependency.get(LockscreenGestureLogger.class);
+ private final VisualStabilityManager mVisualStabilityManager =
+ Dependency.get(VisualStabilityManager.class);
+ protected boolean mClearAllEnabled;
private Interpolator mDarkXInterpolator = Interpolators.FAST_OUT_SLOW_IN;
-
- private final StateListener mStateListener = this::setStatusBarState;
+ private NotificationPanelView mNotificationPanel;
public NotificationStackScrollLayout(Context context) {
this(context, null);
@@ -481,18 +523,102 @@
mDebugPaint.setStrokeWidth(2);
mDebugPaint.setStyle(Paint.Style.STROKE);
}
+ mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+
+ inflateEmptyShadeView();
+ inflateFooterView();
+ mVisualStabilityManager.setVisibilityLocationProvider(this);
+ setLongPressListener(mEntryManager.getNotificationLongClicker());
+ }
+
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ inflateFooterView();
+ inflateEmptyShadeView();
+ updateFooter();
+ }
+
+ @Override
+ public void onThemeChanged() {
+ int which;
+ if (mStatusBarState == StatusBarState.KEYGUARD
+ || mStatusBarState == StatusBarState.SHADE_LOCKED) {
+ which = WallpaperManager.FLAG_LOCK;
+ } else {
+ which = WallpaperManager.FLAG_SYSTEM;
+ }
+ final boolean useDarkText = mColorExtractor.getColors(which,
+ true /* ignoreVisibility */).supportsDarkText();
+ updateDecorViews(useDarkText);
+
+ updateFooter();
+ }
+
+ @VisibleForTesting
+ public void updateFooter() {
+ boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
+ boolean showFooterView = (showDismissView ||
+ mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
+ && mStatusBarState != StatusBarState.KEYGUARD
+ && !mRemoteInputManager.getController().isRemoteInputActive();
+
+ updateFooterView(showFooterView, showDismissView);
+ }
+
+ /**
+ * Return whether there are any clearable notifications
+ */
+ public boolean hasActiveClearableNotifications() {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View child = getChildAt(i);
+ if (!(child instanceof ExpandableNotificationRow)) {
+ continue;
+ }
+ if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public RemoteInputController.Delegate createDelegate() {
+ return new RemoteInputController.Delegate() {
+ public void setRemoteInputActive(NotificationData.Entry entry,
+ boolean remoteInputActive) {
+ mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
+ entry.row.notifyHeightChanged(true /* needsAnimation */);
+ updateFooter();
+ }
+
+ public void lockScrollTo(NotificationData.Entry entry) {
+ NotificationStackScrollLayout.this.lockScrollTo(entry.row);
+ }
+
+ public void requestDisallowLongPressAndDismiss() {
+ requestDisallowLongPress();
+ requestDisallowDismiss();
+ }
+ };
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+ Dependency.get(ConfigurationController.class).addCallback(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(StatusBarStateController.class).removeListener(mStateListener);
+ Dependency.get(ConfigurationController.class).removeCallback(this);
}
@Override
@@ -532,6 +658,7 @@
mSwipeHelper.onMenuShown(row);
}
+ @Override
public void onUiModeChanged() {
mBgColor = mContext.getColor(R.color.notification_shade_background_color);
updateBackgroundDimming();
@@ -809,8 +936,8 @@
private void updateClippingToTopRoundedCorner() {
Float clipStart = (float) mTopPadding
- + mStackTranslation
- + mAmbientState.getExpandAnimationTopChange();
+ + mStackTranslation
+ + mAmbientState.getExpandAnimationTopChange();
Float clipEnd = clipStart + mCornerRadius;
boolean first = true;
for (int i = 0; i < getChildCount(); i++) {
@@ -842,7 +969,8 @@
: increasedPaddingAmount == -1.0f ? 0 : mPaddingBetweenElements;
int childHeight = getIntrinsicHeight(child) + padding;
if (startingPosition < mOwnScrollY) {
- // This child starts off screen, so let's keep it offscreen to keep the others visible
+ // This child starts off screen, so let's keep it offscreen to keep the
+ // others visible
setOwnScrollY(mOwnScrollY + childHeight);
}
@@ -904,7 +1032,7 @@
updateContentHeight();
if (animate && mAnimationsEnabled && mIsExpanded) {
mTopPaddingNeedsAnimation = true;
- mNeedsAnimation = true;
+ mNeedsAnimation = true;
}
requestChildrenUpdate();
notifyHeightChangeListener(null, animate);
@@ -1014,7 +1142,7 @@
/**
* @return The translation at the beginning when expanding.
- * Measured relative to the resting position.
+ * Measured relative to the resting position.
*/
private float getExpandTranslationStart() {
return -mTopPadding + getMinExpansionHeight();
@@ -1022,7 +1150,7 @@
/**
* @return the position from where the appear transition starts when expanding.
- * Measured in absolute height.
+ * Measured in absolute height.
*/
private float getAppearStartPosition() {
if (isHeadsUpTransition()) {
@@ -1033,8 +1161,8 @@
/**
* @return the height of the top heads up notification when pinned. This is different from the
- * intrinsic height, which also includes whether the notification is system expanded and
- * is mainly used when dragging down from a heads up notification.
+ * intrinsic height, which also includes whether the notification is system expanded and
+ * is mainly used when dragging down from a heads up notification.
*/
private int getTopHeadsUpPinnedHeight() {
NotificationData.Entry topEntry = mHeadsUpManager.getTopEntry();
@@ -1054,7 +1182,7 @@
/**
* @return the position from where the appear transition ends when expanding.
- * Measured in absolute height.
+ * Measured in absolute height.
*/
private float getAppearEndPosition() {
int appearPosition;
@@ -1260,9 +1388,9 @@
ExpandableNotificationRow parent = row.getNotificationParent();
if (parent != null && parent.areChildrenExpanded()
&& (parent.areGutsExposed()
- || mMenuExposedView == parent
- || (parent.getNotificationChildren().size() == 1
- && parent.isClearable()))) {
+ || mMenuExposedView == parent
+ || (parent.getNotificationChildren().size() == 1
+ && parent.isClearable()))) {
// In this case the group is expanded and showing the menu for the
// group, further interaction should apply to the group, not any
// child notifications so we use the parent of the child. We also do the same
@@ -1317,8 +1445,8 @@
/**
* Get the child at a certain screen location.
*
- * @param touchX the x coordinate
- * @param touchY the y coordinate
+ * @param touchX the x coordinate
+ * @param touchY the y coordinate
* @param requireMinHeight Whether a minimum height is required for a child to be returned.
* @return the child at the given location.
*/
@@ -1349,8 +1477,8 @@
if (!mIsExpanded && row.isHeadsUp() && row.isPinned()
&& mHeadsUpManager.getTopEntry().row != row
&& mGroupManager.getGroupSummary(
- mHeadsUpManager.getTopEntry().row.getStatusBarNotification())
- != row) {
+ mHeadsUpManager.getTopEntry().row.getStatusBarNotification())
+ != row) {
continue;
}
return row.getViewAtPosition(touchY - childTop);
@@ -1453,7 +1581,7 @@
/**
* @return the scroll necessary to make the bottom edge of {@param v} align with the top of
- * the IME.
+ * the IME.
*/
private int targetScrollForView(ExpandableView v, int positionInLinearLayout) {
return positionInLinearLayout + v.getIntrinsicHeight() +
@@ -1514,7 +1642,7 @@
private void setSwipingInProgress(boolean isSwiped) {
mSwipingInProgress = isSwiped;
- if(isSwiped) {
+ if (isSwiped) {
requestDisallowInterceptTouchEvent(true);
}
}
@@ -1551,7 +1679,7 @@
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean isCancelOrUp = ev.getActionMasked() == MotionEvent.ACTION_CANCEL
- || ev.getActionMasked()== MotionEvent.ACTION_UP;
+ || ev.getActionMasked() == MotionEvent.ACTION_UP;
handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
if (mIsExpanded && !mSwipingInProgress && !mOnlyScrollingInThisMotion) {
@@ -1790,7 +1918,7 @@
*
* @param deltaY The amount to scroll upwards, has to be positive.
* @return The amount of scrolling to be performed by the scroller,
- * not handled by the overScroll amount.
+ * not handled by the overScroll amount.
*/
private float overScrollUp(int deltaY, int range) {
deltaY = Math.max(deltaY, 0);
@@ -1823,7 +1951,7 @@
*
* @param deltaY The amount to scroll downwards, has to be negative.
* @return The amount of scrolling to be performed by the scroller,
- * not handled by the overScroll amount.
+ * not handled by the overScroll amount.
*/
private float overScrollDown(int deltaY) {
deltaY = Math.min(deltaY, 0);
@@ -1949,8 +2077,8 @@
*
* @param numPixels The amount of pixels to overScroll by. These will be scaled according to
* the rubber-banding logic.
- * @param onTop Should the effect be applied on top of the scroller.
- * @param animate Should an animation be performed.
+ * @param onTop Should the effect be applied on top of the scroller.
+ * @param animate Should an animation be performed.
*/
public void setOverScrolledPixels(float numPixels, boolean onTop, boolean animate) {
setOverScrollAmount(numPixels * getRubberBandFactor(onTop), onTop, animate, true);
@@ -1960,8 +2088,8 @@
* Set the effective overScroll amount which will be directly reflected in the layout.
* By default this will also cancel animations on the same overScroll edge.
*
- * @param amount The amount to overScroll by.
- * @param onTop Should the effect be applied on top of the scroller.
+ * @param amount The amount to overScroll by.
+ * @param onTop Should the effect be applied on top of the scroller.
* @param animate Should an animation be performed.
*/
public void setOverScrollAmount(float amount, boolean onTop, boolean animate) {
@@ -1971,9 +2099,9 @@
/**
* Set the effective overScroll amount which will be directly reflected in the layout.
*
- * @param amount The amount to overScroll by.
- * @param onTop Should the effect be applied on top of the scroller.
- * @param animate Should an animation be performed.
+ * @param amount The amount to overScroll by.
+ * @param onTop Should the effect be applied on top of the scroller.
+ * @param animate Should an animation be performed.
* @param cancelAnimators Should running animations be cancelled.
*/
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
@@ -1984,12 +2112,12 @@
/**
* Set the effective overScroll amount which will be directly reflected in the layout.
*
- * @param amount The amount to overScroll by.
- * @param onTop Should the effect be applied on top of the scroller.
- * @param animate Should an animation be performed.
+ * @param amount The amount to overScroll by.
+ * @param onTop Should the effect be applied on top of the scroller.
+ * @param animate Should an animation be performed.
* @param cancelAnimators Should running animations be cancelled.
- * @param isRubberbanded The value which will be passed to
- * {@link OnOverscrollTopChangedListener#onOverscrollTopChanged}
+ * @param isRubberbanded The value which will be passed to
+ * {@link OnOverscrollTopChangedListener#onOverscrollTopChanged}
*/
public void setOverScrollAmount(float amount, boolean onTop, boolean animate,
boolean cancelAnimators, boolean isRubberbanded) {
@@ -2035,7 +2163,7 @@
}
public float getCurrentOverScrolledPixels(boolean top) {
- return top? mOverScrolledTopPixels : mOverScrolledBottomPixels;
+ return top ? mOverScrolledTopPixels : mOverScrolledBottomPixels;
}
private void setOverScrolledPixels(float amount, boolean onTop) {
@@ -2139,7 +2267,7 @@
/**
* @return The first child which has visibility unequal to GONE which is currently below the
- * given translationY or equal to it.
+ * given translationY or equal to it.
*/
private View getFirstChildBelowTranlsationY(float translationY, boolean ignoreChildren) {
int childCount = getChildCount();
@@ -2596,7 +2724,7 @@
setOverScrollAmount(0, false, false);
mMaxOverScroll = Math.abs(velocityY) / 1000f
* getRubberBandFactor(false /* onTop */) * mOverflingDistance
- + bottomAmount;
+ + bottomAmount;
} else {
// it will be set once we reach the boundary
mMaxOverScroll = 0.0f;
@@ -2628,8 +2756,8 @@
* Updates the top padding of the notifications, taking {@link #getIntrinsicPadding()} into
* account.
*
- * @param qsHeight the top padding imposed by the quick settings panel
- * @param animate whether to animate the change
+ * @param qsHeight the top padding imposed by the quick settings panel
+ * @param animate whether to animate the change
* @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
* {@code qsHeight} is the final top padding
*/
@@ -2772,7 +2900,7 @@
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > mTouchSlop
- || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop )) {
+ || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop)) {
mTouchIsClick = false;
}
break;
@@ -2873,7 +3001,7 @@
private boolean isChildInGroup(View child) {
return child instanceof ExpandableNotificationRow
&& mGroupManager.isChildInGroupWithSummary(
- ((ExpandableNotificationRow) child).getStatusBarNotification());
+ ((ExpandableNotificationRow) child).getStatusBarNotification());
}
/**
@@ -2929,7 +3057,7 @@
if (hasAddEvent) {
// This child was just added lets remove all events.
mHeadsUpChangeAnimations.removeAll(mTmpList);
- ((ExpandableNotificationRow ) child).setHeadsUpAnimatingAway(false);
+ ((ExpandableNotificationRow) child).setHeadsUpAnimatingAway(false);
}
mTmpList.clear();
return hasAddEvent;
@@ -2938,7 +3066,7 @@
/**
* @param child the child to query
* @return whether a view is not a top level child but a child notification and that group is
- * not expanded
+ * not expanded
*/
private boolean isChildInInvisibleGroup(View child) {
if (child instanceof ExpandableNotificationRow) {
@@ -3183,7 +3311,7 @@
if (currentIndex == -1) {
boolean isTransient = false;
if (child instanceof ExpandableNotificationRow
- && ((ExpandableNotificationRow)child).getTransientContainer() != null) {
+ && ((ExpandableNotificationRow) child).getTransientContainer() != null) {
isTransient = true;
}
Log.e(TAG, "Attempting to re-position "
@@ -3196,10 +3324,10 @@
if (child != null && child.getParent() == this && currentIndex != newIndex) {
mChangePositionInProgress = true;
- ((ExpandableView)child).setChangingPosition(true);
+ ((ExpandableView) child).setChangingPosition(true);
removeView(child);
addView(child, newIndex);
- ((ExpandableView)child).setChangingPosition(false);
+ ((ExpandableView) child).setChangingPosition(false);
mChangePositionInProgress = false;
if (mIsExpanded && mAnimationsEnabled && child.getVisibility() != View.GONE) {
mChildrenChangingPositions.add(child);
@@ -3310,7 +3438,7 @@
for (AnimationEvent animationEvent : mAnimationEvents) {
final int type = animationEvent.animationType;
if (type == AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
- || type == AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) {
+ || type == AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) {
hasDisappearAnimation = true;
break;
}
@@ -3489,10 +3617,10 @@
*/
/*
- * Shortcut the most recurring case: the user is in the dragging
- * state and is moving their finger. We want to intercept this
- * motion.
- */
+ * Shortcut the most recurring case: the user is in the dragging
+ * state and is moving their finger. We want to intercept this
+ * motion.
+ */
final int action = ev.getAction();
if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {
return true;
@@ -3506,9 +3634,9 @@
*/
/*
- * Locally do absolute value. mLastMotionY is set to the y value
- * of the down event.
- */
+ * Locally do absolute value. mLastMotionY is set to the y value
+ * of the down event.
+ */
final int activePointerId = mActivePointerId;
if (activePointerId == INVALID_POINTER) {
// If we don't have a valid id, the touch down wasn't on content.
@@ -3556,10 +3684,10 @@
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
/*
- * If being flinged and user touches the screen, initiate drag;
- * otherwise don't. mScroller.isFinished should be false when
- * being flinged.
- */
+ * If being flinged and user touches the screen, initiate drag;
+ * otherwise don't. mScroller.isFinished should be false when
+ * being flinged.
+ */
boolean isBeingDragged = !mScroller.isFinished();
setIsBeingDragged(isBeingDragged);
break;
@@ -3581,9 +3709,9 @@
}
/*
- * The only time we want to intercept motion events is if we are in the
- * drag mode.
- */
+ * The only time we want to intercept motion events is if we are in the
+ * drag mode.
+ */
return mIsBeingDragged;
}
@@ -3723,6 +3851,7 @@
mPanelTracking = true;
mAmbientState.setPanelTracking(true);
}
+
public void onPanelTrackingStopped() {
mPanelTracking = false;
mAmbientState.setPanelTracking(false);
@@ -3865,7 +3994,7 @@
mAmbientState.setDimmed(dimmed);
if (animate && mAnimationsEnabled) {
mDimmedNeedsAnimation = true;
- mNeedsAnimation = true;
+ mNeedsAnimation = true;
animateDimmed(dimmed);
} else {
setDimAmount(dimmed ? 1.0f : 0.0f);
@@ -3909,7 +4038,7 @@
mAmbientState.setHideSensitive(hideSensitive);
if (animate && mAnimationsEnabled) {
mHideSensitiveNeedsAnimation = true;
- mNeedsAnimation = true;
+ mNeedsAnimation = true;
}
updateContentHeight();
requestChildrenUpdate();
@@ -3923,7 +4052,7 @@
mAmbientState.setActivatedChild(activatedChild);
if (mAnimationsEnabled) {
mActivateNeedsAnimation = true;
- mNeedsAnimation = true;
+ mNeedsAnimation = true;
}
requestChildrenUpdate();
}
@@ -4078,10 +4207,11 @@
/**
* Sets the current dark amount.
*
- * @param linearDarkAmount The dark amount that follows linear interpoloation in the animation,
- * i.e. animates from 0 to 1 or vice-versa in a linear manner.
+ * @param linearDarkAmount The dark amount that follows linear interpoloation in the
+ * animation,
+ * i.e. animates from 0 to 1 or vice-versa in a linear manner.
* @param interpolatedDarkAmount The dark amount that follows the actual interpolation of the
- * animation curve.
+ * animation curve.
*/
public void setDarkAmount(float linearDarkAmount, float interpolatedDarkAmount) {
mLinearDarkAmount = linearDarkAmount;
@@ -4259,10 +4389,7 @@
public void setGroupManager(NotificationGroupManager groupManager) {
this.mGroupManager = groupManager;
- }
-
- public void onGoToKeyguard() {
- requestAnimateEverything();
+ mGroupManager.setOnGroupChangeListener(this);
}
private void requestAnimateEverything() {
@@ -4286,15 +4413,15 @@
boolean belowChild = touchY > childTop + child.getActualHeight()
- child.getClipBottomAmount();
if (child == mFooterView) {
- if(!belowChild && !mFooterView.isOnEmptySpace(touchX - mFooterView.getX(),
- touchY - childTop)) {
+ if (!belowChild && !mFooterView.isOnEmptySpace(touchX - mFooterView.getX(),
+ touchY - childTop)) {
// We clicked on the dismiss button
return false;
}
} else if (child == mEmptyShadeView) {
// We arrived at the empty shade view, for which we accept all clicks
return true;
- } else if (!belowChild){
+ } else if (!belowChild) {
// We are on a child
return false;
}
@@ -4432,6 +4559,7 @@
mHeadsUpManager = headsUpManager;
mAmbientState.setHeadsUpManager(headsUpManager);
mHeadsUpManager.addListener(mRoundnessManager);
+ mHeadsUpManager.setAnimationStateHandler(this);
}
public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
@@ -4454,7 +4582,7 @@
* Set the boundary for the bottom heads up position. The heads up will always be above this
* position.
*
- * @param height the height of the screen
+ * @param height the height of the screen
* @param bottomBarHeight the height of the bar on the bottom
*/
public void setHeadsUpBoundaries(int height, int bottomBarHeight) {
@@ -4597,7 +4725,7 @@
}
public void setShouldShowShelfOnly(boolean shouldShowShelfOnly) {
- mShouldShowShelfOnly = shouldShowShelfOnly;
+ mShouldShowShelfOnly = shouldShowShelfOnly;
updateAlgorithmLayoutMinHeight();
}
@@ -4633,6 +4761,9 @@
if (activatedChild != null) {
activatedChild.makeInactive(false /* animate */);
}
+ updateFooter();
+ updateChildren();
+ onUpdateRowStates();
}
public void setExpandingVelocity(float expandingVelocity) {
@@ -4660,6 +4791,7 @@
requestChildrenUpdate();
}
+ @Override
public void setHeadsUpGoingAwayAnimationsAllowed(boolean headsUpGoingAwayAnimationsAllowed) {
mHeadsUpGoingAwayAnimationsAllowed = headsUpGoingAwayAnimationsAllowed;
}
@@ -4674,15 +4806,15 @@
+ " alpha:%f scrollY:%d maxTopPadding:%d showShelfOnly=%s"
+ " qsExpandFraction=%f]",
this.getClass().getSimpleName(),
- mPulsing ? "T":"f",
- mAmbientState.isQsCustomizerShowing() ? "T":"f",
+ mPulsing ? "T" : "f",
+ mAmbientState.isQsCustomizerShowing() ? "T" : "f",
getVisibility() == View.VISIBLE ? "visible"
: getVisibility() == View.GONE ? "gone"
: "invisible",
getAlpha(),
mAmbientState.getScrollY(),
mMaxTopPadding,
- mShouldShowShelfOnly ? "T":"f",
+ mShouldShowShelfOnly ? "T" : "f",
mQsExpansionFraction));
}
@@ -4716,6 +4848,150 @@
mIconAreaController = controller;
}
+ public void manageNotifications(View v) {
+ Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS);
+ mStatusBar.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ }
+
+ public void clearAllNotifications() {
+ // animate-swipe all dismissable notifications, then animate the shade closed
+ int numChildren = getChildCount();
+
+ final ArrayList<View> viewsToHide = new ArrayList<>(numChildren);
+ final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
+ for (int i = 0; i < numChildren; i++) {
+ final View child = getChildAt(i);
+ if (child instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ boolean parentVisible = false;
+ boolean hasClipBounds = child.getClipBounds(mTmpRect);
+ if (canChildBeDismissed(child)) {
+ viewsToRemove.add(row);
+ if (child.getVisibility() == View.VISIBLE
+ && (!hasClipBounds || mTmpRect.height() > 0)) {
+ viewsToHide.add(child);
+ parentVisible = true;
+ }
+ } else if (child.getVisibility() == View.VISIBLE
+ && (!hasClipBounds || mTmpRect.height() > 0)) {
+ parentVisible = true;
+ }
+ List<ExpandableNotificationRow> children = row.getNotificationChildren();
+ if (children != null) {
+ for (ExpandableNotificationRow childRow : children) {
+ viewsToRemove.add(childRow);
+ if (parentVisible && row.areChildrenExpanded()
+ && canChildBeDismissed(childRow)) {
+ hasClipBounds = childRow.getClipBounds(mTmpRect);
+ if (childRow.getVisibility() == View.VISIBLE
+ && (!hasClipBounds || mTmpRect.height() > 0)) {
+ viewsToHide.add(childRow);
+ }
+ }
+ }
+ }
+ }
+ }
+ if (viewsToRemove.isEmpty()) {
+ mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ return;
+ }
+
+ mStatusBar.addPostCollapseAction(() -> {
+ setDismissAllInProgress(false);
+ for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
+ if (canChildBeDismissed(rowToRemove)) {
+ mEntryManager.removeNotification(rowToRemove.getEntry().key, null);
+ } else {
+ rowToRemove.resetTranslation();
+ }
+ }
+ try {
+ mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
+ } catch (Exception ex) {
+ }
+ });
+
+ performDismissAllAnimations(viewsToHide);
+ }
+
+ public void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
+ Runnable animationFinishAction = () -> {
+ mStatusBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+ };
+
+ if (hideAnimatedList.isEmpty()) {
+ animationFinishAction.run();
+ return;
+ }
+
+ // let's disable our normal animations
+ setDismissAllInProgress(true);
+
+ // Decrease the delay for every row we animate to give the sense of
+ // accelerating the swipes
+ int rowDelayDecrement = 10;
+ int currentDelay = 140;
+ int totalDelay = 180;
+ int numItems = hideAnimatedList.size();
+ for (int i = numItems - 1; i >= 0; i--) {
+ View view = hideAnimatedList.get(i);
+ Runnable endRunnable = null;
+ if (i == 0) {
+ endRunnable = animationFinishAction;
+ }
+ dismissViewAnimated(view, endRunnable, totalDelay, 260);
+ currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
+ totalDelay += currentDelay;
+ }
+ }
+
+ @VisibleForTesting
+ protected void inflateFooterView() {
+ FooterView footerView = (FooterView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_notification_footer, this, false);
+ footerView.setDismissButtonClickListener(v -> {
+ mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
+ clearAllNotifications();
+ });
+ footerView.setManageButtonClickListener(this::manageNotifications);
+ setFooterView(footerView);
+ }
+
+ private void inflateEmptyShadeView() {
+ EmptyShadeView view = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
+ R.layout.status_bar_no_notifications, this, false);
+ view.setText(R.string.empty_shade_text);
+ setEmptyShadeView(view);
+ }
+
+ /**
+ * Updates expanded, dimmed and locked states of notification rows.
+ */
+ public void onUpdateRowStates() {
+ changeViewPosition(mFooterView, -1);
+
+ // The following views will be moved to the end of mStackScroller. This counter represents
+ // the offset from the last child. Initialized to 1 for the very last position. It is post-
+ // incremented in the following "changeViewPosition" calls so that its value is correct for
+ // subsequent calls.
+ int offsetFromEnd = 1;
+ changeViewPosition(mEmptyShadeView,
+ getChildCount() - offsetFromEnd++);
+
+ // No post-increment for this call because it is the last one. Make sure to add one if
+ // another "changeViewPosition" call is ever added.
+ changeViewPosition(mShelf,
+ getChildCount() - offsetFromEnd);
+
+ // Scrim opacity varies based on notification count
+ mScrimController.setNotificationCount(getNotGoneChildCount());
+ }
+
+ public void setNotificationPanel(NotificationPanelView notificationPanelView) {
+ mNotificationPanel = notificationPanelView;
+ }
+
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@@ -4731,10 +5007,11 @@
/**
* Notifies a listener that the overscroll has changed.
*
- * @param amount the amount of overscroll, in pixels
+ * @param amount the amount of overscroll, in pixels
* @param isRubberbanded if true, this is a rubberbanded overscroll; if false, this is an
- * unrubberbanded motion to directly expand overscroll view (e.g expand
- * QS)
+ * unrubberbanded motion to directly expand overscroll view (e.g
+ * expand
+ * QS)
*/
void onOverscrollTopChanged(float amount, boolean isRubberbanded);
@@ -4743,7 +5020,7 @@
* start a fling animation to the expanded or collapsed overscroll view (e.g expand the QS)
*
* @param velocity The velocity that the Scroller had when over flinging
- * @param open Should the fling open or close the overscroll view.
+ * @param open Should the fling open or close the overscroll view.
*/
void flingTopOverscroll(float velocity, boolean open);
}
@@ -4944,6 +5221,84 @@
}
}
+ public boolean hasActiveNotifications() {
+ return !mEntryManager.getNotificationData().getActiveNotifications().isEmpty();
+ }
+
+ // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
+
+
+ /* Only ever called as a consequence of a lockscreen expansion gesture. */
+ @Override
+ public boolean onDraggedDown(View startingChild, int dragLengthY) {
+ if (mStatusBarState == StatusBarState.KEYGUARD
+ && hasActiveNotifications() && (!mStatusBar.isDozing() || mStatusBar.isPulsing())) {
+ mLockscreenGestureLogger.write(
+ MetricsEvent.ACTION_LS_SHADE,
+ (int) (dragLengthY / mDisplayMetrics.density),
+ 0 /* velocityDp - N/A */);
+
+ // We have notifications, go to locked shade.
+ mStatusBar.goToLockedShade(startingChild);
+ if (startingChild instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
+ row.onExpandedByGesture(true /* drag down is always an open */);
+ }
+ return true;
+ } else {
+ // abort gesture.
+ return false;
+ }
+ }
+
+ @Override
+ public void onDragDownReset() {
+ setDimmed(true /* dimmed */, true /* animated */);
+ resetScrollPosition();
+ resetCheckSnoozeLeavebehind();
+ }
+
+ @Override
+ public void onCrossedThreshold(boolean above) {
+ setDimmed(!above /* dimmed */, true /* animate */);
+ }
+
+ @Override
+ public void onTouchSlopExceeded() {
+ cancelLongPress();
+ checkSnoozeLeavebehind();
+ }
+
+ @Override
+ public void setEmptyDragAmount(float amount) {
+ mNotificationPanel.setEmptyDragAmount(amount);
+ }
+
+ @Override
+ public boolean isFalsingCheckNeeded() {
+ return mStatusBarState == StatusBarState.KEYGUARD;
+ }
+
+ public void updateSpeedBumpIndex() {
+ int speedBumpIndex = 0;
+ int currentIndex = 0;
+ final int N = getChildCount();
+ for (int i = 0; i < N; i++) {
+ View view = getChildAt(i);
+ if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
+ continue;
+ }
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ currentIndex++;
+ if (!mEntryManager.getNotificationData().isAmbient(
+ row.getStatusBarNotification().getKey())) {
+ speedBumpIndex = currentIndex;
+ }
+ }
+ boolean noAmbient = speedBumpIndex == N;
+ updateSpeedBumpIndex(speedBumpIndex, noAmbient);
+ }
+
private boolean isTouchInView(MotionEvent ev, View view) {
if (view == null) {
return false;
@@ -4985,7 +5340,7 @@
static class AnimationEvent {
- static AnimationFilter[] FILTERS = new AnimationFilter[] {
+ static AnimationFilter[] FILTERS = new AnimationFilter[]{
// ANIMATION_TYPE_ADD
new AnimationFilter()
@@ -5142,7 +5497,7 @@
.animateY(),
};
- static int[] LENGTHS = new int[] {
+ static int[] LENGTHS = new int[]{
// ANIMATION_TYPE_ADD
StackStateAnimator.ANIMATION_DURATION_APPEAR_DISAPPEAR,
@@ -5267,7 +5622,7 @@
*
* @param events The events of the lengths to combine.
* @return The combined length. Depending on the event types, this might be the maximum of
- * all events or the length of a specific event.
+ * all events or the length of a specific event.
*/
static long combineLength(ArrayList<AnimationEvent> events) {
long length = 0;
@@ -5282,4 +5637,18 @@
return length;
}
}
+
+ private final StateListener mStateListener = new StateListener() {
+ @Override
+ public void onStatePreChange(int oldState, int newState) {
+ if (oldState == StatusBarState.SHADE_LOCKED && newState == StatusBarState.KEYGUARD) {
+ requestAnimateEverything();
+ }
+ }
+
+ @Override
+ public void onStateChanged(int newState) {
+ setStatusBarState(newState);
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
index 7ddca17..9d40f17 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ConfigurationControllerImpl.java
@@ -52,6 +52,17 @@
}
@Override
+ public void notifyThemeChanged() {
+ ArrayList<ConfigurationListener> listeners = new ArrayList<>(mListeners);
+
+ listeners.forEach(l -> {
+ if (mListeners.contains(l)) {
+ l.onThemeChanged();
+ }
+ });
+ }
+
+ @Override
public void onConfigurationChanged(Configuration newConfig) {
// Avoid concurrent modification exception
ArrayList<ConfigurationListener> listeners = new ArrayList<>(mListeners);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index fc755fe..6150c2f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -80,6 +80,7 @@
private int mStatusBarState;
private final StateListener mStateListener = this::setStatusBarState;
+ private AnimationStateHandler mAnimationStateHandler;
private final Pools.Pool<HeadsUpEntryPhone> mEntryPool = new Pools.Pool<HeadsUpEntryPhone>() {
private Stack<HeadsUpEntryPhone> mPoolObjects = new Stack<>();
@@ -126,6 +127,10 @@
Dependency.get(StatusBarStateController.class).addListener(mStateListener);
}
+ public void setAnimationStateHandler(AnimationStateHandler handler) {
+ mAnimationStateHandler = handler;
+ }
+
public void destroy() {
Dependency.get(StatusBarStateController.class).removeListener(mStateListener);
}
@@ -350,7 +355,7 @@
@Override
public void onReorderingAllowed() {
- mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(false);
+ mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(false);
for (NotificationData.Entry entry : mEntriesToRemoveWhenReorderingAllowed) {
if (contains(entry.key)) {
// Maybe the heads-up was removed already
@@ -358,7 +363,7 @@
}
}
mEntriesToRemoveWhenReorderingAllowed.clear();
- mBar.getNotificationScrollLayout().setHeadsUpGoingAwayAnimationsAllowed(true);
+ mAnimationStateHandler.setHeadsUpGoingAwayAnimationsAllowed(true);
}
///////////////////////////////////////////////////////////////////////////////////////////////
@@ -494,4 +499,8 @@
}
}
}
+
+ public interface AnimationStateHandler {
+ void setHeadsUpGoingAwayAnimationsAllowed(boolean allowed);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index cb3a0d7..b19f57d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -8,6 +8,7 @@
import androidx.collection.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.android.internal.statusbar.StatusBarIcon;
@@ -45,7 +46,7 @@
private NotificationIconContainer mNotificationIcons;
private NotificationIconContainer mShelfIcons;
private final Rect mTintArea = new Rect();
- private NotificationStackScrollLayout mNotificationScrollLayout;
+ private ViewGroup mNotificationScrollLayout;
private Context mContext;
private boolean mFullyDark;
private boolean mHasShelfIconsWhenFullyDark;
@@ -71,8 +72,7 @@
LayoutInflater layoutInflater = LayoutInflater.from(context);
mNotificationIconArea = inflateIconArea(layoutInflater);
- mNotificationIcons = (NotificationIconContainer) mNotificationIconArea.findViewById(
- R.id.notificationIcons);
+ mNotificationIcons = mNotificationIconArea.findViewById(R.id.notificationIcons);
mNotificationScrollLayout = mStatusBar.getNotificationScrollLayout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index b4989c0..5d65b56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -33,6 +33,7 @@
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
+import android.graphics.PointF;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
@@ -67,20 +68,25 @@
import com.android.systemui.statusbar.KeyguardAffordanceView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
+import com.android.systemui.statusbar.policy.ZenModeController;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -92,7 +98,8 @@
ExpandableView.OnHeightChangedListener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener,
- OnHeadsUpChangedListener, QS.HeightListener {
+ OnHeadsUpChangedListener, QS.HeightListener, ZenModeController.Callback,
+ ConfigurationController.ConfigurationListener {
private static final boolean DEBUG = false;
@@ -315,6 +322,8 @@
.setDuration(200)
.setAnimationFinishListener(mAnimatorListenerAdapter)
.setCustomInterpolator(PANEL_ALPHA.getProperty(), Interpolators.ALPHA_IN);
+ private final NotificationEntryManager mEntryManager =
+ Dependency.get(NotificationEntryManager.class);
private final StateListener mListener = this::setBarState;
@@ -329,7 +338,7 @@
setPanelAlpha(255, false /* animate */);
}
- public void setStatusBar(StatusBar bar) {
+ private void setStatusBar(StatusBar bar) {
mStatusBar = bar;
mKeyguardBottomArea.setStatusBar(mStatusBar);
}
@@ -360,6 +369,8 @@
super.onAttachedToWindow();
FragmentHostManager.get(this).addTagListener(QS.TAG, mFragmentListener);
Dependency.get(StatusBarStateController.class).addListener(mListener);
+ Dependency.get(ZenModeController.class).addCallback(this);
+ Dependency.get(ConfigurationController.class).addCallback(this);
}
@Override
@@ -367,6 +378,8 @@
super.onDetachedFromWindow();
FragmentHostManager.get(this).removeTagListener(QS.TAG, mFragmentListener);
Dependency.get(StatusBarStateController.class).removeListener(mListener);
+ Dependency.get(ZenModeController.class).removeCallback(this);
+ Dependency.get(ConfigurationController.class).removeCallback(this);
}
@Override
@@ -413,7 +426,15 @@
}
}
+ @Override
+ public void onDensityOrFontScaleChanged() {
+ updateShowEmptyShadeView();
+ }
+
+ @Override
public void onThemeChanged() {
+ updateShowEmptyShadeView();
+
// Re-inflate the status view group.
int index = indexOfChild(mKeyguardStatusView);
removeView(mKeyguardStatusView);
@@ -589,8 +610,8 @@
continue;
}
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
- row.getStatusBarNotification());
+ boolean suppressedSummary = mGroupManager != null
+ && mGroupManager.isSummaryOfSuppressedGroup(row.getStatusBarNotification());
if (suppressedSummary) {
continue;
}
@@ -2349,7 +2370,6 @@
}
private void updateEmptyShadeView() {
-
// Hide "No notifications" in QS.
mNotificationStackScroller.updateEmptyShadeView(mShowEmptyShadeView && !mQsExpanded);
}
@@ -2720,7 +2740,7 @@
return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
}
- public void setGroupManager(NotificationGroupManager groupManager) {
+ private void setGroupManager(NotificationGroupManager groupManager) {
mGroupManager = groupManager;
}
@@ -2770,14 +2790,17 @@
};
@Override
- public void setTouchDisabled(boolean disabled) {
- super.setTouchDisabled(disabled);
+ public void setTouchAndAnimationDisabled(boolean disabled) {
+ super.setTouchAndAnimationDisabled(disabled);
if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) {
mAffordanceHelper.reset(false /* animate */);
}
+ mNotificationStackScroller.setAnimationsEnabled(!disabled);
}
- public void setDozing(boolean dozing, boolean animate) {
+ public void setDozing(boolean dozing, boolean animate,
+ PointF wakeUpTouchLocation) {
+ mNotificationStackScroller.setDark(mDozing, animate, wakeUpTouchLocation);
if (dozing == mDozing) return;
mDozing = dozing;
@@ -2922,4 +2945,84 @@
mKeyguardStatusBar.dump(fd, pw, args);
}
}
+
+ public boolean hasActiveClearableNotifications() {
+ return mNotificationStackScroller.hasActiveClearableNotifications();
+ }
+
+ @Override
+ public void onZenChanged(int zen) {
+ updateShowEmptyShadeView();
+ }
+
+ private void updateShowEmptyShadeView() {
+ boolean showEmptyShadeView =
+ mBarState != StatusBarState.KEYGUARD &&
+ mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
+ showEmptyShadeView(showEmptyShadeView);
+ }
+
+ public RemoteInputController.Delegate createRemoteInputDelegate() {
+ return mNotificationStackScroller.createDelegate();
+ }
+
+ public void updateNotificationViews() {
+ if (mNotificationStackScroller == null) return;
+ mNotificationStackScroller.updateSpeedBumpIndex();
+ mNotificationStackScroller.updateFooter();
+ updateShowEmptyShadeView();
+ }
+
+ public void onUpdateRowStates() {
+ mNotificationStackScroller.onUpdateRowStates();
+ }
+
+ public boolean hasPulsingNotifications() {
+ return mNotificationStackScroller.hasPulsingNotifications();
+ }
+
+ public boolean isFullyDark() {
+ return mNotificationStackScroller.isFullyDark();
+ }
+
+ public ActivatableNotificationView getActivatedChild() {
+ return mNotificationStackScroller.getActivatedChild();
+ }
+
+ public void setActivatedChild(ActivatableNotificationView o) {
+ mNotificationStackScroller.setActivatedChild(o);
+ }
+
+ public void setParentNotFullyVisible(boolean parent) {
+ mNotificationStackScroller.setParentNotFullyVisible(parent);
+ }
+
+ public void runAfterAnimationFinished(Runnable r) {
+ mNotificationStackScroller.runAfterAnimationFinished(r);
+ }
+
+ public void setScrollingEnabled(boolean b) {
+ mNotificationStackScroller.setScrollingEnabled(b);
+ }
+
+ public void initDependencies(StatusBar statusBar, NotificationGroupManager groupManager,
+ NotificationShelf notificationShelf,
+ HeadsUpManagerPhone headsUpManager,
+ NotificationIconAreaController notificationIconAreaController,
+ ScrimController scrimController) {
+ setStatusBar(statusBar);
+ setGroupManager(mGroupManager);
+ mNotificationStackScroller.setNotificationPanel(this);
+ mNotificationStackScroller.setIconAreaController(notificationIconAreaController);
+ mNotificationStackScroller.setStatusBar(statusBar);
+ mNotificationStackScroller.setGroupManager(groupManager);
+ mNotificationStackScroller.setHeadsUpManager(headsUpManager);
+ mNotificationStackScroller.setShelf(notificationShelf);
+ mNotificationStackScroller.setScrimController(scrimController);
+ updateShowEmptyShadeView();
+ }
+
+ public void setDrawBackgroundAsSrc(boolean asSrc) {
+ mNotificationStackScroller.setDrawBackgroundAsSrc(asSrc);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 7b9dc0e..bef34f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -230,7 +230,7 @@
if (mVelocityTracker != null) mVelocityTracker.addMovement(event);
}
- public void setTouchDisabled(boolean disabled) {
+ public void setTouchAndAnimationDisabled(boolean disabled) {
mTouchDisabled = disabled;
if (mTouchDisabled) {
cancelHeightAnimator();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 068dc76..a318e15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -148,6 +148,7 @@
import com.android.systemui.AutoReinflateContainer;
import com.android.systemui.DemoMode;
import com.android.systemui.Dependency;
+import com.android.systemui.Dumpable;
import com.android.systemui.EventLogTags;
import com.android.systemui.Interpolators;
import com.android.systemui.Prefs;
@@ -191,10 +192,8 @@
import com.android.systemui.statusbar.BackDropView;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.DragDownHelper;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -218,6 +217,7 @@
import com.android.systemui.statusbar.notification.AboveShelfObserver;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
import com.android.systemui.statusbar.policy.BatteryController;
@@ -248,11 +248,10 @@
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
-import java.util.List;
import java.util.Map;
public class StatusBar extends SystemUI implements DemoMode,
- DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
+ ActivityStarter, OnUnlockMethodChangedListener,
OnHeadsUpChangedListener, CommandQueue.Callbacks, ZenModeController.Callback,
ColorExtractor.OnColorsChangedListener, ConfigurationListener, NotificationPresenter,
StatusBarStateController.StateListener {
@@ -425,12 +424,11 @@
private int mSystemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE;
private final Rect mLastFullscreenStackBounds = new Rect();
private final Rect mLastDockedStackBounds = new Rect();
- private final Rect mTmpRect = new Rect();
// last value sent to window manager
private int mLastDispatchedSystemUiVisibility = ~View.SYSTEM_UI_FLAG_VISIBLE;
- private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
+ private final DisplayMetrics mDisplayMetrics = Dependency.get(DisplayMetrics.class);
// XXX: gesture research
private final GestureRecorder mGestureRec = DEBUG_GESTURES
@@ -571,10 +569,10 @@
private boolean mKeyguardRequested;
private boolean mIsKeyguard;
private LogMaker mStatusBarStateLog;
- private final LockscreenGestureLogger mLockscreenGestureLogger = new LockscreenGestureLogger();
+ private final LockscreenGestureLogger mLockscreenGestureLogger =
+ Dependency.get(LockscreenGestureLogger.class);
protected NotificationIconAreaController mNotificationIconAreaController;
private boolean mReinflateNotificationsOnUserSwitched;
- protected boolean mClearAllEnabled;
@Nullable private View mAmbientIndicationContainer;
private SysuiColorExtractor mColorExtractor;
private ScreenLifecycle mScreenLifecycle;
@@ -655,7 +653,6 @@
R.bool.config_vibrateOnIconAnimation);
mVibratorHelper = Dependency.get(VibratorHelper.class);
mScrimSrcModeEnabled = res.getBoolean(R.bool.config_status_bar_scrim_behind_use_src);
- mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
DateTimeView.setReceiverHandler(Dependency.get(Dependency.TIME_TICK_HANDLER));
putComponent(StatusBar.class, this);
@@ -797,12 +794,13 @@
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
mNotificationPanel = mStatusBarWindow.findViewById(R.id.notification_panel);
mStackScroller = mStatusBarWindow.findViewById(R.id.notification_stack_scroller);
+ NotificationListContainer notifListContainer = (NotificationListContainer) mStackScroller;
mZenController.addCallback(this);
mActivityLaunchAnimator = new ActivityLaunchAnimator(mStatusBarWindow,
this,
mNotificationPanel,
- mStackScroller);
- mGutsManager.setUpWithPresenter(this, mEntryManager, mStackScroller, mCheckSaveListener,
+ notifListContainer);
+ mGutsManager.setUpWithPresenter(this, mEntryManager, notifListContainer, mCheckSaveListener,
key -> {
try {
mBarService.onNotificationSettingsViewed(key);
@@ -810,9 +808,7 @@
// if we're here we're dead
}
});
- mNotificationLogger.setUpWithEntryManager(mEntryManager, mStackScroller);
- mNotificationPanel.setStatusBar(this);
- mNotificationPanel.setGroupManager(mGroupManager);
+ mNotificationLogger.setUpWithEntryManager(mEntryManager, notifListContainer);
mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
R.id.notification_container_parent));
@@ -822,7 +818,7 @@
.createNotificationIconAreaController(context, this);
inflateShelf();
mNotificationIconAreaController.setupShelf(mNotificationShelf);
- mStackScroller.setIconAreaController(mNotificationIconAreaController);
+
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
FragmentHostManager.get(mStatusBarWindow)
.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
@@ -881,8 +877,8 @@
mGroupManager.setHeadsUpManager(mHeadsUpManager);
putComponent(HeadsUpManager.class, mHeadsUpManager);
- mEntryManager.setUpWithPresenter(this, mStackScroller, this, mHeadsUpManager);
- mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, mStackScroller);
+ mEntryManager.setUpWithPresenter(this, notifListContainer, this, mHeadsUpManager);
+ mViewHierarchyManager.setUpWithPresenter(this, mEntryManager, notifListContainer);
if (MULTIUSER_DEBUG) {
mNotificationPanelDebugText = mNotificationPanel.findViewById(R.id.header_debug_info);
@@ -898,15 +894,6 @@
} catch (RemoteException ex) {
// no window manager? good luck with that
}
- mStackScroller.setLongPressListener(mEntryManager.getNotificationLongClicker());
- mStackScroller.setStatusBar(this);
- mStackScroller.setGroupManager(mGroupManager);
- mStackScroller.setHeadsUpManager(mHeadsUpManager);
- mGroupManager.setOnGroupChangeListener(mStackScroller);
- mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
-
- inflateEmptyShadeView();
- inflateFooterView();
mBackdrop = mStatusBarWindow.findViewById(R.id.backdrop);
mBackdropFront = mBackdrop.findViewById(R.id.backdrop_front);
@@ -965,12 +952,13 @@
Runnable runnable = () -> {
boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
mScrimController.setDrawBehindAsSrc(asSrc);
- mStackScroller.setDrawBackgroundAsSrc(asSrc);
+ mNotificationPanel.setDrawBackgroundAsSrc(asSrc);
};
mBackdrop.setOnVisibilityChangedRunnable(runnable);
runnable.run();
}
- mStackScroller.setScrimController(mScrimController);
+ mNotificationPanel.initDependencies(this, mGroupManager, mNotificationShelf,
+ mHeadsUpManager, mNotificationIconAreaController, mScrimController);
mDozeScrimController = new DozeScrimController(mScrimController, context,
DozeParameters.getInstance(context));
@@ -1112,10 +1100,10 @@
(NotificationShelf) LayoutInflater.from(mContext).inflate(
R.layout.status_bar_notification_shelf, mStackScroller, false);
mNotificationShelf.setOnActivatedListener(this);
- mStackScroller.setShelf(mNotificationShelf);
mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
}
+ @Override
public void onDensityOrFontScaleChanged() {
MessagingMessage.dropCache();
MessagingGroup.dropCache();
@@ -1140,17 +1128,10 @@
}
mNotificationIconAreaController.onDensityOrFontScaleChanged(mContext);
mHeadsUpManager.onDensityOrFontScaleChanged();
-
- inflateFooterView();
- inflateEmptyShadeView();
- reevaluateStyles();
}
- private void onThemeChanged() {
- reevaluateStyles();
-
- // Clock and bottom icons
- mNotificationPanel.onThemeChanged();
+ @Override
+ public void onThemeChanged() {
// The status bar on the keyguard is a special layout.
if (mKeyguardStatusBar != null) mKeyguardStatusBar.onThemeChanged();
// Recreate Indication controller because internal references changed
@@ -1171,11 +1152,6 @@
}
}
- private void reevaluateStyles() {
- updateFooter();
- updateEmptyShadeView();
- }
-
@Override
public void onOverlayChanged() {
if (mBrightnessMirrorController != null) {
@@ -1193,37 +1169,6 @@
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.onUiModeChanged();
}
- if (mStackScroller != null) {
- mStackScroller.onUiModeChanged();
- }
- }
-
- private void inflateEmptyShadeView() {
- if (mStackScroller == null) {
- return;
- }
- mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_no_notifications, mStackScroller, false);
- mEmptyShadeView.setText(R.string.empty_shade_text);
- mStackScroller.setEmptyShadeView(mEmptyShadeView);
- }
-
- @VisibleForTesting
- protected void inflateFooterView() {
- if (mStackScroller == null) {
- return;
- }
-
- mFooterView = (FooterView) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_notification_footer, mStackScroller, false);
- mFooterView.setDismissButtonClickListener(v -> {
- mMetricsLogger.action(MetricsEvent.ACTION_DISMISS_ALL_NOTES);
- clearAllNotifications();
- });
- mFooterView.setManageButtonClickListener(v -> {
- manageNotifications();
- });
- mStackScroller.setFooterView(mFooterView);
}
protected void createUserSwitcher() {
@@ -1237,105 +1182,6 @@
R.layout.super_status_bar, null);
}
- public void manageNotifications() {
- Intent intent = new Intent(Settings.ACTION_ALL_APPS_NOTIFICATION_SETTINGS);
- startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
- }
-
- public void clearAllNotifications() {
- // animate-swipe all dismissable notifications, then animate the shade closed
- int numChildren = mStackScroller.getChildCount();
-
- final ArrayList<View> viewsToHide = new ArrayList<>(numChildren);
- final ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(numChildren);
- for (int i = 0; i < numChildren; i++) {
- final View child = mStackScroller.getChildAt(i);
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- boolean parentVisible = false;
- boolean hasClipBounds = child.getClipBounds(mTmpRect);
- if (mStackScroller.canChildBeDismissed(child)) {
- viewsToRemove.add(row);
- if (child.getVisibility() == View.VISIBLE
- && (!hasClipBounds || mTmpRect.height() > 0)) {
- viewsToHide.add(child);
- parentVisible = true;
- }
- } else if (child.getVisibility() == View.VISIBLE
- && (!hasClipBounds || mTmpRect.height() > 0)) {
- parentVisible = true;
- }
- List<ExpandableNotificationRow> children = row.getNotificationChildren();
- if (children != null) {
- for (ExpandableNotificationRow childRow : children) {
- viewsToRemove.add(childRow);
- if (parentVisible && row.areChildrenExpanded()
- && mStackScroller.canChildBeDismissed(childRow)) {
- hasClipBounds = childRow.getClipBounds(mTmpRect);
- if (childRow.getVisibility() == View.VISIBLE
- && (!hasClipBounds || mTmpRect.height() > 0)) {
- viewsToHide.add(childRow);
- }
- }
- }
- }
- }
- }
- if (viewsToRemove.isEmpty()) {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- return;
- }
-
- addPostCollapseAction(() -> {
- mStackScroller.setDismissAllInProgress(false);
- for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
- if (mStackScroller.canChildBeDismissed(rowToRemove)) {
- mEntryManager.removeNotification(rowToRemove.getEntry().key, null);
- } else {
- rowToRemove.resetTranslation();
- }
- }
- try {
- mBarService.onClearAllNotifications(mLockscreenUserManager.getCurrentUserId());
- } catch (Exception ex) {
- }
- });
-
- performDismissAllAnimations(viewsToHide);
-
- }
-
- private void performDismissAllAnimations(ArrayList<View> hideAnimatedList) {
- Runnable animationFinishAction = () -> {
- animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
- };
-
- if (hideAnimatedList.isEmpty()) {
- animationFinishAction.run();
- return;
- }
-
- // let's disable our normal animations
- mStackScroller.setDismissAllInProgress(true);
-
- // Decrease the delay for every row we animate to give the sense of
- // accelerating the swipes
- int rowDelayDecrement = 10;
- int currentDelay = 140;
- int totalDelay = 180;
- int numItems = hideAnimatedList.size();
- for (int i = numItems - 1; i >= 0; i--) {
- View view = hideAnimatedList.get(i);
- Runnable endRunnable = null;
- if (i == 0) {
- endRunnable = animationFinishAction;
- }
- mStackScroller.dismissViewAnimated(view, endRunnable, totalDelay, 260);
- currentDelay = Math.max(50, currentDelay - rowDelayDecrement);
- totalDelay += currentDelay;
- }
- }
-
protected void startKeyguard() {
Trace.beginSection("StatusBar#startKeyguard");
KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
@@ -1408,7 +1254,7 @@
@Override
public void onPerformRemoveNotification(StatusBarNotification n) {
- if (mStackScroller.hasPulsingNotifications() &&
+ if (mNotificationPanel.hasPulsingNotifications() &&
!mHeadsUpManager.hasNotifications()) {
// We were showing a pulse for a notification, but no notifications are pulsing anymore.
// Finish the pulse.
@@ -1420,7 +1266,7 @@
public void updateNotificationViews() {
// The function updateRowStates depends on both of these being non-null, so check them here.
// We may be called before they are set from DeviceProvisionedController's callback.
- if (mStackScroller == null || mScrimController == null) return;
+ if (mScrimController == null) return;
// Do not modify the notifications during collapse.
if (isCollapsing()) {
@@ -1430,9 +1276,7 @@
mViewHierarchyManager.updateNotificationViews();
- updateSpeedBumpIndex();
- updateFooter();
- updateEmptyShadeView();
+ mNotificationPanel.updateNotificationViews();
updateQsExpansionEnabled();
@@ -1499,61 +1343,6 @@
mQSPanel.clickTile(tile);
}
- @VisibleForTesting
- protected void updateFooter() {
- boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications();
- boolean showFooterView = (showDismissView ||
- mEntryManager.getNotificationData().getActiveNotifications().size() != 0)
- && mState != StatusBarState.KEYGUARD
- && !mRemoteInputManager.getController().isRemoteInputActive();
-
- mStackScroller.updateFooterView(showFooterView, showDismissView);
- }
-
- /**
- * Return whether there are any clearable notifications
- */
- private boolean hasActiveClearableNotifications() {
- int childCount = mStackScroller.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = mStackScroller.getChildAt(i);
- if (!(child instanceof ExpandableNotificationRow)) {
- continue;
- }
- if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
- return true;
- }
- }
- return false;
- }
-
- private void updateEmptyShadeView() {
- boolean showEmptyShadeView =
- mState != StatusBarState.KEYGUARD &&
- mEntryManager.getNotificationData().getActiveNotifications().size() == 0;
- mNotificationPanel.showEmptyShadeView(showEmptyShadeView);
- }
-
- private void updateSpeedBumpIndex() {
- int speedBumpIndex = 0;
- int currentIndex = 0;
- final int N = mStackScroller.getChildCount();
- for (int i = 0; i < N; i++) {
- View view = mStackScroller.getChildAt(i);
- if (view.getVisibility() == View.GONE || !(view instanceof ExpandableNotificationRow)) {
- continue;
- }
- ExpandableNotificationRow row = (ExpandableNotificationRow) view;
- currentIndex++;
- if (!mEntryManager.getNotificationData().isAmbient(
- row.getStatusBarNotification().getKey())) {
- speedBumpIndex = currentIndex;
- }
- }
- boolean noAmbient = speedBumpIndex == N;
- mStackScroller.updateSpeedBumpIndex(speedBumpIndex, noAmbient);
- }
-
public static boolean isTopLevelChild(Entry entry) {
return entry.row.getParent() instanceof NotificationStackScrollLayout;
}
@@ -1570,7 +1359,7 @@
if (SPEW) {
final boolean clearable = hasActiveNotifications() &&
- hasActiveClearableNotifications();
+ mNotificationPanel.hasActiveClearableNotifications();
Log.d(TAG, "setAreThereNotifications: N=" +
mEntryManager.getNotificationData().getActiveNotifications().size() + " any=" +
hasActiveNotifications() + " clearable=" + clearable);
@@ -1884,7 +1673,7 @@
/**
* Reapplies the disable flags as last requested by StatusBarManager.
*
- * This needs to be called if state used by {@link #adjustDisableFlags} changes.
+ * This needs to be called if state used by adjustDisableFlags changes.
*/
public void recomputeDisableFlags(boolean animate) {
mCommandQueue.recomputeDisableFlags(animate);
@@ -1894,7 +1683,7 @@
return new StatusBar.H();
}
- private void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
+ public void startActivity(Intent intent, boolean onlyProvisioned, boolean dismissShade,
int flags) {
startActivityDismissingKeyguard(intent, onlyProvisioned, dismissShade, flags);
}
@@ -1932,7 +1721,7 @@
@Override
public boolean isDozing() {
- return mDozing && mStackScroller.isFullyDark();
+ return mDozing && mNotificationPanel.isFullyDark();
}
@Override
@@ -2017,7 +1806,7 @@
// we need to keep the panel open artificially, let's wait until the animation
// is finished.
mHeadsUpManager.setHeadsUpGoingAway(true);
- mStackScroller.runAfterAnimationFinished(() -> {
+ mNotificationPanel.runAfterAnimationFinished(() -> {
if (!mHeadsUpManager.hasPinnedHeadsUp()) {
mStatusBarWindowController.setHeadsUpShowing(false);
mHeadsUpManager.setHeadsUpGoingAway(false);
@@ -2073,7 +1862,7 @@
}
}
- public NotificationStackScrollLayout getNotificationScrollLayout() {
+ public ViewGroup getNotificationScrollLayout() {
return mStackScroller;
}
@@ -2796,9 +2585,9 @@
mNotificationPanel.dump(fd, pw, args);
}
pw.println(" mStackScroller: ");
- if (mStackScroller != null) {
+ if (mStackScroller instanceof Dumpable) {
pw.print (" ");
- mStackScroller.dump(fd, pw, args);
+ ((Dumpable) mStackScroller).dump(fd, pw, args);
}
pw.println(" Theme:");
String nightMode = mUiModeManager == null ? "null" : mUiModeManager.getNightMode() + "";
@@ -2890,21 +2679,7 @@
makeStatusBarView();
mStatusBarWindowController = Dependency.get(StatusBarWindowController.class);
mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this,
- new RemoteInputController.Delegate() {
- public void setRemoteInputActive(NotificationData.Entry entry,
- boolean remoteInputActive) {
- mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);
- entry.row.notifyHeightChanged(true /* needsAnimation */);
- updateFooter();
- }
- public void lockScrollTo(NotificationData.Entry entry) {
- mStackScroller.lockScrollTo(entry.row);
- }
- public void requestDisallowLongPressAndDismiss() {
- mStackScroller.requestDisallowLongPress();
- mStackScroller.requestDisallowDismiss();
- }
- });
+ mNotificationPanel.createRemoteInputDelegate());
mRemoteInputManager.getController().addCallback(mStatusBarWindowController);
mStatusBarWindowController.add(mStatusBarWindow, getStatusBarHeight());
}
@@ -3619,7 +3394,7 @@
updateScrimController();
updateMediaMetaData(false, true);
mNotificationPanel.setAlpha(1);
- mStackScroller.setParentNotFullyVisible(true);
+ mNotificationPanel.setParentNotFullyVisible(true);
mNotificationPanel.animate()
.alpha(0)
.setStartDelay(FADE_KEYGUARD_START_DELAY)
@@ -3814,7 +3589,6 @@
* Switches theme from light to dark and vice-versa.
*/
protected void updateTheme() {
- final boolean inflated = mStackScroller != null && mStatusBarWindowController != null;
// Lock wallpaper defines the color of the majority of the views, hence we'll use it
// to set our default theme.
@@ -3823,24 +3597,7 @@
final int themeResId = lockDarkText ? R.style.Theme_SystemUI_Light : R.style.Theme_SystemUI;
if (mContext.getThemeResId() != themeResId) {
mContext.setTheme(themeResId);
- if (inflated) {
- onThemeChanged();
- }
- }
-
- if (inflated) {
- int which;
- if (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED) {
- which = WallpaperManager.FLAG_LOCK;
- } else {
- which = WallpaperManager.FLAG_SYSTEM;
- }
- final boolean useDarkText = mColorExtractor.getColors(which,
- true /* ignoreVisibility */).supportsDarkText();
- mStackScroller.updateDecorViews(useDarkText);
-
- // Make sure we have the correct navbar/statusbar colors.
- mStatusBarWindowController.setKeyguardDark(useDarkText);
+ Dependency.get(ConfigurationController.class).notifyThemeChanged();
}
}
@@ -3853,10 +3610,9 @@
boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup())
|| (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && sleepingFromKeyguard);
- mStackScroller.setDark(mDozing, animate, mWakeUpTouchLocation);
mDozeScrimController.setDozing(mDozing);
mKeyguardIndicationController.setDozing(mDozing);
- mNotificationPanel.setDozing(mDozing, animate);
+ mNotificationPanel.setDozing(mDozing, animate, mWakeUpTouchLocation);
mNotificationLogger.setDozing(mDozing);
updateQsExpansionEnabled();
Trace.endSection();
@@ -3953,7 +3709,7 @@
@Override
public void onActivated(ActivatableNotificationView view) {
onActivated((View) view);
- mStackScroller.setActivatedChild(view);
+ mNotificationPanel.setActivatedChild(view);
}
public void onActivated(View view) {
@@ -3961,7 +3717,7 @@
MetricsEvent.ACTION_LS_NOTE,
0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */);
mKeyguardIndicationController.showTransientIndication(R.string.notification_tap_again);
- ActivatableNotificationView previousView = mStackScroller.getActivatedChild();
+ ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild();
if (previousView != null) {
previousView.makeInactive(true /* animate */);
}
@@ -4031,8 +3787,8 @@
@Override
public void onActivationReset(ActivatableNotificationView view) {
- if (view == mStackScroller.getActivatedChild()) {
- mStackScroller.setActivatedChild(null);
+ if (view == mNotificationPanel.getActivatedChild()) {
+ mNotificationPanel.setActivatedChild(null);
onActivationReset((View)view);
}
}
@@ -4098,8 +3854,9 @@
return mMaxKeyguardNotifications;
}
- public int getMaxNotificationsWhileLocked() {
- return getMaxNotificationsWhileLocked(false /* recompute */);
+ @Override
+ public void onUpdateRowStates() {
+ mNotificationPanel.onUpdateRowStates();
}
// TODO: Figure out way to remove these.
@@ -4119,60 +3876,6 @@
return mNotificationPanel.getKeyguardBottomAreaView();
}
- // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
-
-
- /* Only ever called as a consequence of a lockscreen expansion gesture. */
- @Override
- public boolean onDraggedDown(View startingChild, int dragLengthY) {
- if (mState == StatusBarState.KEYGUARD
- && hasActiveNotifications() && (!isDozing() || isPulsing())) {
- mLockscreenGestureLogger.write(
- MetricsEvent.ACTION_LS_SHADE,
- (int) (dragLengthY / mDisplayMetrics.density),
- 0 /* velocityDp - N/A */);
-
- // We have notifications, go to locked shade.
- goToLockedShade(startingChild);
- if (startingChild instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) startingChild;
- row.onExpandedByGesture(true /* drag down is always an open */);
- }
- return true;
- } else {
- // abort gesture.
- return false;
- }
- }
-
- @Override
- public void onDragDownReset() {
- mStackScroller.setDimmed(true /* dimmed */, true /* animated */);
- mStackScroller.resetScrollPosition();
- mStackScroller.resetCheckSnoozeLeavebehind();
- }
-
- @Override
- public void onCrossedThreshold(boolean above) {
- mStackScroller.setDimmed(!above /* dimmed */, true /* animate */);
- }
-
- @Override
- public void onTouchSlopExceeded() {
- mStackScroller.cancelLongPress();
- mStackScroller.checkSnoozeLeavebehind();
- }
-
- @Override
- public void setEmptyDragAmount(float amount) {
- mNotificationPanel.setEmptyDragAmount(amount);
- }
-
- @Override
- public boolean isFalsingCheckNeeded() {
- return mState == StatusBarState.KEYGUARD;
- }
-
/**
* If secure with redaction: Show bouncer, go to unlocked shade.
*
@@ -4397,7 +4100,6 @@
*/
public void goToKeyguard() {
if (mState == StatusBarState.SHADE_LOCKED) {
- mStackScroller.onGoToKeyguard();
mStatusBarStateController.setState(StatusBarState.KEYGUARD);
}
}
@@ -4431,14 +4133,13 @@
mDeviceInteractive = false;
mWakeUpComingFromTouch = false;
mWakeUpTouchLocation = null;
- mStackScroller.setAnimationsEnabled(false);
mVisualStabilityManager.setScreenOn(false);
updateVisibleToUser();
// We need to disable touch events because these might
// collapse the panel after we expanded it, and thus we would end up with a blank
// Keyguard.
- mNotificationPanel.setTouchDisabled(true);
+ mNotificationPanel.setTouchAndAnimationDisabled(true);
mStatusBarWindow.cancelCurrentTouch();
if (mLaunchCameraOnFinishedGoingToSleep) {
mLaunchCameraOnFinishedGoingToSleep = false;
@@ -4459,9 +4160,8 @@
@Override
public void onStartedWakingUp() {
mDeviceInteractive = true;
- mStackScroller.setAnimationsEnabled(true);
mVisualStabilityManager.setScreenOn(true);
- mNotificationPanel.setTouchDisabled(false);
+ mNotificationPanel.setTouchAndAnimationDisabled(false);
mDozeServiceHost.stopDozing();
updateVisibleToUser();
updateIsKeyguard();
@@ -4931,7 +4631,7 @@
protected IStatusBarService mBarService;
// all notifications
- protected NotificationStackScrollLayout mStackScroller;
+ protected ViewGroup mStackScroller;
protected NotificationGroupManager mGroupManager;
@@ -4972,7 +4672,6 @@
protected RecentsComponent mRecents;
protected NotificationShelf mNotificationShelf;
- protected FooterView mFooterView;
protected EmptyShadeView mEmptyShadeView;
protected AssistManager mAssistManager;
@@ -5168,7 +4867,7 @@
if (Looper.getMainLooper().isCurrentThread()) {
collapsePanel();
} else {
- mStackScroller.post(this::collapsePanel);
+ Dependency.get(Dependency.MAIN_HANDLER).post(this::collapsePanel);
}
}
@@ -5447,33 +5146,6 @@
}
}
- /**
- * Updates expanded, dimmed and locked states of notification rows.
- */
- @Override
- public void onUpdateRowStates() {
- // The following views will be moved to the end of mStackScroller. This counter represents
- // the offset from the last child. Initialized to 1 for the very last position. It is post-
- // incremented in the following "changeViewPosition" calls so that its value is correct for
- // subsequent calls.
- int offsetFromEnd = 1;
- if (mFooterView != null) {
- mStackScroller.changeViewPosition(mFooterView,
- mStackScroller.getChildCount() - offsetFromEnd++);
- }
-
- mStackScroller.changeViewPosition(mEmptyShadeView,
- mStackScroller.getChildCount() - offsetFromEnd++);
-
- // No post-increment for this call because it is the last one. Make sure to add one if
- // another "changeViewPosition" call is ever added.
- mStackScroller.changeViewPosition(mNotificationShelf,
- mStackScroller.getChildCount() - offsetFromEnd);
-
- // Scrim opacity varies based on notification count
- mScrimController.setNotificationCount(mStackScroller.getNotGoneChildCount());
- }
-
protected void notifyHeadsUpGoingToSleep() {
maybeEscalateHeadsUp();
}
@@ -5520,11 +5192,6 @@
}
@Override
- public void onZenChanged(int zen) {
- updateEmptyShadeView();
- }
-
- @Override
public void showAssistDisclosure() {
if (mAssistManager != null) {
mAssistManager.showDisclosure();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index c30e190..46264f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -22,6 +22,7 @@
import android.app.ActivityManager;
import android.app.IActivityManager;
+import android.app.WallpaperManager;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
@@ -40,11 +41,14 @@
import com.android.keyguard.R;
import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.keyguard.KeyguardViewMediator;
-import com.android.systemui.statusbar.RemoteInputController;
+import com.android.systemui.statusbar.RemoteInputController.Callback;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -53,7 +57,7 @@
/**
* Encapsulates all logic for the status bar window state management.
*/
-public class StatusBarWindowController implements RemoteInputController.Callback, Dumpable {
+public class StatusBarWindowController implements Callback, Dumpable, ConfigurationListener {
private static final String TAG = "StatusBarWindowController";
@@ -73,6 +77,7 @@
private OtherwisedCollapsedListener mListener;
private final StateListener mStateListener = this::setStatusBarState;
+ private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
public StatusBarWindowController(Context context) {
this(context, context.getSystemService(WindowManager.class), ActivityManager.getService(),
@@ -89,6 +94,7 @@
mDozeParameters = dozeParameters;
mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
Dependency.get(StatusBarStateController.class).addListener(mStateListener);
+ Dependency.get(ConfigurationController.class).addCallback(this);
}
private boolean shouldEnableKeyguardScreenRotation() {
@@ -135,7 +141,7 @@
mScreenBrightnessDoze = value / 255f;
}
- public void setKeyguardDark(boolean dark) {
+ private void setKeyguardDark(boolean dark) {
int vis = mStatusBarView.getSystemUiVisibility();
if (dark) {
vis = vis | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
@@ -461,6 +467,23 @@
return !mCurrentState.backdropShowing;
}
+ @Override
+ public void onThemeChanged() {
+ StatusBarStateController state = Dependency.get(StatusBarStateController.class);
+ int which;
+ if (state.getState() == StatusBarState.KEYGUARD
+ || state.getState() == StatusBarState.SHADE_LOCKED) {
+ which = WallpaperManager.FLAG_LOCK;
+ } else {
+ which = WallpaperManager.FLAG_SYSTEM;
+ }
+ final boolean useDarkText = mColorExtractor.getColors(which,
+ true /* ignoreVisibility */).supportsDarkText();
+
+ // Make sure we have the correct navbar/statusbar colors.
+ setKeyguardDark(useDarkText);
+ }
+
private static class State {
boolean keyguardShowing;
boolean keyguardOccluded;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 765c788..98f1a36 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -215,7 +215,8 @@
public void setService(StatusBar service) {
mService = service;
- setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout, mService));
+ setDragDownHelper(new DragDownHelper(getContext(), this, mStackScrollLayout,
+ mStackScrollLayout));
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
index 8c631d9..0e5c8c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ConfigurationController.java
@@ -24,11 +24,14 @@
*/
public interface ConfigurationController extends CallbackController<ConfigurationListener> {
+ public void notifyThemeChanged();
+
interface ConfigurationListener {
default void onConfigChanged(Configuration newConfig) {}
default void onDensityOrFontScaleChanged() {}
default void onOverlayChanged() {}
default void onUiModeChanged() {}
+ default void onThemeChanged() {}
default void onLocaleListChanged() {}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 1560f6f..c19188c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -3,10 +3,7 @@
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,9 +13,13 @@
package com.android.systemui.statusbar.notification.stack;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
@@ -26,6 +27,10 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.Looper;
+import android.os.PowerManager;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -33,22 +38,34 @@
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
+import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.NotificationPresenter;
+import com.android.systemui.statusbar.notification.NotificationData;
+import com.android.systemui.statusbar.notification.NotificationData.Entry;
+import com.android.systemui.statusbar.notification.NotificationEntryManager;
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager;
+import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager;
+
+import java.util.ArrayList;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@@ -70,6 +87,12 @@
@Mock private NotificationGroupManager mGroupManager;
@Mock private ExpandHelper mExpandHelper;
@Mock private EmptyShadeView mEmptyShadeView;
+ @Mock private NotificationData mNotificationData;
+ @Mock private NotificationRemoteInputManager mRemoteInputManager;
+ @Mock private RemoteInputController mRemoteInputController;
+ @Mock private SystemServicesProxy mSystemServicesProxy;
+ private PowerManager mPowerManager;
+ private TestableNotificationEntryManager mEntryManager;
@Before
@UiThreadTest
@@ -79,9 +102,21 @@
NotificationBlockingHelperManager.class,
mBlockingHelperManager);
mDependency.injectTestDependency(StatusBarStateController.class, mBarState);
+ mDependency.injectTestDependency(NotificationRemoteInputManager.class,
+ mRemoteInputManager);
+ when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
+
+ IPowerManager powerManagerService = mock(IPowerManager.class);
+ mPowerManager = new PowerManager(mContext, powerManagerService,
+ Handler.createAsync(Looper.myLooper()));
+
+ mEntryManager = new TestableNotificationEntryManager(mSystemServicesProxy, mPowerManager,
+ mContext);
+ mEntryManager.setUpForTest(mock(NotificationPresenter.class), null, null, null, mNotificationData);
+ mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager);
NotificationShelf notificationShelf = spy(new NotificationShelf(getContext(), null));
- mStackScroller = new NotificationStackScrollLayout(getContext());
+ mStackScroller = spy(new NotificationStackScrollLayout(getContext()));
mStackScroller.setShelf(notificationShelf);
mStackScroller.setStatusBar(mBar);
mStackScroller.setScrimController(mock(ScrimController.class));
@@ -189,4 +224,98 @@
verify(view).setVisible(eq(true), anyBoolean());
verify(view).setSecondaryVisible(eq(true), anyBoolean());
}
+
+ @Test
+ public void testInflateFooterView() {
+ mStackScroller.inflateFooterView();
+ ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class);
+ verify(mStackScroller).setFooterView(captor.capture());
+
+ assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners());
+ assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners());
+ }
+
+ @Test
+ public void testUpdateFooter_noNotifications() {
+ setBarStateForTest(StatusBarState.SHADE);
+ assertEquals(0, mNotificationData.getActiveNotifications().size());
+
+ mStackScroller.updateFooter();
+ verify(mStackScroller).updateFooterView(false, false);
+ }
+
+ @Test
+ public void testUpdateFooter_remoteInput() {
+ setBarStateForTest(StatusBarState.SHADE);
+ ArrayList<Entry> entries = new ArrayList<>();
+ entries.add(mock(Entry.class));
+ when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ when(row.canViewBeDismissed()).thenReturn(true);
+ when(mStackScroller.getChildCount()).thenReturn(1);
+ when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
+ when(mRemoteInputController.isRemoteInputActive()).thenReturn(true);
+
+ mStackScroller.updateFooter();
+ verify(mStackScroller).updateFooterView(false, true);
+ }
+
+ @Test
+ public void testUpdateFooter_oneClearableNotification() {
+ setBarStateForTest(StatusBarState.SHADE);
+ ArrayList<Entry> entries = new ArrayList<>();
+ entries.add(mock(Entry.class));
+ when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ when(row.canViewBeDismissed()).thenReturn(true);
+ when(mStackScroller.getChildCount()).thenReturn(1);
+ when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
+
+ mStackScroller.updateFooter();
+ verify(mStackScroller).updateFooterView(true, true);
+ }
+
+ @Test
+ public void testUpdateFooter_oneNonClearableNotification() {
+ setBarStateForTest(StatusBarState.SHADE);
+ ArrayList<Entry> entries = new ArrayList<>();
+ entries.add(mock(Entry.class));
+ when(mNotificationData.getActiveNotifications()).thenReturn(entries);
+
+ mStackScroller.updateFooter();
+ verify(mStackScroller).updateFooterView(true, false);
+ }
+
+ @Test
+ public void testUpdateFooter_atEnd() {
+ // add footer
+ mStackScroller.inflateFooterView();
+
+ // add notification
+ ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+ when(row.isClearable()).thenReturn(true);
+ mStackScroller.addContainerView(row);
+
+ mStackScroller.onUpdateRowStates();
+
+ // move footer to end
+ verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
+ }
+
+ @Test
+ public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() {
+ clearInvocations(mStackScroller);
+ mStackScroller.onDensityOrFontScaleChanged();
+ verify(mStackScroller).setFooterView(any());
+ verify(mStackScroller).setEmptyShadeView(any());
+ }
+
+ private void setBarStateForTest(int state) {
+ ArgumentCaptor<StatusBarStateController.StateListener> captor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+ verify(mBarState).addListener(captor.capture());
+ captor.getValue().onStateChanged(state);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 7686233..cbba251 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -77,8 +77,6 @@
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.AppOpsListener;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.row.FooterView;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.notification.NotificationData;
import com.android.systemui.statusbar.notification.NotificationData.Entry;
@@ -105,7 +103,6 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -593,85 +590,7 @@
}
@Test
- public void testInflateFooterView() {
- mStatusBar.inflateFooterView();
- ArgumentCaptor<FooterView> captor = ArgumentCaptor.forClass(FooterView.class);
- verify(mStackScroller).setFooterView(captor.capture());
- assertNotNull(captor.getValue().findViewById(R.id.manage_text).hasOnClickListeners());
- assertNotNull(captor.getValue().findViewById(R.id.dismiss_text).hasOnClickListeners());
- }
-
- @Test
- public void testUpdateFooter_noNotifications() {
- mStatusBar.setBarStateForTest(StatusBarState.SHADE);
- assertEquals(0, mEntryManager.getNotificationData().getActiveNotifications().size());
-
- mStatusBar.updateFooter();
- verify(mStackScroller).updateFooterView(false, false);
- }
-
- @Test
- public void testUpdateFooter_remoteInput() {
- mStatusBar.setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
- when(mNotificationData.getActiveNotifications()).thenReturn(entries);
-
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
- when(row.canViewBeDismissed()).thenReturn(true);
- when(mStackScroller.getChildCount()).thenReturn(1);
- when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
- when(mRemoteInputController.isRemoteInputActive()).thenReturn(true);
-
- mStatusBar.updateFooter();
- verify(mStackScroller).updateFooterView(false, true);
- }
-
- @Test
- public void testUpdateFooter_oneClearableNotification() {
- mStatusBar.setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
- when(mNotificationData.getActiveNotifications()).thenReturn(entries);
-
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
- when(row.canViewBeDismissed()).thenReturn(true);
- when(mStackScroller.getChildCount()).thenReturn(1);
- when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
-
- mStatusBar.updateFooter();
- verify(mStackScroller).updateFooterView(true, true);
- }
-
- @Test
- public void testUpdateFooter_oneNonClearableNotification() {
- mStatusBar.setBarStateForTest(StatusBarState.SHADE);
- ArrayList<Entry> entries = new ArrayList<>();
- entries.add(mock(Entry.class));
- when(mNotificationData.getActiveNotifications()).thenReturn(entries);
-
- mStatusBar.updateFooter();
- verify(mStackScroller).updateFooterView(true, false);
- }
-
- @Test
- public void testUpdateFooter_atEnd() {
- // add footer
- mStatusBar.inflateFooterView();
-
- // add notification
- ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
- when(row.isClearable()).thenReturn(true);
- mStackScroller.addContainerView(row);
-
- mStatusBar.onUpdateRowStates();
-
- // move footer to end
- verify(mStackScroller).changeViewPosition(any(FooterView.class), eq(-1 /* end */));
- }
-
- @Test
public void testSetState_changesIsFullScreenUserSwitcherState() {
mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
assertFalse(mStatusBar.isFullScreenUserSwitcherState());
@@ -697,13 +616,6 @@
verify(mStatusBarStateController).setState(eq(StatusBarState.FULLSCREEN_USER_SWITCHER));
}
- @Test
- public void testOnDensityOrFontScaleChanged_reInflatesFooterViews() {
- mStatusBar.onDensityOrFontScaleChanged();
- verify(mStackScroller).setFooterView(any());
- verify(mStackScroller).setEmptyShadeView(any());
- }
-
static class TestableStatusBar extends StatusBar {
public TestableStatusBar(StatusBarKeyguardViewManager man,
UnlockMethodCache unlock, KeyguardIndicationController key,
@@ -743,7 +655,6 @@
mBiometricUnlockController = biometricUnlockController;
mActivityLaunchAnimator = launchAnimator;
mKeyguardViewMediator = keyguardViewMediator;
- mClearAllEnabled = true;
mRemoteInputManager = notificationRemoteInputManager;
mGroupManager = notificationGroupManager;
mFalsingManager = falsingManager;
@@ -777,7 +688,7 @@
}
- private class TestableNotificationEntryManager extends NotificationEntryManager {
+ public static class TestableNotificationEntryManager extends NotificationEntryManager {
public TestableNotificationEntryManager(SystemServicesProxy systemServicesProxy,
PowerManager powerManager, Context context) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
index 9ef30c3..5ddf7a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeConfigurationController.java
@@ -23,4 +23,8 @@
public FakeConfigurationController(LeakCheckedTest.SysuiLeakCheck sysuiLeakCheck) {
super(sysuiLeakCheck, "config");
}
+
+ @Override
+ public void notifyThemeChanged() {
+ }
}