Merge changes from topic "b147245740-activitable-notif-view-component"

* changes:
  Add new ExpandableNotificationRowController.
  Fill in ActivatableNotificationViewController.
This commit is contained in:
Dave Mankoff
2020-02-07 14:12:52 +00:00
committed by Android (Google) Code Review
23 changed files with 805 additions and 282 deletions

View File

@@ -30,6 +30,7 @@ import android.view.IWindowManager;
import android.view.LayoutInflater;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.internal.widget.LockPatternUtils;
import com.android.keyguard.ViewMediatorCallback;
import com.android.systemui.dagger.qualifiers.Background;
@@ -191,6 +192,12 @@ public class DependencyProvider {
return new AlwaysOnDisplayPolicy(context);
}
/***/
@Provides
public NotificationMessagingUtil provideNotificationMessagingUtil(Context context) {
return new NotificationMessagingUtil(context);
}
/** */
@Provides
public ViewMediatorCallback providesViewMediatorCallback(KeyguardViewMediator viewMediator) {

View File

@@ -40,6 +40,7 @@ import com.android.systemui.statusbar.notification.collection.inflation.Notifica
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -68,7 +69,9 @@ import dagger.Provides;
NotificationsModule.class,
PeopleHubModule.class,
},
subcomponents = {StatusBarComponent.class, NotificationRowComponent.class})
subcomponents = {StatusBarComponent.class,
NotificationRowComponent.class,
ExpandableNotificationRowComponent.class})
public abstract class SystemUIModule {
@Binds

View File

@@ -68,6 +68,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga
import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotificationGuts;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager;
@@ -149,6 +150,7 @@ public final class NotificationEntry extends ListEntry {
private NotificationEntry parent; // our parent (if we're in a group)
private ExpandableNotificationRow row; // the outer expanded view
private ExpandableNotificationRowController mRowController;
private int mCachedContrastColor = COLOR_INVALID;
private int mCachedContrastColorIsFor = COLOR_INVALID;
@@ -420,6 +422,14 @@ public final class NotificationEntry extends ListEntry {
this.row = row;
}
public ExpandableNotificationRowController getRowController() {
return mRowController;
}
public void setRowController(ExpandableNotificationRowController controller) {
mRowController = controller;
}
@Nullable
public List<NotificationEntry> getChildren() {
if (row == null) {

View File

@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.collection.inflation;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP;
import android.annotation.Nullable;
@@ -40,19 +39,19 @@ import com.android.systemui.statusbar.notification.InflationException;
import com.android.systemui.statusbar.notification.NotificationClicker;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.Objects;
@@ -67,35 +66,28 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
private static final String TAG = "NotificationViewManager";
private final NotificationGroupManager mGroupManager;
private final NotificationGutsManager mGutsManager;
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final Context mContext;
private final NotifBindPipeline mNotifBindPipeline;
private final RowContentBindStage mRowContentBindStage;
private final NotificationMessagingUtil mMessagingUtil;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
private final NotificationRemoteInputManager mNotificationRemoteInputManager;
private final NotificationLockscreenUserManager mNotificationLockscreenUserManager;
private final boolean mAllowLongPress;
private final KeyguardBypassController mKeyguardBypassController;
private final StatusBarStateController mStatusBarStateController;
private NotificationPresenter mPresenter;
private NotificationListContainer mListContainer;
private HeadsUpManager mHeadsUpManager;
private NotificationRowContentBinder.InflationCallback mInflationCallback;
private ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private BindRowCallback mBindRowCallback;
private NotificationClicker mNotificationClicker;
private final Provider<RowInflaterTask> mRowInflaterTaskProvider;
private final NotificationLogger mNotificationLogger;
private final ExpandableNotificationRowComponent.Builder
mExpandableNotificationRowComponentBuilder;
@Inject
public NotificationRowBinderImpl(
Context context,
NotificationMessagingUtil notificationMessagingUtil,
NotificationRemoteInputManager notificationRemoteInputManager,
NotificationLockscreenUserManager notificationLockscreenUserManager,
NotifBindPipeline notifBindPipeline,
@@ -107,21 +99,16 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
NotificationGutsManager notificationGutsManager,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
Provider<RowInflaterTask> rowInflaterTaskProvider,
NotificationLogger logger) {
ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) {
mContext = context;
mNotifBindPipeline = notifBindPipeline;
mRowContentBindStage = rowContentBindStage;
mMessagingUtil = new NotificationMessagingUtil(context);
mMessagingUtil = notificationMessagingUtil;
mNotificationRemoteInputManager = notificationRemoteInputManager;
mNotificationLockscreenUserManager = notificationLockscreenUserManager;
mAllowLongPress = allowLongPress;
mKeyguardBypassController = keyguardBypassController;
mStatusBarStateController = statusBarStateController;
mGroupManager = notificationGroupManager;
mGutsManager = notificationGutsManager;
mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mRowInflaterTaskProvider = rowInflaterTaskProvider;
mNotificationLogger = logger;
mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
}
/**
@@ -129,13 +116,10 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
*/
public void setUpWithPresenter(NotificationPresenter presenter,
NotificationListContainer listContainer,
HeadsUpManager headsUpManager,
BindRowCallback bindRowCallback) {
mPresenter = presenter;
mListContainer = listContainer;
mHeadsUpManager = headsUpManager;
mBindRowCallback = bindRowCallback;
mOnAppOpsClickListener = mGutsManager::openGuts;
}
public void setInflationCallback(NotificationRowContentBinder.InflationCallback callback) {
@@ -150,9 +134,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
* Inflates the views for the given entry (possibly asynchronously).
*/
@Override
public void inflateViews(
NotificationEntry entry,
Runnable onDismissRunnable)
public void inflateViews(NotificationEntry entry, Runnable onDismissRunnable)
throws InflationException {
ViewGroup parent = mListContainer.getViewParentForNotification(entry);
PackageManager pmUser = StatusBar.getPackageManagerForUser(mContext,
@@ -163,12 +145,26 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
entry.updateIcons(mContext, sbn);
entry.reset();
updateNotification(entry, pmUser, sbn, entry.getRow());
entry.getRow().setOnDismissRunnable(onDismissRunnable);
entry.getRowController().setOnDismissRunnable(onDismissRunnable);
} else {
entry.createIcons(mContext, sbn);
mRowInflaterTaskProvider.get().inflate(mContext, parent, entry,
row -> {
bindRow(entry, pmUser, sbn, row, onDismissRunnable);
// Setup the controller for the view.
ExpandableNotificationRowComponent component =
mExpandableNotificationRowComponentBuilder
.expandableNotificationRow(row)
.notificationEntry(entry)
.onDismissRunnable(onDismissRunnable)
.inflationCallback(mInflationCallback)
.rowContentBindStage(mRowContentBindStage)
.onExpandClickListener(mPresenter)
.build();
ExpandableNotificationRowController rowController =
component.getExpandableNotificationRowController();
rowController.init();
entry.setRowController(rowController);
bindRow(entry, pmUser, sbn, row);
updateNotification(entry, pmUser, sbn, row);
});
}
@@ -176,55 +172,12 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
//TODO: This method associates a row with an entry, but eventually needs to not do that
private void bindRow(NotificationEntry entry, PackageManager pmUser,
StatusBarNotification sbn, ExpandableNotificationRow row,
Runnable onDismissRunnable) {
// Get the app name.
// Note that Notification.Builder#bindHeaderAppName has similar logic
// but since this field is used in the guts, it must be accurate.
// Therefore we will only show the application label, or, failing that, the
// package name. No substitutions.
final String pkg = sbn.getPackageName();
String appname = pkg;
try {
final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS);
if (info != null) {
appname = String.valueOf(pmUser.getApplicationLabel(info));
}
} catch (PackageManager.NameNotFoundException e) {
// Do nothing
}
row.initialize(
appname,
sbn.getKey(),
mExpansionLogger,
mKeyguardBypassController,
mGroupManager,
mHeadsUpManager,
mRowContentBindStage,
mPresenter);
// TODO: Either move these into ExpandableNotificationRow#initialize or out of row entirely
row.setStatusBarStateController(mStatusBarStateController);
row.setAppOpsOnClickListener(mOnAppOpsClickListener);
if (mAllowLongPress) {
row.setLongPressListener(mGutsManager::openGuts);
}
StatusBarNotification sbn, ExpandableNotificationRow row) {
mListContainer.bindRow(row);
mNotificationRemoteInputManager.bindRow(row);
row.setOnDismissRunnable(onDismissRunnable);
row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (ENABLE_REMOTE_INPUT) {
row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
entry.setRow(row);
row.setEntry(entry);
mNotifBindPipeline.manageRow(entry, row);
mBindRowCallback.onBindRow(entry, pmUser, sbn, row);
}
@@ -307,10 +260,6 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
Objects.requireNonNull(mNotificationClicker).register(row, sbn);
}
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
mNotificationLogger.onExpansionChanged(key, userAction, expanded);
}
/** Callback for when a row is bound to an entry. */
public interface BindRowCallback {
/**

View File

@@ -90,7 +90,6 @@ class NotificationsControllerImpl @Inject constructor(
notificationRowBinder.setUpWithPresenter(
presenter,
listContainer,
headsUpManager,
bindRowCallback)
if (featureFlags.isNewNotifPipelineEnabled) {

View File

@@ -29,20 +29,17 @@ import android.util.MathUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
import com.android.systemui.Dependency;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.FakeShadowView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.phone.DoubleTapHelper;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationShelf}
@@ -94,14 +91,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
= new PathInterpolator(0, 0, 0.5f, 1);
private int mTintedRippleColor;
protected int mNormalRippleColor;
private final AccessibilityManager mAccessibilityManager;
private final DoubleTapHelper mDoubleTapHelper;
private int mNormalRippleColor;
private Gefingerpoken mTouchHandler;
private boolean mDimmed;
protected int mBgTint = NO_COLOR;
private float mBgAlpha = 1f;
int mBgTint = NO_COLOR;
/**
* Flag to indicate that the notification has been touched once and the second touch will
@@ -116,7 +111,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private Interpolator mCurrentAppearInterpolator;
private Interpolator mCurrentAlphaInterpolator;
protected NotificationBackgroundView mBackgroundNormal;
NotificationBackgroundView mBackgroundNormal;
private NotificationBackgroundView mBackgroundDimmed;
private ObjectAnimator mBackgroundAnimator;
private RectF mAppearAnimationRect = new RectF();
@@ -130,7 +125,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
private boolean mLastInSection;
private boolean mFirstInSection;
private boolean mIsBelowSpeedBump;
private final FalsingManager mFalsingManager;
private float mNormalBackgroundVisibilityAmount;
private float mDimmedBackgroundFadeInAmount = -1;
@@ -154,38 +148,24 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
*/
private boolean mNeedsDimming;
private int mDimmedAlpha;
private boolean mBlockNextTouch;
private boolean mIsHeadsUpAnimation;
private int mHeadsUpAddStartLocation;
private float mHeadsUpLocation;
private boolean mIsAppearing;
private boolean mDismissed;
private boolean mRefocusOnDismiss;
private OnDimmedListener mOnDimmedListener;
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mSlowOutFastInInterpolator = new PathInterpolator(0.8f, 0.0f, 0.6f, 1.0f);
mSlowOutLinearInInterpolator = new PathInterpolator(0.8f, 0.0f, 1.0f, 1.0f);
mFalsingManager = Dependency.get(FalsingManager.class); // TODO: inject into a controller.
setClipChildren(false);
setClipToPadding(false);
updateColors();
mAccessibilityManager = AccessibilityManager.getInstance(mContext);
mDoubleTapHelper = new DoubleTapHelper(this, (active) -> {
if (active) {
makeActive();
} else {
makeInactive(true /* animate */);
}
}, super::performClick, this::handleSlideBack, mFalsingManager::onNotificationDoubleTap);
initDimens();
}
public FalsingManager getFalsingManager() {
return mFalsingManager;
}
private void updateColors() {
mNormalColor = mContext.getColor(R.color.notification_material_background_color);
mTintedRippleColor = mContext.getColor(
@@ -236,32 +216,15 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
}
private final Runnable mTapTimeoutRunnable = new Runnable() {
@Override
public void run() {
makeInactive(true /* animate */);
}
};
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mNeedsDimming && ev.getActionMasked() == MotionEvent.ACTION_DOWN
&& disallowSingleClick(ev) && !isTouchExplorationEnabled()) {
if (!mActivated) {
return true;
} else if (!mDoubleTapHelper.isWithinDoubleTapSlop(ev)) {
mBlockNextTouch = true;
makeInactive(true /* animate */);
return true;
}
if (mTouchHandler != null && mTouchHandler.onInterceptTouchEvent(ev)) {
return true;
}
return super.onInterceptTouchEvent(ev);
}
private boolean isTouchExplorationEnabled() {
return mAccessibilityManager.isTouchExplorationEnabled();
}
protected boolean disallowSingleClick(MotionEvent ev) {
return false;
}
@@ -270,25 +233,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result;
if (mBlockNextTouch) {
mBlockNextTouch = false;
return false;
}
if (mNeedsDimming && !isTouchExplorationEnabled() && isInteractive()) {
boolean wasActivated = mActivated;
result = handleTouchEventDimmed(event);
if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
removeCallbacks(mTapTimeoutRunnable);
}
} else {
result = super.onTouchEvent(event);
}
return result;
}
/**
* @return whether this view is interactive and can be double tapped
*/
@@ -313,28 +257,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
public void setRippleAllowed(boolean allowed) {
void setRippleAllowed(boolean allowed) {
mBackgroundNormal.setPressedAllowed(allowed);
}
private boolean handleTouchEventDimmed(MotionEvent event) {
if (mNeedsDimming && !mDimmed) {
// We're actually dimmed, but our content isn't dimmable, let's ensure we have a ripple
super.onTouchEvent(event);
}
return mDoubleTapHelper.onTouchEvent(event, getActualHeight());
}
@Override
public boolean performClick() {
if (!mNeedsDimming || isTouchExplorationEnabled()) {
return super.performClick();
}
return false;
}
private void makeActive() {
mFalsingManager.onNotificationActive();
void makeActive() {
startActivateAnimation(false /* reverse */);
mActivated = true;
if (mOnActivatedListener != null) {
@@ -388,15 +315,12 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mBackgroundNormal.animate()
.alpha(reverse ? 0f : 1f)
.setInterpolator(alphaInterpolator)
.setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float animatedFraction = animation.getAnimatedFraction();
if (reverse) {
animatedFraction = 1.0f - animatedFraction;
}
setNormalBackgroundVisibilityAmount(animatedFraction);
.setUpdateListener(animation -> {
float animatedFraction = animation.getAnimatedFraction();
if (reverse) {
animatedFraction = 1.0f - animatedFraction;
}
setNormalBackgroundVisibilityAmount(animatedFraction);
})
.setDuration(ACTIVATE_ANIMATION_LENGTH);
}
@@ -418,11 +342,13 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
if (mOnActivatedListener != null) {
mOnActivatedListener.onActivationReset(this);
}
removeCallbacks(mTapTimeoutRunnable);
}
public void setDimmed(boolean dimmed, boolean fade) {
mNeedsDimming = dimmed;
if (mOnDimmedListener != null) {
mOnDimmedListener.onSetDimmed(dimmed);
}
dimmed &= isDimmable();
if (mDimmed != dimmed) {
mDimmed = dimmed;
@@ -439,13 +365,17 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
return true;
}
public boolean isDimmed() {
return mDimmed;
}
private void updateOutlineAlpha() {
float alpha = NotificationStackScrollLayout.BACKGROUND_ALPHA_DIMMED;
alpha = (alpha + (1.0f - alpha) * mNormalBackgroundVisibilityAmount);
setOutlineAlpha(alpha);
}
public void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
private void setNormalBackgroundVisibilityAmount(float normalBackgroundVisibilityAmount) {
mNormalBackgroundVisibilityAmount = normalBackgroundVisibilityAmount;
updateOutlineAlpha();
}
@@ -473,14 +403,14 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
/**
* Sets the tint color of the background
*/
public void setTintColor(int color) {
protected void setTintColor(int color) {
setTintColor(color, false);
}
/**
* Sets the tint color of the background
*/
public void setTintColor(int color, boolean animated) {
void setTintColor(int color, boolean animated) {
if (color != mBgTint) {
mBgTint = color;
updateBackgroundTint(animated);
@@ -562,13 +492,10 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mStartTint = mCurrentBackgroundTint;
mTargetTint = color;
mBackgroundColorAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
mBackgroundColorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
animation.getAnimatedFraction());
setBackgroundTintColor(newColor);
}
mBackgroundColorAnimator.addUpdateListener(animation -> {
int newColor = NotificationUtils.interpolateColors(mStartTint, mTargetTint,
animation.getAnimatedFraction());
setBackgroundTintColor(newColor);
});
mBackgroundColorAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
mBackgroundColorAnimator.setInterpolator(Interpolators.LINEAR);
@@ -643,11 +570,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
protected void updateBackgroundAlpha(float transformationAmount) {
mBgAlpha = isChildInGroup() && mDimmed ? transformationAmount : 1f;
float bgAlpha = isChildInGroup() && mDimmed ? transformationAmount : 1f;
if (mDimmedBackgroundFadeInAmount != -1) {
mBgAlpha *= mDimmedBackgroundFadeInAmount;
bgAlpha *= mDimmedBackgroundFadeInAmount;
}
mBackgroundDimmed.setAlpha(mBgAlpha);
mBackgroundDimmed.setAlpha(bgAlpha);
}
protected void resetBackgroundAlpha() {
@@ -671,7 +598,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mBackgroundDimmed.setVisibility(View.INVISIBLE);
mBackgroundNormal.setVisibility(View.VISIBLE);
mBackgroundNormal.setAlpha(1f);
removeCallbacks(mTapTimeoutRunnable);
// make in inactive to avoid it sticking around active
makeInactive(false /* animate */);
}
@@ -783,14 +709,11 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mAppearAnimator.setInterpolator(Interpolators.LINEAR);
mAppearAnimator.setDuration(
(long) (duration * Math.abs(mAppearAnimationFraction - targetValue)));
mAppearAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mAppearAnimationFraction = (float) animation.getAnimatedValue();
updateAppearAnimationAlpha();
updateAppearRect();
invalidate();
}
mAppearAnimator.addUpdateListener(animation -> {
mAppearAnimationFraction = (float) animation.getAnimatedValue();
updateAppearAnimationAlpha();
updateAppearRect();
invalidate();
});
if (animationListener != null) {
mAppearAnimator.addListener(animationListener);
@@ -921,7 +844,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
getCurrentBackgroundRadiusBottom());
}
protected void applyBackgroundRoundness(float topRadius, float bottomRadius) {
private void applyBackgroundRoundness(float topRadius, float bottomRadius) {
mBackgroundDimmed.setRoundness(topRadius, bottomRadius);
mBackgroundNormal.setRoundness(topRadius, bottomRadius);
}
@@ -963,7 +886,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
}
}
protected int getRippleColor() {
private int getRippleColor() {
if (mBgTint != 0) {
return mTintedRippleColor;
} else {
@@ -1010,10 +933,6 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
mOnActivatedListener = onActivatedListener;
}
public boolean hasSameBgColor(ActivatableNotificationView otherView) {
return calculateBgColor() == otherView.calculateBgColor();
}
@Override
public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
int outlineTranslation) {
@@ -1071,8 +990,20 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
return mRefocusOnDismiss || isAccessibilityFocused();
}
void setTouchHandler(Gefingerpoken touchHandler) {
mTouchHandler = touchHandler;
}
void setOnDimmedListener(OnDimmedListener onDimmedListener) {
mOnDimmedListener = onDimmedListener;
}
public interface OnActivatedListener {
void onActivated(ActivatableNotificationView view);
void onActivationReset(ActivatableNotificationView view);
}
interface OnDimmedListener {
void onSetDimmed(boolean dimmed);
}
}

View File

@@ -16,9 +16,13 @@
package com.android.systemui.statusbar.notification.row;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.statusbar.phone.DoubleTapHelper;
import javax.inject.Inject;
@@ -27,21 +31,106 @@ import javax.inject.Inject;
*/
public class ActivatableNotificationViewController {
private final ActivatableNotificationView mView;
private final ExpandableOutlineViewController mExpandableOutlineViewController;
private final AccessibilityManager mAccessibilityManager;
private final FalsingManager mFalsingManager;
private DoubleTapHelper mDoubleTapHelper;
private boolean mNeedsDimming;
private TouchHandler mTouchHandler = new TouchHandler();
@Inject
public ActivatableNotificationViewController(ActivatableNotificationView view,
ExpandableOutlineViewController expandableOutlineViewController,
AccessibilityManager accessibilityManager, FalsingManager falsingManager) {
mView = view;
mExpandableOutlineViewController = expandableOutlineViewController;
mAccessibilityManager = accessibilityManager;
mFalsingManager = falsingManager;
mView.setOnActivatedListener(new ActivatableNotificationView.OnActivatedListener() {
@Override
public void onActivated(ActivatableNotificationView view) {
mFalsingManager.onNotificationActive();
}
@Override
public void onActivationReset(ActivatableNotificationView view) {
}
});
}
/**
* Initialize the controller, setting up handlers and other behavior.
*/
public void init() {
mExpandableOutlineViewController.init();
mDoubleTapHelper = new DoubleTapHelper(mView, (active) -> {
if (active) {
mView.makeActive();
mFalsingManager.onNotificationActive();
} else {
mView.makeInactive(true /* animate */);
}
}, mView::performClick, mView::handleSlideBack, mFalsingManager::onNotificationDoubleTap);
mView.setOnTouchListener(mTouchHandler);
mView.setTouchHandler(mTouchHandler);
mView.setOnDimmedListener(dimmed -> {
mNeedsDimming = dimmed;
if (dimmed && !mAccessibilityManager.isTouchExplorationEnabled()) {
mView.setOnClickListener(null);
} else {
mView.setOnClickListener((v) -> mView.performClick());
}
});
}
class TouchHandler implements Gefingerpoken, View.OnTouchListener {
private boolean mBlockNextTouch;
@Override
public boolean onTouch(View v, MotionEvent ev) {
boolean result;
if (mBlockNextTouch) {
mBlockNextTouch = false;
return true;
}
if (mNeedsDimming && !mAccessibilityManager.isTouchExplorationEnabled()
&& mView.isInteractive()) {
if (mNeedsDimming && !mView.isDimmed()) {
// We're actually dimmed, but our content isn't dimmable,
// let's ensure we have a ripple
return false;
}
result = mDoubleTapHelper.onTouchEvent(ev, mView.getActualHeight());
} else {
return false;
}
return result;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (mNeedsDimming && ev.getActionMasked() == MotionEvent.ACTION_DOWN
&& mView.disallowSingleClick(ev)
&& !mAccessibilityManager.isTouchExplorationEnabled()) {
if (!mView.isActivated()) {
return true;
} else if (!mDoubleTapHelper.isWithinDoubleTapSlop(ev)) {
mBlockNextTouch = true;
mView.makeInactive(true /* animate */);
return true;
}
}
return false;
}
/**
* Use {@link #onTouch(View, MotionEvent) instead}.
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
return false;
}
}
}

View File

@@ -42,7 +42,6 @@ import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.SystemClock;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.AttributeSet;
@@ -72,11 +71,11 @@ import com.android.internal.widget.CachingIconView;
import com.android.systemui.Dependency;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarIconView;
@@ -199,6 +198,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private NotificationGuts mGuts;
private NotificationEntry mEntry;
private String mAppName;
private FalsingManager mFalsingManager;
/**
* Whether or not the notification is using the heads up view and should peek from the top.
@@ -1086,20 +1086,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mEntry.setInitializationTime(SystemClock.elapsedRealtime());
Dependency.get(PluginManager.class).addPluginListener(this,
NotificationMenuRowPlugin.class, false /* Allow multiple */);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Dependency.get(PluginManager.class).removePluginListener(this);
}
@Override
public void onPluginConnected(NotificationMenuRowPlugin plugin, Context pluginContext) {
boolean existed = mMenuRow != null && mMenuRow.getMenuView() != null;
@@ -1439,7 +1425,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mIsBlockingHelperShowing && mNotificationTranslationFinished;
}
public void setOnDismissRunnable(Runnable onDismissRunnable) {
void setOnDismissRunnable(Runnable onDismissRunnable) {
mOnDismissRunnable = onDismissRunnable;
}
@@ -1597,7 +1583,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mMenuRow = new NotificationMenuRow(mContext);
mImageResolver = new NotificationInlineImageResolver(context,
new NotificationInlineImageCache());
mMediaManager = Dependency.get(NotificationMediaManager.class);
initDimens();
}
@@ -1612,7 +1597,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
NotificationGroupManager groupManager,
HeadsUpManager headsUpManager,
RowContentBindStage rowContentBindStage,
OnExpandClickListener onExpandClickListener) {
OnExpandClickListener onExpandClickListener,
NotificationMediaManager notificationMediaManager,
OnAppOpsClickListener onAppOpsClickListener,
FalsingManager falsingManager,
StatusBarStateController statusBarStateController) {
mAppName = appName;
if (mMenuRow != null && mMenuRow.getMenuView() != null) {
mMenuRow.setAppName(mAppName);
@@ -1625,9 +1614,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mHeadsUpManager = headsUpManager;
mRowContentBindStage = rowContentBindStage;
mOnExpandClickListener = onExpandClickListener;
}
public void setStatusBarStateController(StatusBarStateController statusBarStateController) {
mMediaManager = notificationMediaManager;
setAppOpsOnClickListener(onAppOpsClickListener);
mFalsingManager = falsingManager;
mStatusbarStateController = statusBarStateController;
}
@@ -1719,7 +1708,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mOnAppOpsClickListener;
}
public void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) {
void setAppOpsOnClickListener(ExpandableNotificationRow.OnAppOpsClickListener l) {
mOnAppOpsClickListener = v -> {
createMenu();
NotificationMenuRowPlugin provider = getProvider();
@@ -2188,7 +2177,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* @param allowChildExpansion whether a call to this method allows expanding children
*/
public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
getFalsingManager().setNotificationExpanded();
mFalsingManager.setNotificationExpanded();
if (mIsSummaryWithChildren && !shouldShowPublic() && allowChildExpansion
&& !mChildrenContainer.showingAsLowPriority()) {
final boolean wasExpanded = mGroupManager.isGroupExpanded(mEntry.getSbn());

View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row;
import static com.android.systemui.Dependency.ALLOW_NOTIFICATION_LONG_PRESS_NAME;
import static com.android.systemui.statusbar.NotificationRemoteInputManager.ENABLE_REMOTE_INPUT;
import android.view.View;
import android.view.ViewGroup;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.dagger.AppName;
import com.android.systemui.statusbar.notification.row.dagger.DismissRunnable;
import com.android.systemui.statusbar.notification.row.dagger.NotificationKey;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.time.SystemClock;
import javax.inject.Inject;
import javax.inject.Named;
/**
* Controller for {@link ExpandableNotificationRow}.
*/
@NotificationRowScope
public class ExpandableNotificationRowController {
private final ExpandableNotificationRow mView;
private final ActivatableNotificationViewController mActivatableNotificationViewController;
private final NotificationMediaManager mMediaManager;
private final PluginManager mPluginManager;
private final SystemClock mClock;
private final String mAppName;
private final String mNotificationKey;
private final KeyguardBypassController mKeyguardBypassController;
private final NotificationGroupManager mNotificationGroupManager;
private final RowContentBindStage mRowContentBindStage;
private final NotificationLogger mNotificationLogger;
private final HeadsUpManager mHeadsUpManager;
private final ExpandableNotificationRow.OnExpandClickListener mOnExpandClickListener;
private final StatusBarStateController mStatusBarStateController;
private final NotificationRowContentBinder.InflationCallback mInflationCallback;
private final ExpandableNotificationRow.ExpansionLogger mExpansionLogger =
this::logNotificationExpansion;
private final ExpandableNotificationRow.OnAppOpsClickListener mOnAppOpsClickListener;
private final NotificationGutsManager mNotificationGutsManager;
private Runnable mOnDismissRunnable;
private final FalsingManager mFalsingManager;
private final boolean mAllowLongPress;
@Inject
public ExpandableNotificationRowController(ExpandableNotificationRow view,
ActivatableNotificationViewController activatableNotificationViewController,
NotificationMediaManager mediaManager, PluginManager pluginManager,
SystemClock clock, @AppName String appName, @NotificationKey String notificationKey,
KeyguardBypassController keyguardBypassController,
NotificationGroupManager notificationGroupManager,
RowContentBindStage rowContentBindStage,
NotificationLogger notificationLogger, HeadsUpManager headsUpManager,
ExpandableNotificationRow.OnExpandClickListener onExpandClickListener,
StatusBarStateController statusBarStateController,
NotificationRowContentBinder.InflationCallback inflationCallback,
NotificationGutsManager notificationGutsManager,
@Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress,
@DismissRunnable Runnable onDismissRunnable, FalsingManager falsingManager) {
mView = view;
mActivatableNotificationViewController = activatableNotificationViewController;
mMediaManager = mediaManager;
mPluginManager = pluginManager;
mClock = clock;
mAppName = appName;
mNotificationKey = notificationKey;
mKeyguardBypassController = keyguardBypassController;
mNotificationGroupManager = notificationGroupManager;
mRowContentBindStage = rowContentBindStage;
mNotificationLogger = notificationLogger;
mHeadsUpManager = headsUpManager;
mOnExpandClickListener = onExpandClickListener;
mStatusBarStateController = statusBarStateController;
mInflationCallback = inflationCallback;
mNotificationGutsManager = notificationGutsManager;
mOnDismissRunnable = onDismissRunnable;
mOnAppOpsClickListener = mNotificationGutsManager::openGuts;
mAllowLongPress = allowLongPress;
mFalsingManager = falsingManager;
}
/**
* Initialize the controller.
*/
public void init() {
mActivatableNotificationViewController.init();
mView.initialize(
mAppName,
mNotificationKey,
mExpansionLogger,
mKeyguardBypassController,
mNotificationGroupManager,
mHeadsUpManager,
mRowContentBindStage,
mOnExpandClickListener,
mMediaManager,
mOnAppOpsClickListener,
mFalsingManager,
mStatusBarStateController
);
mView.setOnDismissRunnable(mOnDismissRunnable);
mView.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
if (mAllowLongPress) {
mView.setLongPressListener(mNotificationGutsManager::openGuts);
}
if (ENABLE_REMOTE_INPUT) {
mView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
}
mView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
mView.getEntry().setInitializationTime(mClock.elapsedRealtime());
mPluginManager.addPluginListener(mView,
NotificationMenuRowPlugin.class, false /* Allow multiple */);
}
@Override
public void onViewDetachedFromWindow(View v) {
mPluginManager.removePluginListener(mView);
}
});
}
private void logNotificationExpansion(String key, boolean userAction, boolean expanded) {
mNotificationLogger.onExpansionChanged(key, userAction, expanded);
}
/** */
public void setOnDismissRunnable(Runnable onDismissRunnable) {
mOnDismissRunnable = onDismissRunnable;
mView.setOnDismissRunnable(onDismissRunnable);
}
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row;
import javax.inject.Inject;
/**
* Controller for {@link ExpandableOutlineView}.
*/
public class ExpandableOutlineViewController {
private final ExpandableOutlineView mView;
private final ExpandableViewController mExpandableViewController;
@Inject
public ExpandableOutlineViewController(ExpandableOutlineView view,
ExpandableViewController expandableViewController) {
mView = view;
mExpandableViewController = expandableViewController;
}
/**
* Initialize the controller.
*/
public void init() {
mExpandableViewController.init();
}
}

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row;
import javax.inject.Inject;
/**
* Controller for {@link ExpandableView}.
*/
public class ExpandableViewController {
private final ExpandableView mView;
@Inject
public ExpandableViewController(ExpandableView view) {
mView = view;
}
/**
* Initialize the controller.
*/
public void init() {
}
}

View File

@@ -26,7 +26,6 @@ import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
import com.android.systemui.R;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import javax.inject.Inject;
@@ -37,7 +36,6 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
private static final String TAG = "RowInflaterTask";
private static final boolean TRACE_ORIGIN = true;
private final NotificationRowComponent.Builder mNotificationRowComponentBuilder;
private RowInflationFinishedListener mListener;
private NotificationEntry mEntry;
@@ -45,10 +43,7 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
private Throwable mInflateOrigin;
@Inject
public RowInflaterTask(
NotificationRowComponent.Builder notificationRowComponentBuilder) {
super();
mNotificationRowComponentBuilder = notificationRowComponentBuilder;
public RowInflaterTask() {
}
/**
@@ -75,12 +70,6 @@ public class RowInflaterTask implements InflationTask, AsyncLayoutInflater.OnInf
public void onInflateFinished(View view, int resid, ViewGroup parent) {
if (!mCancelled) {
try {
// Setup the controller for the view.
NotificationRowComponent component = mNotificationRowComponentBuilder
.activatableNotificationView((ActivatableNotificationView) view)
.build();
component.getActivatableNotificationViewController().init();
mEntry.onInflationTaskFinished();
mListener.onInflationFinished((ExpandableNotificationRow) view);
} catch (Throwable t) {

View File

@@ -0,0 +1,37 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row.dagger;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableOutlineView;
import com.android.systemui.statusbar.notification.row.ExpandableView;
import dagger.Binds;
import dagger.Module;
/**
* Module for NotificationRowComponent.
*/
@Module
public interface ActivatableNotificationViewModule {
/** ExpandableView is provided as an instance of ActivatableNotificationView. */
@Binds
ExpandableView bindExpandableView(ActivatableNotificationView view);
/** ExpandableOutlineView is provided as an instance of ActivatableNotificationView. */
@Binds
ExpandableOutlineView bindExpandableOutlineView(ActivatableNotificationView view);
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface AppName {
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface DismissRunnable {
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row.dagger;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.service.notification.StatusBarNotification;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
import com.android.systemui.statusbar.phone.StatusBar;
import dagger.Binds;
import dagger.BindsInstance;
import dagger.Module;
import dagger.Provides;
import dagger.Subcomponent;
/**
* Dagger Component for a {@link ExpandableNotificationRow}.
*/
@Subcomponent(modules = {ExpandableNotificationRowComponent.ExpandableNotificationRowModule.class,
ActivatableNotificationViewModule.class})
@NotificationRowScope
public interface ExpandableNotificationRowComponent {
/**
* Builder for {@link NotificationRowComponent}.
*/
@Subcomponent.Builder
interface Builder {
// TODO: NotificationEntry contains a reference to ExpandableNotificationRow, so it
// should be possible to pull one from the other, but they aren't connected at the time
// this component is constructed.
@BindsInstance
Builder expandableNotificationRow(ExpandableNotificationRow view);
@BindsInstance
Builder notificationEntry(NotificationEntry entry);
@BindsInstance
Builder onDismissRunnable(@DismissRunnable Runnable runnable);
@BindsInstance
Builder rowContentBindStage(RowContentBindStage rowContentBindStage);
@BindsInstance
Builder inflationCallback(NotificationRowContentBinder.InflationCallback inflationCallback);
@BindsInstance
Builder onExpandClickListener(ExpandableNotificationRow.OnExpandClickListener presenter);
ExpandableNotificationRowComponent build();
}
/**
* Creates a ExpandableNotificationRowController.
*/
@NotificationRowScope
ExpandableNotificationRowController getExpandableNotificationRowController();
/**
* Dagger Module that extracts interesting properties from an ExpandableNotificationRow.
*/
@Module
abstract class ExpandableNotificationRowModule {
/** ExpandableNotificationRow is provided as an instance of ActivatableNotificationView. */
@Binds
abstract ActivatableNotificationView bindExpandableView(ExpandableNotificationRow view);
@Provides
static StatusBarNotification provideStatusBarNotification(
NotificationEntry notificationEntry) {
return notificationEntry.getSbn();
}
@Provides
@NotificationKey
static String provideNotificationKey(StatusBarNotification statusBarNotification) {
return statusBarNotification.getKey();
}
@Provides
@AppName
static String provideAppName(Context context, StatusBarNotification statusBarNotification) {
// Get the app name.
// Note that Notification.Builder#bindHeaderAppName has similar logic
// but since this field is used in the guts, it must be accurate.
// Therefore we will only show the application label, or, failing that, the
// package name. No substitutions.
PackageManager pmUser = StatusBar.getPackageManagerForUser(
context, statusBarNotification.getUser().getIdentifier());
final String pkg = statusBarNotification.getPackageName();
try {
final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
PackageManager.MATCH_UNINSTALLED_PACKAGES
| PackageManager.MATCH_DISABLED_COMPONENTS);
if (info != null) {
return String.valueOf(pmUser.getApplicationLabel(info));
}
} catch (PackageManager.NameNotFoundException e) {
// Do nothing
}
return pkg;
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface NotificationKey {
}

View File

@@ -16,24 +16,17 @@
package com.android.systemui.statusbar.notification.row.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Scope;
import dagger.BindsInstance;
import dagger.Subcomponent;
/**
* Dagger subcomponent for Notification related views.
*/
@Subcomponent(modules = {})
@NotificationRowComponent.NotificationRowScope
@Subcomponent(modules = {ActivatableNotificationViewModule.class})
@NotificationRowScope
public interface NotificationRowComponent {
/**
* Builder for {@link NotificationRowComponent}.
@@ -45,14 +38,6 @@ public interface NotificationRowComponent {
NotificationRowComponent build();
}
/**
* Scope annotation for singleton items within the StatusBarComponent.
*/
@Documented
@Retention(RUNTIME)
@Scope
@interface NotificationRowScope {}
/**
* Creates a ActivatableNotificationViewController.
*/

View File

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.notification.row.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Scope;
/**
* Scope annotation for singleton items within the StatusBarComponent.
*/
@Documented
@Retention(RUNTIME)
@Scope
public @interface NotificationRowScope {}

View File

@@ -58,10 +58,13 @@ import androidx.annotation.NonNull;
import androidx.test.filters.SmallTest;
import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NotificationLifetimeExtender;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -83,12 +86,13 @@ import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController;
import com.android.systemui.statusbar.notification.row.NotifBindPipeline;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.row.RowContentBindParams;
import com.android.systemui.statusbar.notification.row.RowContentBindStage;
import com.android.systemui.statusbar.notification.row.RowInflaterTask;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
@@ -96,6 +100,7 @@ import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.util.Assert;
import com.android.systemui.util.leak.LeakDetector;
import com.android.systemui.util.time.FakeSystemClock;
import org.junit.After;
import org.junit.Before;
@@ -106,6 +111,7 @@ import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.stubbing.Answer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -141,8 +147,13 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
@Mock private NotificationEntryManagerLogger mLogger;
@Mock private FeatureFlags mFeatureFlags;
@Mock private LeakDetector mLeakDetector;
@Mock private ActivatableNotificationViewController mActivatableNotificationViewController;
@Mock private NotificationRowComponent.Builder mNotificationRowComponentBuilder;
@Mock private NotificationMediaManager mNotificationMediaManager;
@Mock private ExpandableNotificationRowComponent.Builder
mExpandableNotificationRowComponentBuilder;
@Mock private ExpandableNotificationRowComponent mExpandableNotificationRowComponent;
@Mock private FalsingManager mFalsingManager;
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private StatusBarStateController mStatusBarStateController;
private int mId;
private NotificationEntry mEntry;
@@ -191,7 +202,6 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
public void setUp() {
MockitoAnnotations.initMocks(this);
mDependency.injectMockDependency(SmartReplyController.class);
mDependency.injectMockDependency(NotificationMediaManager.class);
mCountDownLatch = new CountDownLatch(1);
@@ -207,28 +217,23 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntry.expandedIcon = mock(StatusBarIconView.class);
when(mNotificationRowComponentBuilder.activatableNotificationView(any()))
.thenReturn(mNotificationRowComponentBuilder);
when(mNotificationRowComponentBuilder.build()).thenReturn(
() -> mActivatableNotificationViewController);
RowContentBindStage bindStage = mock(RowContentBindStage.class);
when(bindStage.getStageParams(any())).thenReturn(new RowContentBindParams());
NotificationRowBinderImpl notificationRowBinder =
new NotificationRowBinderImpl(mContext,
new NotificationMessagingUtil(mContext),
mRemoteInputManager,
mLockscreenUserManager,
mock(NotifBindPipeline.class),
bindStage,
true, /* allowLongPress */
mock(KeyguardBypassController.class),
mock(StatusBarStateController.class),
mKeyguardBypassController,
mStatusBarStateController,
mGroupManager,
mGutsManager,
mNotificationInterruptionStateProvider,
() -> new RowInflaterTask(mNotificationRowComponentBuilder),
mock(NotificationLogger.class));
RowInflaterTask::new,
mExpandableNotificationRowComponentBuilder);
when(mFeatureFlags.isNewNotifPipelineEnabled()).thenReturn(false);
when(mFeatureFlags.isNewNotifPipelineRenderingEnabled()).thenReturn(false);
@@ -236,7 +241,7 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mLogger,
mGroupManager,
new NotificationRankingManager(
() -> mock(NotificationMediaManager.class),
() -> mNotificationMediaManager,
mGroupManager,
mHeadsUpManager,
mock(NotificationFilter.class),
@@ -255,13 +260,55 @@ public class NotificationEntryManagerTest extends SysuiTestCase {
mEntryManager.addNotificationEntryListener(mEntryListener);
mEntryManager.addNotificationRemoveInterceptor(mRemoveInterceptor);
notificationRowBinder.setUpWithPresenter(
mPresenter, mListContainer, mHeadsUpManager, mBindCallback);
notificationRowBinder.setUpWithPresenter(mPresenter, mListContainer, mBindCallback);
notificationRowBinder.setInflationCallback(mEntryManager);
notificationRowBinder.setNotificationClicker(mock(NotificationClicker.class));
setUserSentiment(
mEntry.getKey(), Ranking.USER_SENTIMENT_NEUTRAL);
ArgumentCaptor<ExpandableNotificationRow> viewCaptor =
ArgumentCaptor.forClass(ExpandableNotificationRow.class);
when(mExpandableNotificationRowComponentBuilder
.expandableNotificationRow(viewCaptor.capture()))
.thenReturn(mExpandableNotificationRowComponentBuilder);
when(mExpandableNotificationRowComponentBuilder
.notificationEntry(any()))
.thenReturn(mExpandableNotificationRowComponentBuilder);
when(mExpandableNotificationRowComponentBuilder
.onDismissRunnable(any()))
.thenReturn(mExpandableNotificationRowComponentBuilder);
when(mExpandableNotificationRowComponentBuilder
.inflationCallback(any()))
.thenReturn(mExpandableNotificationRowComponentBuilder);
when(mExpandableNotificationRowComponentBuilder
.onExpandClickListener(any()))
.thenReturn(mExpandableNotificationRowComponentBuilder);
when(mExpandableNotificationRowComponentBuilder.build())
.thenReturn(mExpandableNotificationRowComponent);
when(mExpandableNotificationRowComponent.getExpandableNotificationRowController())
.thenAnswer((Answer<ExpandableNotificationRowController>) invocation ->
new ExpandableNotificationRowController(
viewCaptor.getValue(),
mock(ActivatableNotificationViewController.class),
mNotificationMediaManager,
mock(PluginManager.class),
new FakeSystemClock(),
"FOOBAR", "FOOBAR",
mKeyguardBypassController,
mGroupManager,
bindStage,
mock(NotificationLogger.class),
mHeadsUpManager,
mPresenter,
mStatusBarStateController,
mEntryManager,
mGutsManager,
true,
null,
mFalsingManager
));
}
@After

View File

@@ -194,9 +194,8 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
@Test
public void testClickSound() throws Exception {
assertTrue("Should play sounds by default.", mGroupRow.isSoundEffectsEnabled());
StatusBarStateController mock = mock(StatusBarStateController.class);
StatusBarStateController mock = mNotificationTestHelper.getStatusBarStateController();
when(mock.isDozing()).thenReturn(true);
mGroupRow.setStatusBarStateController(mock);
mGroupRow.setSecureStateProvider(()-> false);
assertFalse("Shouldn't play sounds when dark and trusted.",
mGroupRow.isSoundEffectsEnabled());

View File

@@ -45,6 +45,7 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.TestableDependency;
import com.android.systemui.bubbles.BubbleController;
import com.android.systemui.bubbles.BubblesTestActivity;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -91,6 +92,7 @@ public class NotificationTestHelper {
private final NotifBindPipeline mBindPipeline;
private final NotificationEntryListener mBindPipelineEntryListener;
private final RowContentBindStage mBindStage;
private StatusBarStateController mStatusBarStateController;
public NotificationTestHelper(Context context, TestableDependency dependency) {
mContext = context;
@@ -98,9 +100,9 @@ public class NotificationTestHelper {
dependency.injectMockDependency(BubbleController.class);
dependency.injectMockDependency(NotificationShadeWindowController.class);
dependency.injectMockDependency(SmartReplyController.class);
StatusBarStateController stateController = mock(StatusBarStateController.class);
mGroupManager = new NotificationGroupManager(stateController);
mHeadsUpManager = new HeadsUpManagerPhone(mContext, stateController,
mStatusBarStateController = mock(StatusBarStateController.class);
mGroupManager = new NotificationGroupManager(mStatusBarStateController);
mHeadsUpManager = new HeadsUpManagerPhone(mContext, mStatusBarStateController,
mock(KeyguardBypassController.class));
mHeadsUpManager.setUp(null, mGroupManager, null, null);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
@@ -307,6 +309,10 @@ public class NotificationTestHelper {
return notificationBuilder.build();
}
public StatusBarStateController getStatusBarStateController() {
return mStatusBarStateController;
}
private ExpandableNotificationRow generateRow(
Notification notification,
String pkg,
@@ -368,7 +374,11 @@ public class NotificationTestHelper {
mGroupManager,
mHeadsUpManager,
mBindStage,
mock(OnExpandClickListener.class));
mock(OnExpandClickListener.class),
mock(NotificationMediaManager.class),
mock(ExpandableNotificationRow.OnAppOpsClickListener.class),
mock(FalsingManager.class),
mStatusBarStateController);
row.setAboveShelfChangedListener(aboveShelf -> { });
mBindStage.getStageParams(entry).requireContentViews(extraInflationFlags);
inflateAndWait(entry, mBindStage);

View File

@@ -30,7 +30,6 @@ import android.testing.TestableLooper.RunWithLooper;
import androidx.test.filters.SmallTest;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -59,8 +58,6 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
private ExpandableNotificationRow mFirst;
private ExpandableNotificationRow mSecond;
@Mock
private StatusBarStateController mStatusBarStateController;
@Mock
private KeyguardBypassController mBypassController;
@Before
@@ -150,13 +147,12 @@ public class NotificationRoundnessManagerTest extends SysuiTestCase {
createSection(mFirst, mSecond),
createSection(null, null)
});
ExpandableNotificationRow row = new NotificationTestHelper(getContext(), mDependency)
.createRow();
NotificationTestHelper testHelper = new NotificationTestHelper(getContext(), mDependency);
ExpandableNotificationRow row = testHelper.createRow();
NotificationEntry entry = mock(NotificationEntry.class);
when(entry.getRow()).thenReturn(row);
when(mStatusBarStateController.isDozing()).thenReturn(true);
row.setStatusBarStateController(mStatusBarStateController);
when(testHelper.getStatusBarStateController().isDozing()).thenReturn(true);
row.setHeadsUp(true);
mRoundnessManager.onHeadsUpStateChanged(entry, true);
Assert.assertEquals(1f, row.getCurrentBottomRoundness(), 0.0f);