Merge changes Ifcf66d9e,I9709e3f6

* changes:
  Move DynamicPrivacyController from NSSL
  Move NotifEntryMan and NotifPipeline from NSSL
This commit is contained in:
TreeHugger Robot
2020-09-11 02:17:23 +00:00
committed by Android (Google) Code Review
6 changed files with 239 additions and 256 deletions

View File

@@ -516,6 +516,7 @@ public class NotificationRemoteInputManager implements Dumpable {
return mLifetimeExtenders;
}
@Nullable
public RemoteInputController getController() {
return mRemoteInputController;
}

View File

@@ -65,13 +65,11 @@ class ShadeViewManager constructor(
return root
}
private fun buildNotifNode(entry: ListEntry, parent: NodeSpec): NodeSpec {
return when (entry) {
is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry))
is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary)))
.apply { entry.children.forEach { children.add(buildNotifNode(it, this)) } }
else -> throw RuntimeException("Unexpected entry: $entry")
}
private fun buildNotifNode(entry: ListEntry, parent: NodeSpec): NodeSpec = when (entry) {
is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry))
is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary)))
.apply { entry.children.forEach { children.add(buildNotifNode(it, this)) } }
else -> throw RuntimeException("Unexpected entry: $entry")
}
}

View File

@@ -16,14 +16,10 @@
package com.android.systemui.statusbar.notification.stack;
import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
import static com.android.systemui.statusbar.notification.stack.NotificationSectionsManagerKt.BUCKET_SILENT;
import static com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.ANCHOR_SCROLLING;
import static com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_SWIPE;
import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY;
import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -49,10 +45,8 @@ import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -83,8 +77,6 @@ import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.UiEvent;
import com.android.internal.logging.UiEventLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.keyguard.KeyguardSliceView;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
@@ -96,27 +88,20 @@ 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.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.ShadeViewRefactor.RefactorComponent;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
@@ -136,7 +121,6 @@ import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpUtil;
import com.android.systemui.statusbar.policy.ScrollAdapter;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.util.Assert;
import java.io.FileDescriptor;
@@ -173,7 +157,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
*/
private static final int DISTANCE_BETWEEN_ADJACENT_SECTIONS_PX = 1;
private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
private final DynamicPrivacyController mDynamicPrivacyController;
private final SysuiStatusBarStateController mStatusbarStateController;
private ExpandHelper mExpandHelper;
@@ -225,7 +208,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private int mBottomMargin;
private int mBottomInset = 0;
private float mQsExpansionFraction;
private int mCurrentUserId;
/**
* The algorithm which calculates the properties for our children
@@ -468,12 +450,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
private int mHeadsUpInset;
private HeadsUpAppearanceController mHeadsUpAppearanceController;
private final Rect mTmpRect = new Rect();
private final FeatureFlags mFeatureFlags;
private final NotifPipeline mNotifPipeline;
private final NotifCollection mNotifCollection;
private final NotificationEntryManager mEntryManager;
private final IStatusBarService mBarService = IStatusBarService.Stub.asInterface(
ServiceManager.getService(Context.STATUS_BAR_SERVICE));
private DismissAllAnimationListener mDismissAllAnimationListener;
@VisibleForTesting
protected final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class);
protected final UiEventLogger mUiEventLogger;
@@ -553,18 +530,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
@Named(VIEW_CONTEXT) Context context,
AttributeSet attrs,
NotificationRoundnessManager notificationRoundnessManager,
DynamicPrivacyController dynamicPrivacyController,
SysuiStatusBarStateController statusbarStateController,
NotificationSectionsManager notificationSectionsManager,
ForegroundServiceSectionController fgsSectionController,
ForegroundServiceDismissalFeatureController fgsFeatureController,
FeatureFlags featureFlags,
NotifPipeline notifPipeline,
NotificationEntryManager entryManager,
NotifCollection notifCollection,
UiEventLogger uiEventLogger,
GroupMembershipManager groupMembershipManager,
GroupExpansionManager groupExpansionManager
GroupExpansionManager groupExpansionManager,
UiEventLogger uiEventLogger
) {
super(context, attrs, 0, 0);
Resources res = getResources();
@@ -576,7 +548,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mSectionsManager.initialize(this, LayoutInflater.from(context));
mSectionsManager.setOnClearSilentNotifsClickListener(v -> {
// Leave the shade open if there will be other notifs left over to clear
final boolean closeShade = !hasActiveClearableNotifications(ROWS_HIGH_PRIORITY);
final boolean closeShade =
!mController.hasActiveClearableNotifications(ROWS_HIGH_PRIORITY);
clearNotifications(ROWS_GENTLE, closeShade);
});
mSections = mSectionsManager.createSectionsForBuckets();
@@ -613,37 +586,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mDebugPaint.setTextSize(25f);
}
mClearAllEnabled = res.getBoolean(R.bool.config_enableNotificationsClearAll);
TunerService tunerService = Dependency.get(TunerService.class);
tunerService.addTunable((key, newValue) -> {
if (key.equals(HIGH_PRIORITY)) {
mHighPriorityBeforeSpeedBump = "1".equals(newValue);
}
}, HIGH_PRIORITY);
mFeatureFlags = featureFlags;
mNotifPipeline = notifPipeline;
mEntryManager = entryManager;
mNotifCollection = notifCollection;
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
public void onEntryUpdated(NotificationEntry entry) {
NotificationStackScrollLayout.this.onEntryUpdated(entry);
}
});
} else {
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
NotificationStackScrollLayout.this.onEntryUpdated(entry);
}
});
}
mGroupMembershipManager = groupMembershipManager;
mGroupExpansionManager = groupExpansionManager;
mDynamicPrivacyController = dynamicPrivacyController;
mStatusbarStateController = statusbarStateController;
initializeForegroundServiceSection(fgsFeatureController);
mUiEventLogger = uiEventLogger;
@@ -707,10 +651,13 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
if (mFooterView == null) {
return;
}
boolean showDismissView = mClearAllEnabled && hasActiveClearableNotifications(ROWS_ALL);
boolean showFooterView = (showDismissView || hasActiveNotifications())
// TODO: move this logic to controller, which will invoke updateFooterView directly
boolean showDismissView = mClearAllEnabled &&
mController.hasActiveClearableNotifications(ROWS_ALL);
RemoteInputController remoteInputController = mRemoteInputManager.getController();
boolean showFooterView = (showDismissView || mController.hasActiveNotifications())
&& mStatusBarState != StatusBarState.KEYGUARD
&& !mRemoteInputManager.getController().isRemoteInputActive();
&& (remoteInputController == null || !remoteInputController.isRemoteInputActive());
boolean showHistory = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
@@ -721,22 +668,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
* Return whether there are any clearable notifications
*/
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
public boolean hasActiveClearableNotifications(@SelectedRows int selection) {
if (mDynamicPrivacyController.isInLockedDownShade()) {
return false;
}
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (!(child instanceof ExpandableNotificationRow)) {
continue;
}
final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
if (row.canViewBeDismissed() && matchesSelection(row, selection)) {
return true;
}
}
return false;
boolean hasActiveClearableNotifications(@SelectedRows int selection) {
return mController.hasActiveClearableNotifications(selection);
}
@ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
@@ -5292,8 +5225,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
updateFooter();
requestChildrenUpdate();
onUpdateRowStates();
mEntryManager.updateNotifications("StatusBar state changed");
updateVisibility();
}
@@ -5697,10 +5628,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return mController;
}
void setCurrentUserid(int userId) {
mCurrentUserId = userId;
}
void addSwipedOutView(View v) {
mSwipedOutViews.add(v);
}
@@ -5774,6 +5701,14 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
return mCheckForLeavebehind;
}
void setDismissAllAnimationListener(DismissAllAnimationListener dismissAllAnimationListener) {
mDismissAllAnimationListener = dismissAllAnimationListener;
}
public void setHighPriorityBeforeSpeedBump(boolean highPriorityBeforeSpeedBump) {
mHighPriorityBeforeSpeedBump = highPriorityBeforeSpeedBump;
}
/**
* A listener that is notified when the empty space below the notifications is clicked on
*/
@@ -5852,7 +5787,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
mSwipeHelper.resetExposedMenuView(animate, force);
}
private static boolean matchesSelection(
static boolean matchesSelection(
ExpandableNotificationRow row,
@SelectedRows int selection) {
switch (selection) {
@@ -6127,7 +6062,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
// --------------------- NotificationEntryManager/NotifPipeline methods ------------------------
private void onEntryUpdated(NotificationEntry entry) {
void onEntryUpdated(NotificationEntry entry) {
// If the row already exists, the user may have performed a dismiss action on the
// notification. Since it's not clearable we should snap it back.
if (entry.rowExists() && !entry.getSbn().isClearable()) {
@@ -6135,73 +6070,17 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
}
private boolean hasActiveNotifications() {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
return !mNotifPipeline.getShadeList().isEmpty();
} else {
return mEntryManager.hasActiveNotifications();
}
}
/**
* Called after the animations for a "clear all notifications" action has ended.
*/
private void onDismissAllAnimationsEnd(
List<ExpandableNotificationRow> viewsToRemove,
@SelectedRows int selectedRows) {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
if (selectedRows == ROWS_ALL) {
mNotifCollection.dismissAllNotifications(mCurrentUserId);
} else {
final List<Pair<NotificationEntry, DismissedByUserStats>>
entriesWithRowsDismissedFromShade = new ArrayList<>();
final int numVisibleEntries = mNotifPipeline.getShadeListCount();
for (int i = 0; i < viewsToRemove.size(); i++) {
final NotificationEntry entry = viewsToRemove.get(i).getEntry();
entriesWithRowsDismissedFromShade.add(
new Pair<NotificationEntry, DismissedByUserStats>(
entry,
getDismissedByUserStats(entry, numVisibleEntries)));
}
mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade);
}
} else {
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
if (canChildBeDismissed(rowToRemove)) {
mEntryManager.performRemoveNotification(
rowToRemove.getEntry().getSbn(),
getDismissedByUserStats(
rowToRemove.getEntry(),
mEntryManager.getActiveNotificationsCount()),
NotificationListenerService.REASON_CANCEL_ALL);
} else {
rowToRemove.resetTranslation();
}
}
if (selectedRows == ROWS_ALL) {
try {
mBarService.onClearAllNotifications(mCurrentUserId);
} catch (Exception ex) {
}
}
if (mDismissAllAnimationListener != null) {
mDismissAllAnimationListener.onAnimationEnd(viewsToRemove, selectedRows);
}
}
private DismissedByUserStats getDismissedByUserStats(
NotificationEntry entry,
int numVisibleEntries
) {
return new DismissedByUserStats(
DISMISSAL_SHADE,
DISMISS_SENTIMENT_NEUTRAL,
NotificationVisibility.obtain(
entry.getKey(),
entry.getRanking().getRank(),
numVisibleEntries,
true,
NotificationLogger.getNotificationLocation(entry)));
}
public void setKeyguardMediaControllorVisible(boolean keyguardMediaControllorVisible) {
mKeyguardMediaControllorVisible = keyguardMediaControllorVisible;
}
@@ -6218,7 +6097,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
/* Only ever called as a consequence of a lockscreen expansion gesture. */
@Override
public boolean onDraggedDown(View startingChild, int dragLengthY) {
boolean canDragDown = hasActiveNotifications() || mKeyguardMediaControllorVisible;
boolean canDragDown =
mController.hasActiveNotifications() || mKeyguardMediaControllorVisible;
if (mStatusBarState == StatusBarState.KEYGUARD && canDragDown) {
mLockscreenGestureLogger.write(
MetricsEvent.ACTION_LS_SHADE,
@@ -6236,7 +6116,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
}
return true;
} else if (mDynamicPrivacyController.isInLockedDownShade()) {
} else if (mController.isInLockedDownShade()) {
mStatusbarStateController.setLeaveOpenOnKeyguardHide(true);
mStatusBar.dismissKeyguardThenExecute(() -> false /* dismissAction */,
null /* cancelRunnable */, false /* afterKeyguardGone */);
@@ -6280,7 +6160,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
if (isDragDownAnywhereEnabled()) {
return true;
}
if (mDynamicPrivacyController.isInLockedDownShade()) {
if (mController.isInLockedDownShade()) {
if (view == null) {
// Dragging down is allowed in general
return true;
@@ -6424,7 +6304,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
/** Enum for selecting some or all notification rows (does not included non-notif views). */
@Retention(SOURCE)
@IntDef({ROWS_ALL, ROWS_HIGH_PRIORITY, ROWS_GENTLE})
public @interface SelectedRows {}
@interface SelectedRows {}
/** All rows representing notifs. */
public static final int ROWS_ALL = 0;
/** Only rows where entry.isHighPriority() is true. */
@@ -6466,4 +6346,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable
interface KeyguardBypassEnabledProvider {
boolean getBypassEnabled();
}
interface DismissAllAnimationListener {
void onAnimationEnd(
List<ExpandableNotificationRow> viewsToRemove, @SelectedRows int selectedRows);
}
}

View File

@@ -16,17 +16,28 @@
package com.android.systemui.statusbar.notification.stack;
import static android.service.notification.NotificationStats.DISMISSAL_SHADE;
import static android.service.notification.NotificationStats.DISMISS_SENTIMENT_NEUTRAL;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_HIGH_PRIORITY;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnEmptySpaceClickListener;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.OnOverscrollTopChangedListener;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.SelectedRows;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.canChildBeDismissed;
import static com.android.systemui.statusbar.phone.NotificationIconAreaController.HIGH_PRIORITY;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.PointF;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.util.Pair;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
@@ -37,6 +48,8 @@ import android.widget.FrameLayout;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
@@ -49,6 +62,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.NotificationShelfController;
@@ -58,10 +72,17 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.ShadeViewRefactor;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.NotificationGroup;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy.OnGroupChangeListener;
import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.dagger.SilentHeader;
@@ -86,6 +107,8 @@ import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.tuner.TunerService;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiConsumer;
import javax.inject.Inject;
@@ -114,6 +137,11 @@ public class NotificationStackScrollLayoutController {
private final Resources mResources;
private final NotificationSwipeHelper.Builder mNotificationSwipeHelperBuilder;
private final ScrimController mScrimController;
private final FeatureFlags mFeatureFlags;
private final NotifPipeline mNotifPipeline;
private final NotifCollection mNotifCollection;
private final NotificationEntryManager mNotificationEntryManager;
private final IStatusBarService mIStatusBarService;
private final KeyguardMediaController mKeyguardMediaController;
private final SysuiStatusBarStateController mStatusBarStateController;
private final KeyguardBypassController mKeyguardBypassController;
@@ -211,13 +239,13 @@ public class NotificationStackScrollLayoutController {
mView.updateSensitiveness(mStatusBarStateController.goingToFullShade(),
mLockscreenUserManager.isAnyProfilePublicMode());
mView.onStatePostChange(mStatusBarStateController.fromShadeLocked());
mNotificationEntryManager.updateNotifications("StatusBar state changed");
}
};
private final UserChangedListener mLockscreenUserChangeListener = new UserChangedListener() {
@Override
public void onUserChanged(int userId) {
mView.setCurrentUserid(userId);
mView.updateSensitiveness(false, mLockscreenUserManager.isAnyProfilePublicMode());
}
};
@@ -525,7 +553,12 @@ public class NotificationStackScrollLayoutController {
ScrimController scrimController,
NotificationGroupManagerLegacy legacyGroupManager,
GroupExpansionManager groupManager,
@SilentHeader SectionHeaderController silentHeaderController) {
@SilentHeader SectionHeaderController silentHeaderController,
FeatureFlags featureFlags,
NotifPipeline notifPipeline,
NotifCollection notifCollection,
NotificationEntryManager notificationEntryManager,
IStatusBarService iStatusBarService) {
mAllowLongPress = allowLongPress;
mNotificationGutsManager = notificationGutsManager;
mHeadsUpManager = headsUpManager;
@@ -549,7 +582,6 @@ public class NotificationStackScrollLayoutController {
groupManager.registerGroupExpansionChangeListener((changedRow, expanded) -> {
mView.onGroupExpandChanged(changedRow, expanded);
});
legacyGroupManager.registerGroupChangeListener(new OnGroupChangeListener() {
@Override
public void onGroupCreatedFromChildren(NotificationGroup group) {
@@ -562,6 +594,11 @@ public class NotificationStackScrollLayoutController {
}
});
mSilentHeaderController = silentHeaderController;
mFeatureFlags = featureFlags;
mNotifPipeline = notifPipeline;
mNotifCollection = notifCollection;
mNotificationEntryManager = notificationEntryManager;
mIStatusBarService = iStatusBarService;
}
public void attach(NotificationStackScrollLayout view) {
@@ -569,6 +606,7 @@ public class NotificationStackScrollLayoutController {
mView.setController(this);
mView.setTouchHandler(new TouchHandler());
mView.setStatusBar(mStatusBar);
mView.setDismissAllAnimationListener(this::onAnimationEnd);
mSwipeHelper = mNotificationSwipeHelperBuilder
.setSwipeDirection(SwipeHelper.X)
@@ -576,6 +614,22 @@ public class NotificationStackScrollLayoutController {
.setOnMenuEventListener(mMenuEventListener)
.build();
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
public void onEntryUpdated(NotificationEntry entry) {
mView.onEntryUpdated(entry);
}
});
} else {
mNotificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
mView.onEntryUpdated(entry);
}
});
}
mView.initView(mView.getContext(), mKeyguardBypassController::getBypassEnabled,
mSwipeHelper);
@@ -587,7 +641,6 @@ public class NotificationStackScrollLayoutController {
mScrimController.setScrimBehindChangeRunnable(mView::updateBackgroundDimming);
mLockscreenUserManager.addUserChangedListener(mLockscreenUserChangeListener);
mView.setCurrentUserid(mLockscreenUserManager.getCurrentUserId());
mFadeNotificationsOnDismiss = // TODO: this should probably be injected directly
mResources.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
@@ -597,12 +650,19 @@ public class NotificationStackScrollLayoutController {
mTunerService.addTunable(
(key, newValue) -> {
if (key.equals(Settings.Secure.NOTIFICATION_DISMISS_RTL)) {
mView.updateDismissRtlSetting("1".equals(newValue));
} else if (key.equals(Settings.Secure.NOTIFICATION_HISTORY_ENABLED)) {
updateFooter();
switch (key) {
case Settings.Secure.NOTIFICATION_DISMISS_RTL:
mView.updateDismissRtlSetting("1".equals(newValue));
break;
case Settings.Secure.NOTIFICATION_HISTORY_ENABLED:
updateFooter();
break;
case HIGH_PRIORITY:
mView.setHighPriorityBeforeSpeedBump("1".equals(newValue));
break;
}
},
HIGH_PRIORITY,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
Settings.Secure.NOTIFICATION_HISTORY_ENABLED);
@@ -684,12 +744,12 @@ public class NotificationStackScrollLayoutController {
}
public void setOverscrollTopChangedListener(
NotificationStackScrollLayout.OnOverscrollTopChangedListener listener) {
OnOverscrollTopChangedListener listener) {
mView.setOverscrollTopChangedListener(listener);
}
public void setOnEmptySpaceClickListener(
NotificationStackScrollLayout.OnEmptySpaceClickListener listener) {
OnEmptySpaceClickListener listener) {
mView.setOnEmptySpaceClickListener(listener);
}
@@ -1007,9 +1067,26 @@ public class NotificationStackScrollLayoutController {
mView.setPulsing(pulsing, animatePulse);
}
public boolean hasActiveClearableNotifications(
@NotificationStackScrollLayout.SelectedRows int selection) {
return mView.hasActiveClearableNotifications(selection);
/**
* Return whether there are any clearable notifications
*/
public boolean hasActiveClearableNotifications(@SelectedRows int selection) {
if (mDynamicPrivacyController.isInLockedDownShade()) {
return false;
}
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (!(child instanceof ExpandableNotificationRow)) {
continue;
}
final ExpandableNotificationRow row = (ExpandableNotificationRow) child;
if (row.canViewBeDismissed() &&
NotificationStackScrollLayout.matchesSelection(row, selection)) {
return true;
}
}
return false;
}
/**
@@ -1120,6 +1197,29 @@ public class NotificationStackScrollLayoutController {
mView.resetCheckSnoozeLeavebehind();
}
private DismissedByUserStats getDismissedByUserStats(
NotificationEntry entry,
int numVisibleEntries
) {
return new DismissedByUserStats(
DISMISSAL_SHADE,
DISMISS_SENTIMENT_NEUTRAL,
NotificationVisibility.obtain(
entry.getKey(),
entry.getRanking().getRank(),
numVisibleEntries,
true,
NotificationLogger.getNotificationLocation(entry)));
}
boolean hasActiveNotifications() {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
return !mNotifPipeline.getShadeList().isEmpty();
} else {
return mNotificationEntryManager.hasActiveNotifications();
}
}
public void closeControlsIfOutsideTouch(MotionEvent ev) {
NotificationGuts guts = mNotificationGutsManager.getExposedGuts();
NotificationMenuRowPlugin menuRow = mSwipeHelper.getCurrentMenuRow();
@@ -1148,6 +1248,51 @@ public class NotificationStackScrollLayoutController {
mView.clearNotifications(ROWS_GENTLE, closeShade);
}
private void onAnimationEnd(List<ExpandableNotificationRow> viewsToRemove, int selectedRows) {
if (mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
if (selectedRows == ROWS_ALL) {
mNotifCollection.dismissAllNotifications(
mLockscreenUserManager.getCurrentUserId());
} else {
final List<Pair<NotificationEntry, DismissedByUserStats>>
entriesWithRowsDismissedFromShade = new ArrayList<>();
final int numVisibleEntries = mNotifPipeline.getShadeListCount();
for (ExpandableNotificationRow row : viewsToRemove) {
final NotificationEntry entry = row.getEntry();
entriesWithRowsDismissedFromShade.add(
new Pair<>(
entry,
getDismissedByUserStats(entry, numVisibleEntries)));
}
mNotifCollection.dismissNotifications(entriesWithRowsDismissedFromShade);
}
} else {
for (ExpandableNotificationRow rowToRemove : viewsToRemove) {
if (canChildBeDismissed(rowToRemove)) {
mNotificationEntryManager.performRemoveNotification(
rowToRemove.getEntry().getSbn(),
getDismissedByUserStats(
rowToRemove.getEntry(),
mNotificationEntryManager.getActiveNotificationsCount()),
NotificationListenerService.REASON_CANCEL_ALL);
} else {
rowToRemove.resetTranslation();
}
}
if (selectedRows == ROWS_ALL) {
try {
mIStatusBarService.onClearAllNotifications(
mLockscreenUserManager.getCurrentUserId());
} catch (Exception ignored) {
}
}
}
}
public boolean isInLockedDownShade() {
return mDynamicPrivacyController.isInLockedDownShade();
}
private class NotificationListContainerImpl implements NotificationListContainer {
@Override

View File

@@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.stack;
import static android.provider.Settings.Secure.NOTIFICATION_HISTORY_ENABLED;
import static android.provider.Settings.Secure.NOTIFICATION_NEW_INTERRUPTION_MODEL;
import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNotNull;
@@ -43,44 +45,26 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.testing.UiEventLoggerFake;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.ExpandHelper;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.NotificationShelfController;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger;
import com.android.systemui.statusbar.notification.NotificationFilter;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
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.notification.stack.NotificationStackScrollLayout.KeyguardBypassEnabledProvider;
import com.android.systemui.statusbar.phone.HeadsUpManagerPhone;
import com.android.systemui.statusbar.phone.ShadeController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.util.leak.LeakDetector;
import org.junit.After;
import org.junit.Before;
@@ -92,9 +76,6 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for {@link NotificationStackScrollLayout}.
*/
@@ -109,7 +90,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Rule public MockitoRule mockito = MockitoJUnit.rule();
@Mock private StatusBar mBar;
@Mock private SysuiStatusBarStateController mBarState;
@Mock private HeadsUpManagerPhone mHeadsUpManager;
@Mock private NotificationBlockingHelperManager mBlockingHelperManager;
@Mock private NotificationGroupManagerLegacy mGroupMembershipManger;
@Mock private NotificationGroupManagerLegacy mGroupExpansionManager;
@@ -122,11 +102,9 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Mock private KeyguardBypassEnabledProvider mKeyguardBypassEnabledProvider;
@Mock private NotificationSectionsManager mNotificationSectionsManager;
@Mock private NotificationSection mNotificationSection;
@Mock private FeatureFlags mFeatureFlags;
@Mock private SysuiStatusBarStateController mStatusBarStateController;
@Mock private NotificationSwipeHelper mNotificationSwipeHelper;
@Mock NotificationStackScrollLayoutController mStackScrollLayoutController;
private NotificationEntryManager mEntryManager;
@Mock private NotificationStackScrollLayoutController mStackScrollLayoutController;
private int mOriginalInterruptionModelSetting;
private UiEventLoggerFake mUiEventLoggerFake = new UiEventLoggerFake();
@@ -154,31 +132,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mRemoteInputManager);
mDependency.injectMockDependency(ShadeController.class);
when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
mEntryManager = new NotificationEntryManager(
mock(NotificationEntryManagerLogger.class),
mock(NotificationGroupManagerLegacy.class),
new NotificationRankingManager(
() -> mock(NotificationMediaManager.class),
mGroupMembershipManger,
mHeadsUpManager,
mock(NotificationFilter.class),
mock(NotificationEntryManagerLogger.class),
mock(NotificationSectionsFeatureManager.class),
mock(PeopleNotificationIdentifier.class),
mock(HighPriorityProvider.class)
),
mock(NotificationEntryManager.KeyguardEnvironment.class),
mock(FeatureFlags.class),
() -> mock(NotificationRowBinder.class),
() -> mRemoteInputManager,
mock(LeakDetector.class),
mock(ForegroundServiceDismissalFeatureController.class),
mock(IStatusBarService.class)
);
mEntryManager.setUpWithPresenter(mock(NotificationPresenter.class));
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
NotificationShelfController notificationShelfController =
mock(NotificationShelfController.class);
NotificationShelf notificationShelf = mock(NotificationShelf.class);
@@ -196,18 +149,13 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
getContext(),
null,
mNotificationRoundnessManager,
mock(DynamicPrivacyController.class),
mStatusBarStateController,
mNotificationSectionsManager,
mock(ForegroundServiceSectionController.class),
mock(ForegroundServiceDismissalFeatureController.class),
mFeatureFlags,
mock(NotifPipeline.class),
mEntryManager,
mock(NotifCollection.class),
mUiEventLoggerFake,
mGroupMembershipManger,
mGroupExpansionManager
mGroupExpansionManager,
mUiEventLoggerFake
);
mStackScrollerInternal.initView(getContext(), mKeyguardBypassEnabledProvider,
mNotificationSwipeHelper);
@@ -216,9 +164,9 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
mStackScroller.setStatusBar(mBar);
mStackScroller.setEmptyShadeView(mEmptyShadeView);
when(mStackScrollLayoutController.getNoticationRoundessManager())
.thenReturn(mock(NotificationRoundnessManager.class));
.thenReturn(mNotificationRoundnessManager);
mStackScroller.setController(mStackScrollLayoutController);
// Stub out functionality that isn't necessary to test.
doNothing().when(mBar)
.executeRunnableDismissingKeyguard(any(Runnable.class),
@@ -323,8 +271,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testUpdateFooter_noNotifications() {
setBarStateForTest(StatusBarState.SHADE);
assertEquals(0, mEntryManager.getActiveNotificationsCount());
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
mStackScroller.updateFooter();
@@ -334,15 +280,15 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testUpdateFooter_remoteInput() {
setBarStateForTest(StatusBarState.SHADE);
ArrayList<NotificationEntry> entries = new ArrayList<>();
entries.add(new NotificationEntryBuilder().build());
addEntriesToEntryManager(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);
when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL))
.thenReturn(true);
when(mStackScrollLayoutController.hasActiveNotifications()).thenReturn(true);
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
@@ -354,14 +300,9 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void testUpdateFooter_oneClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
ArrayList<NotificationEntry> entries = new ArrayList<>();
entries.add(new NotificationEntryBuilder().build());
addEntriesToEntryManager(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.canViewBeDismissed()).thenReturn(true);
when(mStackScroller.getChildCount()).thenReturn(1);
when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL))
.thenReturn(true);
when(mStackScrollLayoutController.hasActiveNotifications()).thenReturn(true);
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
@@ -373,9 +314,13 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
public void testUpdateFooter_oneNonClearableNotification() {
setBarStateForTest(StatusBarState.SHADE);
ArrayList<NotificationEntry> entries = new ArrayList<>();
entries.add(new NotificationEntryBuilder().build());
addEntriesToEntryManager(entries);
ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
when(row.canViewBeDismissed()).thenReturn(false);
when(mStackScroller.getChildCount()).thenReturn(1);
when(mStackScroller.getChildAt(anyInt())).thenReturn(row);
when(mStackScrollLayoutController.hasActiveNotifications()).thenReturn(true);
when(mStackScrollLayoutController.hasActiveClearableNotifications(ROWS_ALL))
.thenReturn(false);
FooterView view = mock(FooterView.class);
mStackScroller.setFooterView(view);
@@ -435,7 +380,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testClearNotifications_All() {
mStackScroller.clearNotifications(NotificationStackScrollLayout.ROWS_ALL, true);
mStackScroller.clearNotifications(ROWS_ALL, true);
assertEquals(1, mUiEventLoggerFake.numLogs());
assertEquals(NotificationStackScrollLayout.NotificationPanelEvent
.DISMISS_ALL_NOTIFICATIONS_PANEL.getId(), mUiEventLoggerFake.eventId(0));
@@ -508,10 +453,4 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
// rather than the mock because the spy just coppied the anonymous inner /shruggie.
mStackScroller.setStatusBarState(state);
}
private void addEntriesToEntryManager(List<NotificationEntry> entries) {
for (NotificationEntry e : entries) {
mEntryManager.addActiveNotificationForTest(e);
}
}
}

View File

@@ -37,6 +37,7 @@ import androidx.test.filters.SmallTest;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.media.KeyguardMediaController;
@@ -44,10 +45,14 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationLockscreenUserManager.UserChangedListener;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -101,9 +106,14 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
@Mock private ScrimController mScrimController;
@Mock private NotificationGroupManagerLegacy mLegacyGroupManager;
@Mock private SectionHeaderController mSilentHeaderController;
@Mock private FeatureFlags mFeatureFlags;
@Mock private NotifPipeline mNotifPipeline;
@Mock private NotifCollection mNotifCollection;
@Mock private NotificationEntryManager mEntryManager;
@Mock private IStatusBarService mIStatusBarService;
@Captor
ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
private ArgumentCaptor<StatusBarStateController.StateListener> mStateListenerArgumentCaptor;
private NotificationStackScrollLayoutController mController;
@@ -112,6 +122,7 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this);
when(mNotificationSwipeHelperBuilder.build()).thenReturn(mNotificationSwipeHelper);
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
mController = new NotificationStackScrollLayoutController(
true,
@@ -136,7 +147,12 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
mScrimController,
mLegacyGroupManager,
mLegacyGroupManager,
mSilentHeaderController
mSilentHeaderController,
mFeatureFlags,
mNotifPipeline,
mNotifCollection,
mEntryManager,
mIStatusBarService
);
when(mNotificationStackScrollLayout.isAttachedToWindow()).thenReturn(true);
@@ -236,7 +252,6 @@ public class NotificationStackScrollerControllerTest extends SysuiTestCase {
UserChangedListener changedListener = userChangedCaptor.getValue();
changedListener.onUserChanged(0);
verify(mNotificationStackScrollLayout).setCurrentUserid(0);
verify(mNotificationStackScrollLayout).updateSensitiveness(false, true);
}