Merge "Children should have backgrounds" into nyc-dev

This commit is contained in:
Mady Mellor
2016-05-24 20:59:49 +00:00
committed by Android (Google) Code Review
17 changed files with 508 additions and 175 deletions

View File

@@ -18,7 +18,11 @@ package android.view;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.RemoteViews;
@@ -47,6 +51,18 @@ public class NotificationHeaderView extends ViewGroup {
private int mOriginalNotificationColor;
private boolean mExpanded;
private boolean mShowWorkBadgeAtEnd;
private Drawable mBackground;
private int mHeaderBackgroundHeight;
ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (mBackground != null) {
outline.setRect(0, 0, getWidth(), mHeaderBackgroundHeight);
outline.setAlpha(1f);
}
}
};
public NotificationHeaderView(Context context) {
this(context, null);
@@ -66,6 +82,8 @@ public class NotificationHeaderView extends ViewGroup {
com.android.internal.R.dimen.notification_header_shrink_min_width);
mContentEndMargin = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_end);
mHeaderBackgroundHeight = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_header_background_height);
}
@Override
@@ -165,6 +183,43 @@ public class NotificationHeaderView extends ViewGroup {
return new ViewGroup.MarginLayoutParams(getContext(), attrs);
}
/**
* Set a {@link Drawable} to be displayed as a background on the header.
*/
public void setHeaderBackgroundDrawable(Drawable drawable) {
if (drawable != null) {
setWillNotDraw(false);
mBackground = drawable;
mBackground.setCallback(this);
setOutlineProvider(mProvider);
} else {
setWillNotDraw(true);
mBackground = null;
setOutlineProvider(null);
}
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
if (mBackground != null) {
mBackground.setBounds(0, 0, getWidth(), mHeaderBackgroundHeight);
mBackground.draw(canvas);
}
}
@Override
protected boolean verifyDrawable(Drawable who) {
return super.verifyDrawable(who) || who == mBackground;
}
@Override
protected void drawableStateChanged() {
if (mBackground != null && mBackground.isStateful()) {
mBackground.setState(getDrawableState());
}
}
private void updateTouchListener() {
if (mExpandClickListener != null) {
mTouchListener.bindTouchRects();

View File

@@ -163,6 +163,9 @@
<!-- height of the content margin on the bottom -->
<dimen name="notification_content_margin_bottom">16dp</dimen>
<!-- The height of the background for a notification header on a group -->
<dimen name="notification_header_background_height">45.5dp</dimen>
<!-- Height of a small notification in the status bar -->
<dimen name="notification_min_height">92dp</dimen>

View File

@@ -2436,6 +2436,7 @@
<java-symbol type="dimen" name="notification_content_picture_margin" />
<java-symbol type="dimen" name="notification_content_margin_top" />
<java-symbol type="dimen" name="notification_content_margin_bottom" />
<java-symbol type="dimen" name="notification_header_background_height" />
<java-symbol type="string" name="importance_from_user" />
<java-symbol type="string" name="importance_from_person" />

View File

@@ -20,4 +20,4 @@
android:id="@+id/notification_more_divider"
android:layout_width="match_parent"
android:layout_height="@dimen/notification_divider_height"
android:background="#61000000" />
android:background="#FF616161" />

View File

@@ -248,6 +248,9 @@
<!-- The height of the divider between the individual notifications. -->
<dimen name="notification_divider_height">0.5dp</dimen>
<!-- The height of a notification header -->
<dimen name="notification_header_height">53dp</dimen>
<!-- The height of the divider between the individual notifications when the notification wants it to be increased. This is currently the case for notification groups -->
<dimen name="notification_divider_height_increased">6dp</dimen>

View File

@@ -45,6 +45,7 @@ public class ExpandHelper implements Gefingerpoken {
void setUserLockedChild(View v, boolean userLocked);
void expansionStateChanged(boolean isExpanding);
int getMaxExpandHeight(ExpandableView view);
void setExpansionCancelled(View view);
}
private static final String TAG = "ExpandHelper";
@@ -558,6 +559,8 @@ public class ExpandHelper implements Gefingerpoken {
public void onAnimationEnd(Animator animation) {
if (!mCancelled) {
mCallback.setUserExpandedChild(scaledView, expand);
} else {
mCallback.setExpansionCancelled(scaledView);
}
mCallback.setUserLockedChild(scaledView, false);
mScaleAnimation.removeListener(this);

View File

@@ -22,7 +22,6 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Notification;
import android.content.Context;
import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable;
@@ -31,6 +30,8 @@ import android.graphics.drawable.Drawable;
import android.os.Build;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Property;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.NotificationHeaderView;
@@ -39,13 +40,11 @@ import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
import android.widget.Chronometer;
import android.widget.ImageView;
import android.widget.RemoteViews;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
@@ -65,6 +64,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private int mMaxHeadsUpHeight;
private int mNotificationMinHeight;
private int mNotificationMaxHeight;
private int mIncreasedPaddingBetweenElements;
/** Does this row contain layouts that can adapt to row expansion */
private boolean mExpandable;
@@ -97,7 +97,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*/
private boolean mOnKeyguard;
private AnimatorSet mTranslateAnim;
private Animator mTranslateAnim;
private ArrayList<View> mTranslateableViews;
private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout;
@@ -115,8 +115,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private String mAppName;
private boolean mIsHeadsUp;
private boolean mLastChronometerRunning = true;
private NotificationHeaderView mNotificationHeader;
private NotificationViewWrapper mNotificationHeaderWrapper;
private ViewStub mChildrenContainerStub;
private NotificationGroupManager mGroupManager;
private boolean mChildrenExpanded;
@@ -128,13 +126,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mIsPinned;
private FalsingManager mFalsingManager;
private HeadsUpManager mHeadsUpManager;
private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
private boolean mJustClicked;
private boolean mIconAnimationRunning;
private boolean mShowNoBackground;
private ExpandableNotificationRow mNotificationParent;
private OnExpandClickListener mOnExpandClickListener;
private boolean mGroupExpansionChanging;
private OnClickListener mExpandClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
@@ -142,6 +141,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mGroupManager.toggleGroupExpansion(mStatusBarNotification);
mOnExpandClickListener.onExpandClicked(mEntry,
mGroupManager.isGroupExpanded(mStatusBarNotification));
mGroupExpansionChanging = true;
updateBackgroundForGroupState();
} else {
boolean nowExpanded;
if (isPinned()) {
@@ -160,6 +161,29 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mDismissed;
private boolean mKeepInParent;
private boolean mRemoved;
private static final Property<ExpandableNotificationRow, Float> TRANSLATE_CONTENT =
new FloatProperty<ExpandableNotificationRow>("translate") {
@Override
public void setValue(ExpandableNotificationRow object, float value) {
object.setTranslation(value);
}
@Override
public Float get(ExpandableNotificationRow object) {
return object.getTranslation();
}
};
public boolean isGroupExpansionChanging() {
if (isChildInGroup()) {
return mNotificationParent.isGroupExpansionChanging();
}
return mGroupExpansionChanging;
}
public void setGroupExpansionChanging(boolean changing) {
mGroupExpansionChanging = changing;
}
public NotificationContentView getPrivateLayout() {
return mPrivateLayout;
@@ -172,8 +196,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setIconAnimationRunning(boolean running) {
setIconAnimationRunning(running, mPublicLayout);
setIconAnimationRunning(running, mPrivateLayout);
setIconAnimationRunningForChild(running, mNotificationHeader);
if (mIsSummaryWithChildren) {
setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
List<ExpandableNotificationRow> notificationChildren =
mChildrenContainer.getNotificationChildren();
for (int i = 0; i < notificationChildren.size(); i++) {
@@ -235,7 +259,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
updateNotificationColor();
updateClearability();
if (mIsSummaryWithChildren) {
recreateNotificationHeader();
mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
mChildrenContainer.onNotificationUpdated();
}
if (mIconAnimationRunning) {
@@ -329,9 +353,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (mChildrenContainer != null) {
mChildrenContainer.removeNotification(row);
}
if (!row.isRemoved()) {
mHeaderUtil.restoreNotificationHeader(row);
}
onChildrenCountChanged();
row.setIsChildInGroup(false, null);
}
@@ -352,7 +373,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
mNotificationParent = childInGroup ? parent : null;
mPrivateLayout.setIsChildInGroup(childInGroup);
updateNoBackgroundState();
updateBackgroundForGroupState();
if (mNotificationParent != null) {
mNotificationParent.updateBackgroundForGroupState();
}
}
@Override
@@ -544,15 +568,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
public NotificationHeaderView getNotificationHeader() {
if (mNotificationHeader != null) {
return mNotificationHeader;
if (mIsSummaryWithChildren) {
return mChildrenContainer.getHeaderView();
}
return mPrivateLayout.getNotificationHeader();
}
private NotificationHeaderView getVisibleNotificationHeader() {
if (mNotificationHeader != null) {
return mNotificationHeader;
if (mIsSummaryWithChildren) {
return mChildrenContainer.getHeaderView();
}
return getShowingLayout().getVisibleNotificationHeader();
}
@@ -568,11 +592,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void reInflateViews() {
initDimens();
if (mIsSummaryWithChildren) {
removeView(mNotificationHeader);
mNotificationHeader = null;
recreateNotificationHeader();
if (mChildrenContainer != null) {
mChildrenContainer.reInflateViews();
mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
}
}
if (mGuts != null) {
@@ -646,9 +667,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
continue;
}
mChildrenContainer.removeNotification(row);
if (!row.isRemoved()) {
mHeaderUtil.restoreNotificationHeader(row);
}
row.setIsChildInGroup(false, null);
}
onChildrenCountChanged();
@@ -709,6 +727,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mMaxHeadsUpHeightLegacy = getFontScaledHeight(
R.dimen.notification_max_heads_up_height_legacy);
mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
mIncreasedPaddingBetweenElements = getResources()
.getDimensionPixelSize(R.dimen.notification_divider_height_increased);
}
/**
@@ -804,17 +824,13 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mTranslateableViews.remove(mGutsStub);
}
private void setTranslationForOutline(float translationX) {
setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
}
public void resetTranslation() {
if (mTranslateableViews != null) {
for (int i = 0; i < mTranslateableViews.size(); i++) {
mTranslateableViews.get(i).setTranslationX(0);
}
setTranslationForOutline(0);
}
invalidateOutline();
if (mSettingsIconRow != null) {
mSettingsIconRow.resetState();
}
@@ -824,8 +840,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (mTranslateAnim != null) {
mTranslateAnim.cancel();
}
mTranslateAnim = (AnimatorSet) getTranslateViewAnimator(leftTarget,
null /* updateListener */);
mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
if (mTranslateAnim != null) {
mTranslateAnim.start();
}
@@ -843,7 +858,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mTranslateableViews.get(i).setTranslationX(translationX);
}
}
setTranslationForOutline(translationX);
invalidateOutline();
if (mSettingsIconRow != null) {
mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
}
@@ -867,48 +882,29 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
// No translation if guts are exposed.
return null;
}
AnimatorSet set = new AnimatorSet();
if (mTranslateableViews != null) {
for (int i = 0; i < mTranslateableViews.size(); i++) {
final View animView = mTranslateableViews.get(i);
final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(
animView, "translationX", leftTarget);
if (i == 0) {
translateAnim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setTranslationForOutline((float) animation.getAnimatedValue());
if (mSettingsIconRow != null) {
mSettingsIconRow.updateSettingsIcons(
(float) animation.getAnimatedValue(), getMeasuredWidth());
}
}
});
if (listener != null) {
translateAnim.addUpdateListener(listener);
}
translateAnim.addListener(new AnimatorListenerAdapter() {
boolean cancelled = false;
@Override
public void onAnimationCancel(Animator anim) {
cancelled = true;
}
@Override
public void onAnimationEnd(Animator anim) {
if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
mSettingsIconRow.resetState();
mTranslateAnim = null;
}
}
});
}
set.play(translateAnim);
}
final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
leftTarget);
if (listener != null) {
translateAnim.addUpdateListener(listener);
}
mTranslateAnim = set;
return set;
translateAnim.addListener(new AnimatorListenerAdapter() {
boolean cancelled = false;
@Override
public void onAnimationCancel(Animator anim) {
cancelled = true;
}
@Override
public void onAnimationEnd(Animator anim) {
if (!cancelled && mSettingsIconRow != null && leftTarget == 0) {
mSettingsIconRow.resetState();
mTranslateAnim = null;
}
}
});
mTranslateAnim = translateAnim;
return translateAnim;
}
public float getSpaceForGear() {
@@ -937,9 +933,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (mChildrenContainer != null) {
mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
: INVISIBLE);
}
if (mNotificationHeader != null) {
mNotificationHeader.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
? VISIBLE
: INVISIBLE);
}
// The limits might have changed if the view suddenly became a group or vice versa
@@ -969,7 +964,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
if (mIsSummaryWithChildren) {
mChildrenContainer.setDark(dark, fade, delay);
mNotificationHeaderWrapper.setDark(dark, fade, delay);
}
}
@@ -1044,6 +1038,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mPrivateLayout.setUserExpanding(userLocked);
if (mIsSummaryWithChildren) {
mChildrenContainer.setUserLocked(userLocked);
if (userLocked) {
updateBackgroundForGroupState();
}
}
}
@@ -1123,30 +1120,28 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
private boolean isGroupExpanded() {
public boolean isGroupExpanded() {
return mGroupManager.isGroupExpanded(mStatusBarNotification);
}
/**
* @return whether this view has a header on the top of the content
*/
private boolean hasNotificationHeader() {
return mIsSummaryWithChildren;
}
private void onChildrenCountChanged() {
mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
&& mChildrenContainer != null && mChildrenContainer.getChildCount() > 0;
if (mIsSummaryWithChildren) {
if (mNotificationHeader == null) {
recreateNotificationHeader();
}
&& mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
mEntry.notification);
}
mPrivateLayout.updateExpandButtons(isExpandable());
updateChildrenHeaderAppearance();
updateChildrenVisibility();
}
public void updateChildrenHeaderAppearance() {
if (mChildrenContainer != null) {
mChildrenContainer.updateChildrenHeaderAppearance();
}
}
/**
* Check whether the view state is currently expanded. This is given by the system in {@link
* #setSystemExpanded(boolean)} and can be overridden by user expansion or
@@ -1251,8 +1246,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
private void animateShowingPublic(long delay, long duration) {
View[] privateViews = mIsSummaryWithChildren ?
new View[] {mChildrenContainer, mNotificationHeader}
View[] privateViews = mIsSummaryWithChildren
? new View[] {mChildrenContainer}
: new View[] {mPrivateLayout};
View[] publicViews = new View[] {mPublicLayout};
View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
@@ -1302,9 +1297,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setChildrenExpanded(boolean expanded, boolean animate) {
mChildrenExpanded = expanded;
if (mNotificationHeader != null) {
mNotificationHeader.setExpanded(expanded);
}
if (mChildrenContainer != null) {
mChildrenContainer.setChildrenExpanded(expanded);
}
@@ -1348,6 +1340,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return getShowingLayout();
}
@Override
public int getExtraBottomPadding() {
if (mIsSummaryWithChildren && isGroupExpanded()) {
return mIncreasedPaddingBetweenElements;
}
return 0;
}
@Override
public void setActualHeight(int height, boolean notifyListeners) {
super.setActualHeight(height, notifyListeners);
@@ -1406,33 +1406,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
}
private void recreateNotificationHeader() {
final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
getStatusBarNotification().getNotification());
final RemoteViews header = builder.makeNotificationHeader();
if (mNotificationHeader == null) {
mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
final View expandButton = mNotificationHeader.findViewById(
com.android.internal.R.id.expand_button);
expandButton.setVisibility(VISIBLE);
mNotificationHeader.setOnClickListener(mExpandClickListener);
mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
mNotificationHeader, this);
addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
mTranslateableViews.add(mNotificationHeader);
} else {
header.reapply(getContext(), mNotificationHeader);
mNotificationHeaderWrapper.notifyContentUpdated(mEntry.notification);
}
updateChildrenHeaderAppearance();
}
public void updateChildrenHeaderAppearance() {
if (mIsSummaryWithChildren) {
mHeaderUtil.updateChildrenHeaderAppearance();
}
}
public boolean isMaxExpandHeightInitialized() {
return mMaxExpandHeight != 0;
}
@@ -1451,19 +1424,50 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override
protected void updateBackgroundTint() {
super.updateBackgroundTint();
updateNoBackgroundState();
updateBackgroundForGroupState();
if (mIsSummaryWithChildren) {
List<ExpandableNotificationRow> notificationChildren =
mChildrenContainer.getNotificationChildren();
for (int i = 0; i < notificationChildren.size(); i++) {
ExpandableNotificationRow child = notificationChildren.get(i);
child.updateNoBackgroundState();
child.updateBackgroundForGroupState();
}
}
}
private void updateNoBackgroundState() {
mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
/**
* Called when a group has finished animating from collapsed or expanded state.
*/
public void onFinishedExpansionChange() {
mGroupExpansionChanging = false;
updateBackgroundForGroupState();
}
/**
* Updates the parent and children backgrounds in a group based on the expansion state.
*/
public void updateBackgroundForGroupState() {
if (mIsSummaryWithChildren) {
// Only when the group has finished expanding do we hide its background.
mShowNoBackground = isGroupExpanded() && !isGroupExpansionChanging() && !isUserLocked();
mChildrenContainer.updateHeaderForExpansion(mShowNoBackground);
List<ExpandableNotificationRow> children = mChildrenContainer.getNotificationChildren();
for (int i = 0; i < children.size(); i++) {
children.get(i).updateBackgroundForGroupState();
}
} else if (isChildInGroup()) {
final int childColor = getShowingLayout().getBackgroundColorForExpansionState();
// Only show a background if the group is expanded OR if it is expanding / collapsing
// and has a custom background color
final boolean showBackground = isGroupExpanded()
|| ((mNotificationParent.isGroupExpansionChanging()
|| mNotificationParent.isUserLocked()) && childColor != 0);
mShowNoBackground = !showBackground;
} else {
// Only children or parents ever need no background.
mShowNoBackground = false;
}
updateOutline();
updateBackground();
}

View File

@@ -33,22 +33,25 @@ public abstract class ExpandableOutlineView extends ExpandableView {
private boolean mCustomOutline;
private float mOutlineAlpha = -1f;
ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
int translation = (int) getTranslation();
if (!mCustomOutline) {
outline.setRect(translation,
mClipTopAmount,
getWidth() + translation,
Math.max(getActualHeight(), mClipTopAmount));
} else {
outline.setRect(mOutlineRect);
}
outline.setAlpha(mOutlineAlpha);
}
};
public ExpandableOutlineView(Context context, AttributeSet attrs) {
super(context, attrs);
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (!mCustomOutline) {
outline.setRect(0,
mClipTopAmount,
getWidth(),
Math.max(getActualHeight(), mClipTopAmount));
} else {
outline.setRect(mOutlineRect);
}
outline.setAlpha(mOutlineAlpha);
}
});
setOutlineProvider(mProvider);
}
@Override
@@ -87,17 +90,30 @@ public abstract class ExpandableOutlineView extends ExpandableView {
@Override
public int getOutlineTranslation() {
return mCustomOutline ? mOutlineRect.left : 0;
return mCustomOutline ? mOutlineRect.left : (int) getTranslation();
}
public void updateOutline() {
if (mCustomOutline) {
return;
}
boolean hasOutline = true;
if (isChildInGroup()) {
hasOutline = isGroupExpanded() && !isGroupExpansionChanging();
} else if (isSummaryWithChildren()) {
hasOutline = !isGroupExpanded() || isGroupExpansionChanging();
}
setOutlineProvider(hasOutline ? mProvider : null);
}
public boolean isOutlineShowing() {
ViewOutlineProvider op = getOutlineProvider();
return op != null;
}
protected void setOutlineRect(float left, float top, float right, float bottom) {
setOutlineRect(true, left, top, right, bottom);
}
protected void setOutlineRect(boolean clipToOutline, float left, float top, float right,
float bottom) {
mCustomOutline = true;
setClipToOutline(clipToOutline);
setClipToOutline(true);
mOutlineRect.set((int) left, (int) top, (int) right, (int) bottom);

View File

@@ -323,7 +323,7 @@ public abstract class ExpandableView extends FrameLayout {
if (top >= getActualHeight()) {
top = getActualHeight() - 1;
}
mClipRect.set(0, top, getWidth(), getActualHeight());
mClipRect.set(0, top, getWidth(), getActualHeight() + getExtraBottomPadding());
setClipBounds(mClipRect);
} else {
setClipBounds(null);
@@ -410,6 +410,28 @@ public abstract class ExpandableView extends FrameLayout {
return mTransientContainer;
}
/**
* @return padding used to alter how much of the view is clipped.
*/
public int getExtraBottomPadding() {
return 0;
}
/**
* @return true if the group's expansion state is changing, false otherwise.
*/
public boolean isGroupExpansionChanging() {
return false;
}
public boolean isGroupExpanded() {
return false;
}
public boolean isChildInGroup() {
return false;
}
/**
* A listener notifying when {@link #getActualHeight} changes.
*/

View File

@@ -71,7 +71,6 @@ public class NotificationContentView extends FrameLayout {
private HybridGroupManager mHybridGroupManager;
private int mClipTopAmount;
private int mContentHeight;
private int mUnrestrictedContentHeight;
private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
private boolean mDark;
private boolean mAnimate;
@@ -371,8 +370,7 @@ public class NotificationContentView extends FrameLayout {
}
public void setContentHeight(int contentHeight) {
mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());;
mUnrestrictedContentHeight = Math.max(contentHeight, getMinHeight());
mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());
selectLayout(mAnimate /* animate */, false /* force */);
int minHeightHint = getMinContentHeightHint();
@@ -591,7 +589,21 @@ public class NotificationContentView extends FrameLayout {
mContainingNotification.setContentBackground(customBackgroundColor, animate, this);
}
private int getBackgroundColor(int visibleType) {
public int getVisibleType() {
return mVisibleType;
}
public int getBackgroundColorForExpansionState() {
// When expanding or user locked we want the new type, when collapsing we want
// the original type
final int visibleType = (mContainingNotification.isGroupExpanded()
|| mContainingNotification.isUserLocked())
? calculateVisibleType()
: getVisibleType();
return getBackgroundColor(visibleType);
}
public int getBackgroundColor(int visibleType) {
NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
int customBackgroundColor = 0;
if (currentVisibleWrapper != null) {
@@ -699,7 +711,7 @@ public class NotificationContentView extends FrameLayout {
/**
* @return one of the static enum types in this view, calculated form the current state
*/
private int calculateVisibleType() {
public int calculateVisibleType() {
if (mUserExpanding) {
int height = !mIsChildInGroup || isGroupExpanded()
|| mContainingNotification.isExpanded(true /* allowOnKeyguard */)

View File

@@ -90,7 +90,7 @@ public class NotificationHeaderUtil {
private final ArrayList<HeaderProcessor> mComparators = new ArrayList<>();
private final HashSet<Integer> mDividers = new HashSet<>();
NotificationHeaderUtil(ExpandableNotificationRow row) {
public NotificationHeaderUtil(ExpandableNotificationRow row) {
mRow = row;
// To hide the icons if they are the same and the color is the same
mComparators.add(new HeaderProcessor(mRow,

View File

@@ -4335,6 +4335,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (expandView instanceof ExpandableNotificationRow) {
row = (ExpandableNotificationRow) expandView;
row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */);
// Indicate that the group expansion is changing at this time -- this way the group
// and children backgrounds / divider animations will look correct.
row.setGroupExpansionChanging(true);
}
boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
|| !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();

View File

@@ -16,21 +16,28 @@
package com.android.systemui.statusbar.stack;
import android.app.Notification;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.drawable.ColorDrawable;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.NotificationHeaderView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RemoteViews;
import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationHeaderUtil;
import com.android.systemui.statusbar.notification.HybridGroupManager;
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import java.util.ArrayList;
@@ -51,7 +58,7 @@ public class NotificationChildrenContainer extends ViewGroup {
private int mChildPadding;
private int mDividerHeight;
private int mMaxNotificationHeight;
private int mNotificationHeaderHeight;
private int mNotificationHeaderMargin;
private int mNotificatonTopPadding;
private float mCollapsedBottompadding;
private ViewInvertHelper mOverflowInvertHelper;
@@ -63,6 +70,12 @@ public class NotificationChildrenContainer extends ViewGroup {
private boolean mUserLocked;
private int mActualHeight;
private boolean mNeverAppliedGroupState;
private int mHeaderHeight;
private NotificationHeaderView mNotificationHeader;
private NotificationViewWrapper mNotificationHeaderWrapper;
private NotificationHeaderUtil mHeaderUtil;
private ViewState mHeaderViewState;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -88,9 +101,10 @@ public class NotificationChildrenContainer extends ViewGroup {
R.dimen.notification_children_padding);
mDividerHeight = Math.max(1, getResources().getDimensionPixelSize(
R.dimen.notification_divider_height));
mHeaderHeight = getResources().getDimensionPixelSize(R.dimen.notification_header_height);
mMaxNotificationHeight = getResources().getDimensionPixelSize(
R.dimen.notification_max_height);
mNotificationHeaderHeight = getResources().getDimensionPixelSize(
mNotificationHeaderMargin = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_top);
mNotificatonTopPadding = getResources().getDimensionPixelSize(
R.dimen.notification_children_container_top_padding);
@@ -112,6 +126,10 @@ public class NotificationChildrenContainer extends ViewGroup {
mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(),
mOverflowNumber.getMeasuredHeight());
}
if (mNotificationHeader != null) {
mNotificationHeader.layout(0, 0, mNotificationHeader.getMeasuredWidth(),
mNotificationHeader.getMeasuredHeight());
}
}
@Override
@@ -131,7 +149,7 @@ public class NotificationChildrenContainer extends ViewGroup {
newHeightSpec);
}
int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY);
int height = mNotificationHeaderHeight + mNotificatonTopPadding;
int height = mNotificationHeaderMargin + mNotificatonTopPadding;
int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
int collapsedChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
int overflowIndex = childCount > collapsedChildren ? collapsedChildren - 1 : -1;
@@ -155,6 +173,12 @@ public class NotificationChildrenContainer extends ViewGroup {
if (heightMode != MeasureSpec.UNSPECIFIED) {
height = Math.min(height, size);
}
if (mNotificationHeader != null) {
int headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
mNotificationHeader.measure(widthMeasureSpec, headerHeightSpec);
}
setMeasuredDimension(width, height);
}
@@ -201,6 +225,41 @@ public class NotificationChildrenContainer extends ViewGroup {
row.setSystemChildExpanded(false);
row.setUserLocked(false);
updateGroupOverflow();
if (!row.isRemoved()) {
mHeaderUtil.restoreNotificationHeader(row);
}
}
/**
* @return The number of notification children in the container.
*/
public int getNotificationChildCount() {
return mChildren.size();
}
public void recreateNotificationHeader(OnClickListener listener, StatusBarNotification notification) {
final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
mNotificationParent.getStatusBarNotification().getNotification());
final RemoteViews header = builder.makeNotificationHeader();
if (mNotificationHeader == null) {
mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
final View expandButton = mNotificationHeader.findViewById(
com.android.internal.R.id.expand_button);
expandButton.setVisibility(VISIBLE);
mNotificationHeader.setOnClickListener(listener);
mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
mNotificationHeader, mNotificationParent);
addView(mNotificationHeader, 0);
invalidate();
} else {
header.reapply(getContext(), mNotificationHeader);
mNotificationHeaderWrapper.notifyContentUpdated(notification);
}
updateChildrenHeaderAppearance();
}
public void updateChildrenHeaderAppearance() {
mHeaderUtil.updateChildrenHeaderAppearance();
}
public void updateGroupOverflow() {
@@ -210,7 +269,7 @@ public class NotificationChildrenContainer extends ViewGroup {
mOverflowNumber = mHybridGroupManager.bindOverflowNumber(
mOverflowNumber, childCount - maxAllowedVisibleChildren);
if (mOverflowInvertHelper == null) {
mOverflowInvertHelper= new ViewInvertHelper(mOverflowNumber,
mOverflowInvertHelper = new ViewInvertHelper(mOverflowNumber,
NotificationPanelView.DOZE_ANIMATION_DURATION);
}
if (mGroupOverFlowState == null) {
@@ -300,7 +359,7 @@ public class NotificationChildrenContainer extends ViewGroup {
* in @param maxAllowedVisibleChildren
*/
private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
int intrinsicHeight = mNotificationHeaderHeight;
int intrinsicHeight = mNotificationHeaderMargin;
int visibleChildren = 0;
int childCount = mChildren.size();
boolean firstChild = true;
@@ -353,7 +412,7 @@ public class NotificationChildrenContainer extends ViewGroup {
*/
public void getState(StackScrollState resultState, StackViewState parentState) {
int childCount = mChildren.size();
int yPosition = mNotificationHeaderHeight;
int yPosition = mNotificationHeaderMargin;
boolean firstChild = true;
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
int lastVisibleIndex = maxAllowedVisibleChildren - 1;
@@ -363,12 +422,16 @@ public class NotificationChildrenContainer extends ViewGroup {
expandFactor = getGroupExpandFraction();
firstOverflowIndex = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
}
boolean childrenExpanded = !mNotificationParent.isGroupExpansionChanging()
&& mChildrenExpanded;
int parentHeight = parentState.height;
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
if (!firstChild) {
if (mUserLocked) {
yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
expandFactor);
yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
expandFactor);
} else {
yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
}
@@ -383,11 +446,28 @@ public class NotificationChildrenContainer extends ViewGroup {
}
firstChild = false;
}
StackViewState childState = resultState.getViewStateForView(child);
int intrinsicHeight = child.getIntrinsicHeight();
if (childrenExpanded) {
// When a group is expanded and moving into bottom stack, the bottom visible child
// adjusts its height to move into it. Children after it are hidden.
if (updateChildStateForExpandedGroup(child, parentHeight, childState, yPosition)) {
// Clipping might be deactivated if the view is transforming, however, clipping
// the child into the bottom stack should take precedent over this.
childState.isBottomClipped = true;
}
} else {
childState.hidden = false;
childState.height = intrinsicHeight;
childState.isBottomClipped = false;
}
childState.yTranslation = yPosition;
childState.zTranslation = 0;
childState.height = intrinsicHeight;
// When the group is expanded, the children cast the shadows rather than the parent
// so use the parent's elevation here.
childState.zTranslation = childrenExpanded
? mNotificationParent.getTranslationZ()
: 0;
childState.dimmed = parentState.dimmed;
childState.dark = parentState.dark;
childState.hideSensitive = parentState.hideSensitive;
@@ -422,10 +502,44 @@ public class NotificationChildrenContainer extends ViewGroup {
mGroupOverFlowState.alpha = mirrorView.getAlpha();
}
} else {
mGroupOverFlowState.yTranslation += mNotificationHeaderHeight;
mGroupOverFlowState.yTranslation += mNotificationHeaderMargin;
mGroupOverFlowState.alpha = 0.0f;
}
}
if (mNotificationHeader != null) {
if (mHeaderViewState == null) {
mHeaderViewState = new ViewState();
}
mHeaderViewState.initFrom(mNotificationHeader);
mHeaderViewState.zTranslation = childrenExpanded
? mNotificationParent.getTranslationZ()
: 0;
}
}
/**
* When moving into the bottom stack, the bottom visible child in an expanded group adjusts its
* height, children in the group after this are gone.
*
* @param child the child who's height to adjust.
* @param parentHeight the height of the parent.
* @param childState the state to update.
* @param yPosition the yPosition of the view.
* @return true if children after this one should be hidden.
*/
private boolean updateChildStateForExpandedGroup(ExpandableNotificationRow child,
int parentHeight, StackViewState childState, int yPosition) {
final int top = yPosition + child.getClipTopAmount();
final int intrinsicHeight = child.getIntrinsicHeight();
final int bottom = top + intrinsicHeight;
int newHeight = intrinsicHeight;
if (bottom >= parentHeight) {
// Child is either clipped or gone
newHeight = Math.max((parentHeight - top), 0);
}
childState.hidden = newHeight == 0;
childState.height = newHeight;
return childState.height != intrinsicHeight && !childState.hidden;
}
private int getMaxAllowedVisibleChildren() {
@@ -450,6 +564,8 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mUserLocked) {
expandFraction = getGroupExpandFraction();
}
final boolean dividersVisible = mUserLocked
|| mNotificationParent.isGroupExpansionChanging();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
@@ -464,6 +580,7 @@ public class NotificationChildrenContainer extends ViewGroup {
alpha = NotificationUtils.interpolate(0, 0.5f,
Math.min(viewState.alpha, expandFraction));
}
tmpState.hidden = !dividersVisible;
tmpState.alpha = alpha;
state.applyViewState(divider, tmpState);
// There is no fake shadow to be drawn on the children
@@ -473,6 +590,9 @@ public class NotificationChildrenContainer extends ViewGroup {
state.applyViewState(mOverflowNumber, mGroupOverFlowState);
mNeverAppliedGroupState = false;
}
if (mNotificationHeader != null) {
state.applyViewState(mNotificationHeader, mHeaderViewState);
}
}
/**
@@ -491,6 +611,8 @@ public class NotificationChildrenContainer extends ViewGroup {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
float expandFraction = getGroupExpandFraction();
final boolean dividersVisible = mUserLocked
|| mNotificationParent.isGroupExpansionChanging();
for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
@@ -505,6 +627,7 @@ public class NotificationChildrenContainer extends ViewGroup {
alpha = NotificationUtils.interpolate(0, 0.5f,
Math.min(viewState.alpha, expandFraction));
}
tmpState.hidden = !dividersVisible;
tmpState.alpha = alpha;
stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
// There is no fake shadow to be drawn on the children
@@ -521,6 +644,9 @@ public class NotificationChildrenContainer extends ViewGroup {
stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState,
baseDelay, duration);
}
if (mNotificationHeader != null) {
state.applyViewState(mNotificationHeader, mHeaderViewState);
}
}
public ExpandableNotificationRow getViewAtPosition(float y) {
@@ -541,14 +667,45 @@ public class NotificationChildrenContainer extends ViewGroup {
public void setChildrenExpanded(boolean childrenExpanded) {
mChildrenExpanded = childrenExpanded;
updateExpansionStates();
if (mNotificationHeader != null) {
mNotificationHeader.setExpanded(childrenExpanded);
}
}
public void setNotificationParent(ExpandableNotificationRow parent) {
mNotificationParent = parent;
mHeaderUtil = new NotificationHeaderUtil(mNotificationParent);
}
public NotificationHeaderView getHeaderView() {
return mNotificationHeader;
}
public void updateHeaderVisibility(int visiblity) {
if (mNotificationHeader != null) {
mNotificationHeader.setVisibility(visiblity);
}
}
/**
* Called when a groups expansion changes to adjust the background of the header view.
*
* @param expanded whether the group is expanded.
*/
public void updateHeaderForExpansion(boolean expanded) {
if (mNotificationHeader != null) {
if (expanded) {
ColorDrawable cd = new ColorDrawable();
cd.setColor(mNotificationParent.calculateBgColor());
mNotificationHeader.setHeaderBackgroundDrawable(cd);
} else {
mNotificationHeader.setHeaderBackgroundDrawable(null);
}
}
}
public int getMaxContentHeight() {
int maxContentHeight = mNotificationHeaderHeight + mNotificatonTopPadding;
int maxContentHeight = mNotificationHeaderMargin + mNotificatonTopPadding;
int visibleChildren = 0;
int childCount = mChildren.size();
for (int i = 0; i < childCount; i++) {
@@ -601,7 +758,7 @@ public class NotificationChildrenContainer extends ViewGroup {
}
private int getVisibleChildrenExpandHeight() {
int intrinsicHeight = mNotificationHeaderHeight + mNotificatonTopPadding + mDividerHeight;
int intrinsicHeight = mNotificationHeaderMargin + mNotificatonTopPadding + mDividerHeight;
int visibleChildren = 0;
int childCount = mChildren.size();
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
@@ -628,7 +785,7 @@ public class NotificationChildrenContainer extends ViewGroup {
}
private int getMinHeight(int maxAllowedVisibleChildren) {
int minExpandHeight = mNotificationHeaderHeight;
int minExpandHeight = mNotificationHeaderMargin;
int visibleChildren = 0;
boolean firstChild = true;
int childCount = mChildren.size();
@@ -653,9 +810,13 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mOverflowNumber != null) {
mOverflowInvertHelper.setInverted(dark, fade, delay);
}
mNotificationHeaderWrapper.setDark(dark, fade, delay);
}
public void reInflateViews() {
public void reInflateViews(OnClickListener listener, StatusBarNotification notification) {
removeView(mNotificationHeader);
mNotificationHeader = null;
recreateNotificationHeader(listener, notification);
initDimens();
for (int i = 0; i < mDividers.size(); i++) {
View prevDivider = mDividers.get(i);

View File

@@ -733,6 +733,7 @@ public class NotificationStackScrollLayout extends ViewGroup
mQsContainer = qsContainer;
}
@Override
public void onChildDismissed(View v) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
if (!row.isDismissed()) {
@@ -820,6 +821,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return true; // Don't fade out the notification
}
@Override
public void onBeginDrag(View v) {
mFalsingManager.onNotificatonStartDismissing();
setSwipingInProgress(true);
@@ -848,6 +850,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return false;
}
@Override
public void onDragCancelled(View v) {
mFalsingManager.onNotificatonStopDismissing();
setSwipingInProgress(false);
@@ -906,11 +909,13 @@ public class NotificationStackScrollLayout extends ViewGroup
return closestChild;
}
@Override
public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
getLocationOnScreen(mTempInt2);
return getChildAtPosition(touchX - mTempInt2[0], touchY - mTempInt2[1]);
}
@Override
public ExpandableView getChildAtPosition(float touchX, float touchY) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
@@ -947,12 +952,14 @@ public class NotificationStackScrollLayout extends ViewGroup
return null;
}
@Override
public boolean canChildBeExpanded(View v) {
return v instanceof ExpandableNotificationRow
&& ((ExpandableNotificationRow) v).isExpandable()
&& (mIsExpanded || !((ExpandableNotificationRow) v).isPinned());
}
@Override
public void setUserExpandedChild(View v, boolean userExpanded) {
if (v instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) v).setUserExpanded(userExpanded,
@@ -960,6 +967,14 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
@Override
public void setExpansionCancelled(View v) {
if (v instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) v).setGroupExpansionChanging(false);
}
}
@Override
public void setUserLockedChild(View v, boolean userLocked) {
if (v instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) v).setUserLocked(userLocked);
@@ -1070,6 +1085,7 @@ public class NotificationStackScrollLayout extends ViewGroup
return mScrollingEnabled;
}
@Override
public boolean canChildBeDismissed(View v) {
return StackScrollAlgorithm.canChildBeDismissed(v);
}
@@ -1927,7 +1943,8 @@ public class NotificationStackScrollLayout extends ViewGroup
// we're ending up at the same location as we are now, lets just skip the animation
bottom = finalBottom;
} else {
bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight());
bottom = (int) (lastView.getTranslationY() + lastView.getActualHeight()
- lastView.getExtraBottomPadding());
bottom = Math.min(bottom, getHeight());
}
} else {
@@ -3153,8 +3170,9 @@ public class NotificationStackScrollLayout extends ViewGroup
expandableView.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
} else {
float yLocation = previous.getTranslationY() + previous.getActualHeight() -
expandableView.getTranslationY();
expandableView.setFakeShadowIntensity(diff / FakeShadowView.SHADOW_SIBLING_TRESHOLD,
expandableView.getTranslationY() - previous.getExtraBottomPadding();
expandableView.setFakeShadowIntensity(
diff / FakeShadowView.SHADOW_SIBLING_TRESHOLD,
previous.getOutlineAlpha(), (int) yLocation,
previous.getOutlineTranslation());
}
@@ -3525,6 +3543,12 @@ public class NotificationStackScrollLayout extends ViewGroup
if (!mGroupExpandedForMeasure) {
onHeightChanged(changedRow, false /* needsAnimation */);
}
runAfterAnimationFinished(new Runnable() {
@Override
public void run() {
changedRow.onFinishedExpansionChange();
}
});
}
@Override

View File

@@ -173,6 +173,9 @@ public class StackScrollState {
}
if (view instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) view;
if (state.isBottomClipped) {
row.setClipToActualHeight(true);
}
row.applyChildrenState(this);
}
return true;

View File

@@ -223,7 +223,7 @@ public class StackStateAnimator {
startViewAnimations(child, viewState, delay, duration);
// start height animation
if (heightChanging && child.getActualHeight() != 0) {
if (heightChanging) {
startHeightAnimation(child, viewState, duration, delay);
}
@@ -270,7 +270,8 @@ public class StackStateAnimator {
public void startViewAnimations(View child, ViewState viewState, long delay, long duration) {
boolean wasVisible = child.getVisibility() == View.VISIBLE;
final float alpha = viewState.alpha;
if (!wasVisible && alpha != 0 && !viewState.gone && !viewState.hidden) {
if (!wasVisible && (alpha != 0 || child.getAlpha() != 0)
&& !viewState.gone && !viewState.hidden) {
child.setVisibility(View.VISIBLE);
}
boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
@@ -477,11 +478,27 @@ public class StackStateAnimator {
animator.addListener(getGlobalAnimationFinishedListener());
// remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() {
boolean mWasCancelled;
@Override
public void onAnimationEnd(Animator animation) {
child.setTag(TAG_ANIMATOR_HEIGHT, null);
child.setTag(TAG_START_HEIGHT, null);
child.setTag(TAG_END_HEIGHT, null);
if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
((ExpandableNotificationRow) child).setGroupExpansionChanging(
false /* isExpansionChanging */);
}
}
@Override
public void onAnimationStart(Animator animation) {
mWasCancelled = false;
}
@Override
public void onAnimationCancel(Animator animation) {
mWasCancelled = true;
}
});
startAnimator(animator);

View File

@@ -57,6 +57,11 @@ public class StackViewState extends ViewState {
*/
public int location;
/**
* Whether a child in a group is being clipped at the bottom.
*/
public boolean isBottomClipped;
@Override
public void copyFrom(ViewState viewState) {
super.copyFrom(viewState);
@@ -71,6 +76,7 @@ public class StackViewState extends ViewState {
clipTopAmount = svs.clipTopAmount;
notGoneIndex = svs.notGoneIndex;
location = svs.location;
isBottomClipped = svs.isBottomClipped;
}
}
}