From 7acbb778c48cd9df072c2610ecbdeb5f3255ba09 Mon Sep 17 00:00:00 2001 From: Anthony Chen Date: Fri, 7 Apr 2017 16:45:25 -0700 Subject: [PATCH] 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 --- packages/SystemUI/res/values/config.xml | 11 ++++ packages/SystemUI/res/values/dimens.xml | 4 ++ .../src/com/android/systemui/SwipeHelper.java | 26 +++++---- .../statusbar/ExpandableNotificationRow.java | 56 +++++++++++++------ .../statusbar/ExpandableOutlineView.java | 15 ++++- .../NotificationMediaTemplateViewWrapper.java | 1 - .../stack/NotificationStackScrollLayout.java | 23 +++++++- 7 files changed, 103 insertions(+), 33 deletions(-) diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index d34a8b5946f4a..aac2d1f372b06 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -345,4 +345,15 @@ have been scrolled off-screen. --> true + + false + + + true + + + false + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index cdb5af92c0c8d..d031fe84c591d 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -69,6 +69,10 @@ 92dp + + @dimen/match_parent + 132dp diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java index 8c4159abf0610..36c38f372b46c 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.ObjectAnimator; 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.VelocityTracker; 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 @@ public class SwipeHelper implements Gefingerpoken { private int mFalsingThreshold; private boolean mTouchAboveFalsingThreshold; private boolean mDisableHwLayers; + private boolean mFadeDependingOnAmountSwiped; private Context mContext; private HashMap mDismissPendingMap = new HashMap<>(); @@ -98,12 +98,15 @@ public class SwipeHelper implements Gefingerpoken { 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 @@ public class SwipeHelper implements Gefingerpoken { } 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 @@ public class SwipeHelper implements Gefingerpoken { } 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 @@ public class SwipeHelper implements Gefingerpoken { 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 dff09bda88442..7277ff90a771f 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.ObjectAnimator; 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView 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(); - 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // 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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @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 91abc8779274c..553c478959815 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 @@ public abstract class ExpandableOutlineView extends ExpandableView { 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 abstract class ExpandableOutlineView extends ExpandableView { 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 ef5a25ca52620..a2f488c7d7ed7 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 391d96b487e48..771e02a4c428c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -149,6 +149,13 @@ public class NotificationStackScrollLayout extends ViewGroup private int mTopPadding; 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 */ @@ -205,6 +212,7 @@ public class NotificationStackScrollLayout extends ViewGroup 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 @@ public class NotificationStackScrollLayout extends ViewGroup 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 @@ public class NotificationStackScrollLayout extends ViewGroup 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 @@ public class NotificationStackScrollLayout extends ViewGroup @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 @@ public class NotificationStackScrollLayout extends ViewGroup 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