Allow notifications to be smaller in width than its container.
Add a width dimension that the children of the
NotificationStackScrollLayout can use to make a separate MeasureSpec for
its children.
Also, adjust the translation of the row so that the row can be swiped
off screen without any clipping if the width is smaller than the
notification panel itself.
Test: booted on phone and Android Auto headunit
Bug: 36692077
Change-Id: Ic8bb8a707c4d91f4e38d5ee3461b406bf14d0042
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index d34a8b5..aac2d1f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -345,4 +345,15 @@
have been scrolled off-screen. -->
<bool name="config_showNotificationShelf">true</bool>
+ <!-- Whether or not the notifications should always fade as they are dismissed. -->
+ <bool name="config_fadeNotificationsOnDismiss">false</bool>
+
+ <!-- Whether or not the parent of the notification row itself is being translated when swiped or
+ its children views. If true, then the contents are translated and vice versa. -->
+ <bool name="config_translateNotificationContentsOnSwipe">true</bool>
+
+ <!-- Whether or not the fade on the notification is based on the amount that it has been swiped
+ off-screen. -->
+ <bool name="config_fadeDependingOnAmountSwiped">false</bool>
+
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index cdb5af9..d031fe8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -69,6 +69,10 @@
<!-- Height of a small notification in the status bar-->
<dimen name="notification_min_height">92dp</dimen>
+ <!-- Width of each individual notification in the notification panel. MATCH_PARENT in this
+ case means the notifications will be measured with its parent's MeasureSpec. -->
+ <dimen name="notification_child_width">@dimen/match_parent</dimen>
+
<!-- Increased height of a small notification in the status bar -->
<dimen name="notification_min_height_increased">132dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 8c4159a..36c38f3 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -22,6 +22,7 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Handler;
import android.util.Log;
@@ -30,9 +31,7 @@
import android.view.View;
import android.view.ViewConfiguration;
import android.view.accessibility.AccessibilityEvent;
-
import com.android.systemui.classifier.FalsingManager;
-import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -88,6 +87,7 @@
private int mFalsingThreshold;
private boolean mTouchAboveFalsingThreshold;
private boolean mDisableHwLayers;
+ private boolean mFadeDependingOnAmountSwiped;
private Context mContext;
private HashMap<View, Animator> mDismissPendingMap = new HashMap<>();
@@ -98,12 +98,15 @@
mHandler = new Handler();
mSwipeDirection = swipeDirection;
mVelocityTracker = VelocityTracker.obtain();
- mDensityScale = context.getResources().getDisplayMetrics().density;
mPagingTouchSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop();
- mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f); // extra long-press!
- mFalsingThreshold = context.getResources().getDimensionPixelSize(
- R.dimen.swipe_helper_falsing_threshold);
+ // Extra long-press!
+ mLongPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
+
+ Resources res = context.getResources();
+ mDensityScale = res.getDisplayMetrics().density;
+ mFalsingThreshold = res.getDimensionPixelSize(R.dimen.swipe_helper_falsing_threshold);
+ mFadeDependingOnAmountSwiped = res.getBoolean(R.bool.config_fadeDependingOnAmountSwiped);
mFalsingManager = FalsingManager.getInstance(context);
mFlingAnimationUtils = new FlingAnimationUtils(context, getMaxEscapeAnimDuration() / 1000f);
}
@@ -173,8 +176,7 @@
}
protected float getSize(View v) {
- return mSwipeDirection == X ? v.getMeasuredWidth() :
- v.getMeasuredHeight();
+ return mSwipeDirection == X ? v.getMeasuredWidth() : v.getMeasuredHeight();
}
public void setMinSwipeProgress(float minSwipeProgress) {
@@ -192,6 +194,11 @@
}
private float getSwipeAlpha(float progress) {
+ if (mFadeDependingOnAmountSwiped) {
+ // The more progress has been fade, the lower the alpha value so that the view fades.
+ return Math.max(1 - progress, 0);
+ }
+
return Math.min(0, Math.max(1, progress / SWIPE_PROGRESS_FADE_END));
}
@@ -204,9 +211,8 @@
float swipeProgress = getSwipeProgressForOffset(animView, translation);
if (!mCallback.updateSwipeProgress(animView, dismissable, swipeProgress)) {
if (FADE_OUT_DURING_SWIPE && dismissable) {
- float alpha = swipeProgress;
if (!mDisableHwLayers) {
- if (alpha != 0f && alpha != 1f) {
+ if (swipeProgress != 0f && swipeProgress != 1f) {
animView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
} else {
animView.setLayerType(View.LAYER_TYPE_NONE, null);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index dff09bd..7277ff9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -24,6 +24,7 @@
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.ColorDrawable;
@@ -1143,9 +1144,10 @@
mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
mMaxHeadsUpHeightIncreased = getFontScaledHeight(
R.dimen.notification_max_heads_up_height_increased);
- mIncreasedPaddingBetweenElements = getResources()
- .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
- mIconTransformContentShiftNoIcon = getResources().getDimensionPixelSize(
+ Resources res = getResources();
+ mIncreasedPaddingBetweenElements = res.getDimensionPixelSize(
+ R.dimen.notification_divider_height_increased);
+ mIconTransformContentShiftNoIcon = res.getDimensionPixelSize(
R.dimen.notification_icon_transform_content_shift);
}
@@ -1199,30 +1201,39 @@
mChildrenContainer.setIsLowPriority(mIsLowPriority);
mChildrenContainer.setContainingNotification(ExpandableNotificationRow.this);
mChildrenContainer.onNotificationUpdated();
- mTranslateableViews.add(mChildrenContainer);
+
+ if (mShouldTranslateContents) {
+ mTranslateableViews.add(mChildrenContainer);
+ }
}
});
- // Add the views that we translate to reveal the menu
- mTranslateableViews = new ArrayList<View>();
- for (int i = 0; i < getChildCount(); i++) {
- mTranslateableViews.add(getChildAt(i));
+ if (mShouldTranslateContents) {
+ // Add the views that we translate to reveal the menu
+ mTranslateableViews = new ArrayList<>();
+ for (int i = 0; i < getChildCount(); i++) {
+ mTranslateableViews.add(getChildAt(i));
+ }
+ // Remove views that don't translate
+ mTranslateableViews.remove(mChildrenContainerStub);
+ mTranslateableViews.remove(mGutsStub);
}
- // Remove views that don't translate
- mTranslateableViews.remove(mChildrenContainerStub);
- mTranslateableViews.remove(mGutsStub);
}
public void resetTranslation() {
if (mTranslateAnim != null) {
mTranslateAnim.cancel();
}
- if (mTranslateableViews != null) {
+
+ if (!mShouldTranslateContents) {
+ setTranslationX(0);
+ } else if (mTranslateableViews != null) {
for (int i = 0; i < mTranslateableViews.size(); i++) {
mTranslateableViews.get(i).setTranslationX(0);
}
+ invalidateOutline();
}
- invalidateOutline();
+
mMenuRow.resetMenu();
}
@@ -1242,13 +1253,17 @@
// Don't translate if guts are showing.
return;
}
- // Translate the group of views
- for (int i = 0; i < mTranslateableViews.size(); i++) {
- if (mTranslateableViews.get(i) != null) {
- mTranslateableViews.get(i).setTranslationX(translationX);
+ if (!mShouldTranslateContents) {
+ setTranslationX(translationX);
+ } else if (mTranslateableViews != null) {
+ // Translate the group of views
+ for (int i = 0; i < mTranslateableViews.size(); i++) {
+ if (mTranslateableViews.get(i) != null) {
+ mTranslateableViews.get(i).setTranslationX(translationX);
+ }
}
+ invalidateOutline();
}
- invalidateOutline();
if (mMenuRow.getMenuView() != null) {
mMenuRow.onTranslationUpdate(translationX);
}
@@ -1256,10 +1271,15 @@
@Override
public float getTranslation() {
+ if (mShouldTranslateContents) {
+ return getTranslationX();
+ }
+
if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
// All of the views in the list should have same translation, just use first one.
return mTranslateableViews.get(0).getTranslationX();
}
+
return 0;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 91abc87..553c478 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -17,12 +17,14 @@
package com.android.systemui.statusbar;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
+import com.android.systemui.R;
/**
* Like {@link ExpandableView}, but setting an outline for the height and clipping.
@@ -33,10 +35,16 @@
private boolean mCustomOutline;
private float mOutlineAlpha = -1f;
- ViewOutlineProvider mProvider = new ViewOutlineProvider() {
+ /**
+ * {@code true} if the children views of the {@link ExpandableOutlineView} are translated when
+ * it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself.
+ */
+ protected boolean mShouldTranslateContents;
+
+ private final ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- int translation = (int) getTranslation();
+ int translation = mShouldTranslateContents ? 0 : (int) getTranslation();
if (!mCustomOutline) {
outline.setRect(translation,
mClipTopAmount,
@@ -52,6 +60,9 @@
public ExpandableOutlineView(Context context, AttributeSet attrs) {
super(context, attrs);
setOutlineProvider(mProvider);
+ Resources res = getResources();
+ mShouldTranslateContents =
+ res.getBoolean(R.bool.config_translateNotificationContentsOnSwipe);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index ef5a25c..a2f488c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification;
import android.content.Context;
-import android.service.notification.StatusBarNotification;
import android.view.View;
import com.android.systemui.statusbar.ExpandableNotificationRow;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 391d96b..771e02a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -150,6 +150,13 @@
private int mBottomInset = 0;
/**
+ * The width of each child View in this layout. A value of -1 or
+ * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT} will make it so that the children
+ * match this View's width.
+ */
+ private int mChildWidth;
+
+ /**
* The algorithm which calculates the properties for our children
*/
protected final StackScrollAlgorithm mStackScrollAlgorithm;
@@ -205,6 +212,7 @@
protected DismissView mDismissView;
protected EmptyShadeView mEmptyShadeView;
private boolean mDismissAllInProgress;
+ private boolean mFadeNotificationsOnDismiss;
/**
* Was the scroller scrolled to the top when the down motion was observed?
@@ -391,6 +399,7 @@
mBgColor = context.getColor(R.color.notification_shade_background_color);
int minHeight = res.getDimensionPixelSize(R.dimen.notification_min_height);
int maxHeight = res.getDimensionPixelSize(R.dimen.notification_max_height);
+ mChildWidth = res.getDimensionPixelSize(R.dimen.notification_child_width);
mExpandHelper = new ExpandHelper(getContext(), this,
minHeight, maxHeight);
mExpandHelper.setEventSource(this);
@@ -402,6 +411,8 @@
mFalsingManager = FalsingManager.getInstance(context);
mShouldDrawNotificationBackground =
res.getBoolean(R.bool.config_drawNotificationBackground);
+ mFadeNotificationsOnDismiss =
+ res.getBoolean(R.bool.config_fadeNotificationsOnDismiss);
updateWillNotDraw();
if (DEBUG) {
@@ -536,11 +547,18 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ // If the children want to match the parent's width, then simply pass this View's width
+ // MeasureSpec. It should contain the width to measure at.
+ int childWidthSpec = mChildWidth == LayoutParams.MATCH_PARENT
+ ? widthMeasureSpec
+ : MeasureSpec.makeMeasureSpec(mChildWidth, MeasureSpec.EXACTLY);
+
// We need to measure all children even the GONE ones, such that the heights are calculated
// correctly as they are used to calculate how many we can fit on the screen.
final int size = getChildCount();
for (int i = 0; i < size; i++) {
- measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
+ measureChild(getChildAt(i), childWidthSpec, heightMeasureSpec);
}
}
@@ -964,7 +982,8 @@
mScrimController.setTopHeadsUpDragAmount(animView,
Math.min(Math.abs(swipeProgress / 2f - 1.0f), 1.0f));
}
- return true; // Don't fade out the notification
+ // Returning true prevents alpha fading.
+ return !mFadeNotificationsOnDismiss;
}
@Override