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.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RemoteViews; import android.widget.RemoteViews;
@@ -47,6 +51,18 @@ public class NotificationHeaderView extends ViewGroup {
private int mOriginalNotificationColor; private int mOriginalNotificationColor;
private boolean mExpanded; private boolean mExpanded;
private boolean mShowWorkBadgeAtEnd; 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) { public NotificationHeaderView(Context context) {
this(context, null); this(context, null);
@@ -66,6 +82,8 @@ public class NotificationHeaderView extends ViewGroup {
com.android.internal.R.dimen.notification_header_shrink_min_width); com.android.internal.R.dimen.notification_header_shrink_min_width);
mContentEndMargin = getResources().getDimensionPixelSize( mContentEndMargin = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_end); com.android.internal.R.dimen.notification_content_margin_end);
mHeaderBackgroundHeight = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_header_background_height);
} }
@Override @Override
@@ -165,6 +183,43 @@ public class NotificationHeaderView extends ViewGroup {
return new ViewGroup.MarginLayoutParams(getContext(), attrs); 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() { private void updateTouchListener() {
if (mExpandClickListener != null) { if (mExpandClickListener != null) {
mTouchListener.bindTouchRects(); mTouchListener.bindTouchRects();

View File

@@ -163,6 +163,9 @@
<!-- height of the content margin on the bottom --> <!-- height of the content margin on the bottom -->
<dimen name="notification_content_margin_bottom">16dp</dimen> <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 --> <!-- Height of a small notification in the status bar -->
<dimen name="notification_min_height">92dp</dimen> <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_picture_margin" />
<java-symbol type="dimen" name="notification_content_margin_top" /> <java-symbol type="dimen" name="notification_content_margin_top" />
<java-symbol type="dimen" name="notification_content_margin_bottom" /> <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_user" />
<java-symbol type="string" name="importance_from_person" /> <java-symbol type="string" name="importance_from_person" />

View File

@@ -20,4 +20,4 @@
android:id="@+id/notification_more_divider" android:id="@+id/notification_more_divider"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/notification_divider_height" 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. --> <!-- The height of the divider between the individual notifications. -->
<dimen name="notification_divider_height">0.5dp</dimen> <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 --> <!-- 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> <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 setUserLockedChild(View v, boolean userLocked);
void expansionStateChanged(boolean isExpanding); void expansionStateChanged(boolean isExpanding);
int getMaxExpandHeight(ExpandableView view); int getMaxExpandHeight(ExpandableView view);
void setExpansionCancelled(View view);
} }
private static final String TAG = "ExpandHelper"; private static final String TAG = "ExpandHelper";
@@ -558,6 +559,8 @@ public class ExpandHelper implements Gefingerpoken {
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
if (!mCancelled) { if (!mCancelled) {
mCallback.setUserExpandedChild(scaledView, expand); mCallback.setUserExpandedChild(scaledView, expand);
} else {
mCallback.setExpansionCancelled(scaledView);
} }
mCallback.setUserLockedChild(scaledView, false); mCallback.setUserLockedChild(scaledView, false);
mScaleAnimation.removeListener(this); mScaleAnimation.removeListener(this);

View File

@@ -22,7 +22,6 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator; import android.animation.ObjectAnimator;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener; import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.app.Notification;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.AnimationDrawable; import android.graphics.drawable.AnimationDrawable;
@@ -31,6 +30,8 @@ import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.service.notification.StatusBarNotification; import android.service.notification.StatusBarNotification;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.Property;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.NotificationHeaderView; import android.view.NotificationHeaderView;
@@ -39,13 +40,11 @@ import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityEvent;
import android.widget.Chronometer; import android.widget.Chronometer;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.RemoteViews;
import com.android.internal.util.NotificationColorUtil; import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager; import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.statusbar.notification.HybridNotificationView; 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.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.stack.NotificationChildrenContainer; import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
@@ -65,6 +64,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private int mMaxHeadsUpHeight; private int mMaxHeadsUpHeight;
private int mNotificationMinHeight; private int mNotificationMinHeight;
private int mNotificationMaxHeight; private int mNotificationMaxHeight;
private int mIncreasedPaddingBetweenElements;
/** Does this row contain layouts that can adapt to row expansion */ /** Does this row contain layouts that can adapt to row expansion */
private boolean mExpandable; private boolean mExpandable;
@@ -97,7 +97,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
*/ */
private boolean mOnKeyguard; private boolean mOnKeyguard;
private AnimatorSet mTranslateAnim; private Animator mTranslateAnim;
private ArrayList<View> mTranslateableViews; private ArrayList<View> mTranslateableViews;
private NotificationContentView mPublicLayout; private NotificationContentView mPublicLayout;
private NotificationContentView mPrivateLayout; private NotificationContentView mPrivateLayout;
@@ -115,8 +115,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private String mAppName; private String mAppName;
private boolean mIsHeadsUp; private boolean mIsHeadsUp;
private boolean mLastChronometerRunning = true; private boolean mLastChronometerRunning = true;
private NotificationHeaderView mNotificationHeader;
private NotificationViewWrapper mNotificationHeaderWrapper;
private ViewStub mChildrenContainerStub; private ViewStub mChildrenContainerStub;
private NotificationGroupManager mGroupManager; private NotificationGroupManager mGroupManager;
private boolean mChildrenExpanded; private boolean mChildrenExpanded;
@@ -128,13 +126,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mIsPinned; private boolean mIsPinned;
private FalsingManager mFalsingManager; private FalsingManager mFalsingManager;
private HeadsUpManager mHeadsUpManager; private HeadsUpManager mHeadsUpManager;
private NotificationHeaderUtil mHeaderUtil = new NotificationHeaderUtil(this);
private boolean mJustClicked; private boolean mJustClicked;
private boolean mIconAnimationRunning; private boolean mIconAnimationRunning;
private boolean mShowNoBackground; private boolean mShowNoBackground;
private ExpandableNotificationRow mNotificationParent; private ExpandableNotificationRow mNotificationParent;
private OnExpandClickListener mOnExpandClickListener; private OnExpandClickListener mOnExpandClickListener;
private boolean mGroupExpansionChanging;
private OnClickListener mExpandClickListener = new OnClickListener() { private OnClickListener mExpandClickListener = new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
@@ -142,6 +141,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mGroupManager.toggleGroupExpansion(mStatusBarNotification); mGroupManager.toggleGroupExpansion(mStatusBarNotification);
mOnExpandClickListener.onExpandClicked(mEntry, mOnExpandClickListener.onExpandClicked(mEntry,
mGroupManager.isGroupExpanded(mStatusBarNotification)); mGroupManager.isGroupExpanded(mStatusBarNotification));
mGroupExpansionChanging = true;
updateBackgroundForGroupState();
} else { } else {
boolean nowExpanded; boolean nowExpanded;
if (isPinned()) { if (isPinned()) {
@@ -160,6 +161,29 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
private boolean mDismissed; private boolean mDismissed;
private boolean mKeepInParent; private boolean mKeepInParent;
private boolean mRemoved; 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() { public NotificationContentView getPrivateLayout() {
return mPrivateLayout; return mPrivateLayout;
@@ -172,8 +196,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setIconAnimationRunning(boolean running) { public void setIconAnimationRunning(boolean running) {
setIconAnimationRunning(running, mPublicLayout); setIconAnimationRunning(running, mPublicLayout);
setIconAnimationRunning(running, mPrivateLayout); setIconAnimationRunning(running, mPrivateLayout);
setIconAnimationRunningForChild(running, mNotificationHeader);
if (mIsSummaryWithChildren) { if (mIsSummaryWithChildren) {
setIconAnimationRunningForChild(running, mChildrenContainer.getHeaderView());
List<ExpandableNotificationRow> notificationChildren = List<ExpandableNotificationRow> notificationChildren =
mChildrenContainer.getNotificationChildren(); mChildrenContainer.getNotificationChildren();
for (int i = 0; i < notificationChildren.size(); i++) { for (int i = 0; i < notificationChildren.size(); i++) {
@@ -235,7 +259,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
updateNotificationColor(); updateNotificationColor();
updateClearability(); updateClearability();
if (mIsSummaryWithChildren) { if (mIsSummaryWithChildren) {
recreateNotificationHeader(); mChildrenContainer.recreateNotificationHeader(mExpandClickListener, mEntry.notification);
mChildrenContainer.onNotificationUpdated(); mChildrenContainer.onNotificationUpdated();
} }
if (mIconAnimationRunning) { if (mIconAnimationRunning) {
@@ -329,9 +353,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (mChildrenContainer != null) { if (mChildrenContainer != null) {
mChildrenContainer.removeNotification(row); mChildrenContainer.removeNotification(row);
} }
if (!row.isRemoved()) {
mHeaderUtil.restoreNotificationHeader(row);
}
onChildrenCountChanged(); onChildrenCountChanged();
row.setIsChildInGroup(false, null); row.setIsChildInGroup(false, null);
} }
@@ -352,7 +373,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup; boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
mNotificationParent = childInGroup ? parent : null; mNotificationParent = childInGroup ? parent : null;
mPrivateLayout.setIsChildInGroup(childInGroup); mPrivateLayout.setIsChildInGroup(childInGroup);
updateNoBackgroundState(); updateBackgroundForGroupState();
if (mNotificationParent != null) {
mNotificationParent.updateBackgroundForGroupState();
}
} }
@Override @Override
@@ -544,15 +568,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
} }
public NotificationHeaderView getNotificationHeader() { public NotificationHeaderView getNotificationHeader() {
if (mNotificationHeader != null) { if (mIsSummaryWithChildren) {
return mNotificationHeader; return mChildrenContainer.getHeaderView();
} }
return mPrivateLayout.getNotificationHeader(); return mPrivateLayout.getNotificationHeader();
} }
private NotificationHeaderView getVisibleNotificationHeader() { private NotificationHeaderView getVisibleNotificationHeader() {
if (mNotificationHeader != null) { if (mIsSummaryWithChildren) {
return mNotificationHeader; return mChildrenContainer.getHeaderView();
} }
return getShowingLayout().getVisibleNotificationHeader(); return getShowingLayout().getVisibleNotificationHeader();
} }
@@ -568,11 +592,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void reInflateViews() { public void reInflateViews() {
initDimens(); initDimens();
if (mIsSummaryWithChildren) { if (mIsSummaryWithChildren) {
removeView(mNotificationHeader);
mNotificationHeader = null;
recreateNotificationHeader();
if (mChildrenContainer != null) { if (mChildrenContainer != null) {
mChildrenContainer.reInflateViews(); mChildrenContainer.reInflateViews(mExpandClickListener, mEntry.notification);
} }
} }
if (mGuts != null) { if (mGuts != null) {
@@ -646,9 +667,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
continue; continue;
} }
mChildrenContainer.removeNotification(row); mChildrenContainer.removeNotification(row);
if (!row.isRemoved()) {
mHeaderUtil.restoreNotificationHeader(row);
}
row.setIsChildInGroup(false, null); row.setIsChildInGroup(false, null);
} }
onChildrenCountChanged(); onChildrenCountChanged();
@@ -709,6 +727,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mMaxHeadsUpHeightLegacy = getFontScaledHeight( mMaxHeadsUpHeightLegacy = getFontScaledHeight(
R.dimen.notification_max_heads_up_height_legacy); R.dimen.notification_max_heads_up_height_legacy);
mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height); 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); mTranslateableViews.remove(mGutsStub);
} }
private void setTranslationForOutline(float translationX) {
setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
}
public void resetTranslation() { public void resetTranslation() {
if (mTranslateableViews != null) { if (mTranslateableViews != null) {
for (int i = 0; i < mTranslateableViews.size(); i++) { for (int i = 0; i < mTranslateableViews.size(); i++) {
mTranslateableViews.get(i).setTranslationX(0); mTranslateableViews.get(i).setTranslationX(0);
} }
setTranslationForOutline(0);
} }
invalidateOutline();
if (mSettingsIconRow != null) { if (mSettingsIconRow != null) {
mSettingsIconRow.resetState(); mSettingsIconRow.resetState();
} }
@@ -824,8 +840,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (mTranslateAnim != null) { if (mTranslateAnim != null) {
mTranslateAnim.cancel(); mTranslateAnim.cancel();
} }
mTranslateAnim = (AnimatorSet) getTranslateViewAnimator(leftTarget, mTranslateAnim = getTranslateViewAnimator(leftTarget, null /* updateListener */);
null /* updateListener */);
if (mTranslateAnim != null) { if (mTranslateAnim != null) {
mTranslateAnim.start(); mTranslateAnim.start();
} }
@@ -843,7 +858,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mTranslateableViews.get(i).setTranslationX(translationX); mTranslateableViews.get(i).setTranslationX(translationX);
} }
} }
setTranslationForOutline(translationX); invalidateOutline();
if (mSettingsIconRow != null) { if (mSettingsIconRow != null) {
mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth()); mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
} }
@@ -867,23 +882,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
// No translation if guts are exposed. // No translation if guts are exposed.
return null; return null;
} }
AnimatorSet set = new AnimatorSet(); final ObjectAnimator translateAnim = ObjectAnimator.ofFloat(this, TRANSLATE_CONTENT,
if (mTranslateableViews != null) { leftTarget);
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) { if (listener != null) {
translateAnim.addUpdateListener(listener); translateAnim.addUpdateListener(listener);
} }
@@ -903,12 +903,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
} }
} }
}); });
} mTranslateAnim = translateAnim;
set.play(translateAnim); return translateAnim;
}
}
mTranslateAnim = set;
return set;
} }
public float getSpaceForGear() { public float getSpaceForGear() {
@@ -937,9 +933,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
if (mChildrenContainer != null) { if (mChildrenContainer != null) {
mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE mChildrenContainer.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
: INVISIBLE); : INVISIBLE);
} mChildrenContainer.updateHeaderVisibility(!mShowingPublic && mIsSummaryWithChildren
if (mNotificationHeader != null) { ? VISIBLE
mNotificationHeader.setVisibility(!mShowingPublic && mIsSummaryWithChildren ? VISIBLE
: INVISIBLE); : INVISIBLE);
} }
// The limits might have changed if the view suddenly became a group or vice versa // 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) { if (mIsSummaryWithChildren) {
mChildrenContainer.setDark(dark, fade, delay); mChildrenContainer.setDark(dark, fade, delay);
mNotificationHeaderWrapper.setDark(dark, fade, delay);
} }
} }
@@ -1044,6 +1038,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
mPrivateLayout.setUserExpanding(userLocked); mPrivateLayout.setUserExpanding(userLocked);
if (mIsSummaryWithChildren) { if (mIsSummaryWithChildren) {
mChildrenContainer.setUserLocked(userLocked); 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 mGroupManager.isGroupExpanded(mStatusBarNotification);
} }
/**
* @return whether this view has a header on the top of the content
*/
private boolean hasNotificationHeader() {
return mIsSummaryWithChildren;
}
private void onChildrenCountChanged() { private void onChildrenCountChanged() {
mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS mIsSummaryWithChildren = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
&& mChildrenContainer != null && mChildrenContainer.getChildCount() > 0; && mChildrenContainer != null && mChildrenContainer.getNotificationChildCount() > 0;
if (mIsSummaryWithChildren) { if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() == null) {
if (mNotificationHeader == null) { mChildrenContainer.recreateNotificationHeader(mExpandClickListener,
recreateNotificationHeader(); mEntry.notification);
}
} }
mPrivateLayout.updateExpandButtons(isExpandable()); mPrivateLayout.updateExpandButtons(isExpandable());
updateChildrenHeaderAppearance(); updateChildrenHeaderAppearance();
updateChildrenVisibility(); 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 * 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 * #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) { private void animateShowingPublic(long delay, long duration) {
View[] privateViews = mIsSummaryWithChildren ? View[] privateViews = mIsSummaryWithChildren
new View[] {mChildrenContainer, mNotificationHeader} ? new View[] {mChildrenContainer}
: new View[] {mPrivateLayout}; : new View[] {mPrivateLayout};
View[] publicViews = new View[] {mPublicLayout}; View[] publicViews = new View[] {mPublicLayout};
View[] hiddenChildren = mShowingPublic ? privateViews : publicViews; View[] hiddenChildren = mShowingPublic ? privateViews : publicViews;
@@ -1302,9 +1297,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
public void setChildrenExpanded(boolean expanded, boolean animate) { public void setChildrenExpanded(boolean expanded, boolean animate) {
mChildrenExpanded = expanded; mChildrenExpanded = expanded;
if (mNotificationHeader != null) {
mNotificationHeader.setExpanded(expanded);
}
if (mChildrenContainer != null) { if (mChildrenContainer != null) {
mChildrenContainer.setChildrenExpanded(expanded); mChildrenContainer.setChildrenExpanded(expanded);
} }
@@ -1348,6 +1340,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
return getShowingLayout(); return getShowingLayout();
} }
@Override
public int getExtraBottomPadding() {
if (mIsSummaryWithChildren && isGroupExpanded()) {
return mIncreasedPaddingBetweenElements;
}
return 0;
}
@Override @Override
public void setActualHeight(int height, boolean notifyListeners) { public void setActualHeight(int height, boolean notifyListeners) {
super.setActualHeight(height, 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() { public boolean isMaxExpandHeightInitialized() {
return mMaxExpandHeight != 0; return mMaxExpandHeight != 0;
} }
@@ -1451,19 +1424,50 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
@Override @Override
protected void updateBackgroundTint() { protected void updateBackgroundTint() {
super.updateBackgroundTint(); super.updateBackgroundTint();
updateNoBackgroundState(); updateBackgroundForGroupState();
if (mIsSummaryWithChildren) { if (mIsSummaryWithChildren) {
List<ExpandableNotificationRow> notificationChildren = List<ExpandableNotificationRow> notificationChildren =
mChildrenContainer.getNotificationChildren(); mChildrenContainer.getNotificationChildren();
for (int i = 0; i < notificationChildren.size(); i++) { for (int i = 0; i < notificationChildren.size(); i++) {
ExpandableNotificationRow child = notificationChildren.get(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(); updateBackground();
} }

View File

@@ -33,22 +33,25 @@ public abstract class ExpandableOutlineView extends ExpandableView {
private boolean mCustomOutline; private boolean mCustomOutline;
private float mOutlineAlpha = -1f; private float mOutlineAlpha = -1f;
public ExpandableOutlineView(Context context, AttributeSet attrs) { ViewOutlineProvider mProvider = new ViewOutlineProvider() {
super(context, attrs);
setOutlineProvider(new ViewOutlineProvider() {
@Override @Override
public void getOutline(View view, Outline outline) { public void getOutline(View view, Outline outline) {
int translation = (int) getTranslation();
if (!mCustomOutline) { if (!mCustomOutline) {
outline.setRect(0, outline.setRect(translation,
mClipTopAmount, mClipTopAmount,
getWidth(), getWidth() + translation,
Math.max(getActualHeight(), mClipTopAmount)); Math.max(getActualHeight(), mClipTopAmount));
} else { } else {
outline.setRect(mOutlineRect); outline.setRect(mOutlineRect);
} }
outline.setAlpha(mOutlineAlpha); outline.setAlpha(mOutlineAlpha);
} }
}); };
public ExpandableOutlineView(Context context, AttributeSet attrs) {
super(context, attrs);
setOutlineProvider(mProvider);
} }
@Override @Override
@@ -87,17 +90,30 @@ public abstract class ExpandableOutlineView extends ExpandableView {
@Override @Override
public int getOutlineTranslation() { 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) { 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; mCustomOutline = true;
setClipToOutline(clipToOutline); setClipToOutline(true);
mOutlineRect.set((int) left, (int) top, (int) right, (int) bottom); 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()) { if (top >= getActualHeight()) {
top = getActualHeight() - 1; top = getActualHeight() - 1;
} }
mClipRect.set(0, top, getWidth(), getActualHeight()); mClipRect.set(0, top, getWidth(), getActualHeight() + getExtraBottomPadding());
setClipBounds(mClipRect); setClipBounds(mClipRect);
} else { } else {
setClipBounds(null); setClipBounds(null);
@@ -410,6 +410,28 @@ public abstract class ExpandableView extends FrameLayout {
return mTransientContainer; 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. * A listener notifying when {@link #getActualHeight} changes.
*/ */

View File

@@ -71,7 +71,6 @@ public class NotificationContentView extends FrameLayout {
private HybridGroupManager mHybridGroupManager; private HybridGroupManager mHybridGroupManager;
private int mClipTopAmount; private int mClipTopAmount;
private int mContentHeight; private int mContentHeight;
private int mUnrestrictedContentHeight;
private int mVisibleType = VISIBLE_TYPE_CONTRACTED; private int mVisibleType = VISIBLE_TYPE_CONTRACTED;
private boolean mDark; private boolean mDark;
private boolean mAnimate; private boolean mAnimate;
@@ -371,8 +370,7 @@ public class NotificationContentView extends FrameLayout {
} }
public void setContentHeight(int contentHeight) { public void setContentHeight(int contentHeight) {
mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());; mContentHeight = Math.max(Math.min(contentHeight, getHeight()), getMinHeight());
mUnrestrictedContentHeight = Math.max(contentHeight, getMinHeight());
selectLayout(mAnimate /* animate */, false /* force */); selectLayout(mAnimate /* animate */, false /* force */);
int minHeightHint = getMinContentHeightHint(); int minHeightHint = getMinContentHeightHint();
@@ -591,7 +589,21 @@ public class NotificationContentView extends FrameLayout {
mContainingNotification.setContentBackground(customBackgroundColor, animate, this); 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); NotificationViewWrapper currentVisibleWrapper = getVisibleWrapper(visibleType);
int customBackgroundColor = 0; int customBackgroundColor = 0;
if (currentVisibleWrapper != null) { 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 * @return one of the static enum types in this view, calculated form the current state
*/ */
private int calculateVisibleType() { public int calculateVisibleType() {
if (mUserExpanding) { if (mUserExpanding) {
int height = !mIsChildInGroup || isGroupExpanded() int height = !mIsChildInGroup || isGroupExpanded()
|| mContainingNotification.isExpanded(true /* allowOnKeyguard */) || mContainingNotification.isExpanded(true /* allowOnKeyguard */)

View File

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

View File

@@ -4335,6 +4335,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
if (expandView instanceof ExpandableNotificationRow) { if (expandView instanceof ExpandableNotificationRow) {
row = (ExpandableNotificationRow) expandView; row = (ExpandableNotificationRow) expandView;
row.setUserExpanded(true /* userExpanded */, true /* allowChildExpansion */); 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) boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
|| !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer(); || !mShowLockscreenNotifications || mFalsingManager.shouldEnforceBouncer();

View File

@@ -16,21 +16,28 @@
package com.android.systemui.statusbar.stack; package com.android.systemui.statusbar.stack;
import android.app.Notification;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.graphics.drawable.ColorDrawable;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.NotificationHeaderView;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.RemoteViews;
import android.widget.TextView; import android.widget.TextView;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper; import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow; 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.HybridGroupManager;
import com.android.systemui.statusbar.notification.HybridNotificationView; import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationPanelView; import com.android.systemui.statusbar.phone.NotificationPanelView;
import java.util.ArrayList; import java.util.ArrayList;
@@ -51,7 +58,7 @@ public class NotificationChildrenContainer extends ViewGroup {
private int mChildPadding; private int mChildPadding;
private int mDividerHeight; private int mDividerHeight;
private int mMaxNotificationHeight; private int mMaxNotificationHeight;
private int mNotificationHeaderHeight; private int mNotificationHeaderMargin;
private int mNotificatonTopPadding; private int mNotificatonTopPadding;
private float mCollapsedBottompadding; private float mCollapsedBottompadding;
private ViewInvertHelper mOverflowInvertHelper; private ViewInvertHelper mOverflowInvertHelper;
@@ -63,6 +70,12 @@ public class NotificationChildrenContainer extends ViewGroup {
private boolean mUserLocked; private boolean mUserLocked;
private int mActualHeight; private int mActualHeight;
private boolean mNeverAppliedGroupState; private boolean mNeverAppliedGroupState;
private int mHeaderHeight;
private NotificationHeaderView mNotificationHeader;
private NotificationViewWrapper mNotificationHeaderWrapper;
private NotificationHeaderUtil mHeaderUtil;
private ViewState mHeaderViewState;
public NotificationChildrenContainer(Context context) { public NotificationChildrenContainer(Context context) {
this(context, null); this(context, null);
@@ -88,9 +101,10 @@ public class NotificationChildrenContainer extends ViewGroup {
R.dimen.notification_children_padding); R.dimen.notification_children_padding);
mDividerHeight = Math.max(1, getResources().getDimensionPixelSize( mDividerHeight = Math.max(1, getResources().getDimensionPixelSize(
R.dimen.notification_divider_height)); R.dimen.notification_divider_height));
mHeaderHeight = getResources().getDimensionPixelSize(R.dimen.notification_header_height);
mMaxNotificationHeight = getResources().getDimensionPixelSize( mMaxNotificationHeight = getResources().getDimensionPixelSize(
R.dimen.notification_max_height); R.dimen.notification_max_height);
mNotificationHeaderHeight = getResources().getDimensionPixelSize( mNotificationHeaderMargin = getResources().getDimensionPixelSize(
com.android.internal.R.dimen.notification_content_margin_top); com.android.internal.R.dimen.notification_content_margin_top);
mNotificatonTopPadding = getResources().getDimensionPixelSize( mNotificatonTopPadding = getResources().getDimensionPixelSize(
R.dimen.notification_children_container_top_padding); R.dimen.notification_children_container_top_padding);
@@ -112,6 +126,10 @@ public class NotificationChildrenContainer extends ViewGroup {
mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(), mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(),
mOverflowNumber.getMeasuredHeight()); mOverflowNumber.getMeasuredHeight());
} }
if (mNotificationHeader != null) {
mNotificationHeader.layout(0, 0, mNotificationHeader.getMeasuredWidth(),
mNotificationHeader.getMeasuredHeight());
}
} }
@Override @Override
@@ -131,7 +149,7 @@ public class NotificationChildrenContainer extends ViewGroup {
newHeightSpec); newHeightSpec);
} }
int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY); 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 childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
int collapsedChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */); int collapsedChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
int overflowIndex = childCount > collapsedChildren ? collapsedChildren - 1 : -1; int overflowIndex = childCount > collapsedChildren ? collapsedChildren - 1 : -1;
@@ -155,6 +173,12 @@ public class NotificationChildrenContainer extends ViewGroup {
if (heightMode != MeasureSpec.UNSPECIFIED) { if (heightMode != MeasureSpec.UNSPECIFIED) {
height = Math.min(height, size); height = Math.min(height, size);
} }
if (mNotificationHeader != null) {
int headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
mNotificationHeader.measure(widthMeasureSpec, headerHeightSpec);
}
setMeasuredDimension(width, height); setMeasuredDimension(width, height);
} }
@@ -201,6 +225,41 @@ public class NotificationChildrenContainer extends ViewGroup {
row.setSystemChildExpanded(false); row.setSystemChildExpanded(false);
row.setUserLocked(false); row.setUserLocked(false);
updateGroupOverflow(); 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() { public void updateGroupOverflow() {
@@ -300,7 +359,7 @@ public class NotificationChildrenContainer extends ViewGroup {
* in @param maxAllowedVisibleChildren * in @param maxAllowedVisibleChildren
*/ */
private int getIntrinsicHeight(float maxAllowedVisibleChildren) { private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
int intrinsicHeight = mNotificationHeaderHeight; int intrinsicHeight = mNotificationHeaderMargin;
int visibleChildren = 0; int visibleChildren = 0;
int childCount = mChildren.size(); int childCount = mChildren.size();
boolean firstChild = true; boolean firstChild = true;
@@ -353,7 +412,7 @@ public class NotificationChildrenContainer extends ViewGroup {
*/ */
public void getState(StackScrollState resultState, StackViewState parentState) { public void getState(StackScrollState resultState, StackViewState parentState) {
int childCount = mChildren.size(); int childCount = mChildren.size();
int yPosition = mNotificationHeaderHeight; int yPosition = mNotificationHeaderMargin;
boolean firstChild = true; boolean firstChild = true;
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(); int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
int lastVisibleIndex = maxAllowedVisibleChildren - 1; int lastVisibleIndex = maxAllowedVisibleChildren - 1;
@@ -363,6 +422,10 @@ public class NotificationChildrenContainer extends ViewGroup {
expandFactor = getGroupExpandFraction(); expandFactor = getGroupExpandFraction();
firstOverflowIndex = getMaxAllowedVisibleChildren(true /* likeCollapsed */); firstOverflowIndex = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
} }
boolean childrenExpanded = !mNotificationParent.isGroupExpansionChanging()
&& mChildrenExpanded;
int parentHeight = parentState.height;
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i); ExpandableNotificationRow child = mChildren.get(i);
if (!firstChild) { if (!firstChild) {
@@ -383,11 +446,28 @@ public class NotificationChildrenContainer extends ViewGroup {
} }
firstChild = false; firstChild = false;
} }
StackViewState childState = resultState.getViewStateForView(child); StackViewState childState = resultState.getViewStateForView(child);
int intrinsicHeight = child.getIntrinsicHeight(); int intrinsicHeight = child.getIntrinsicHeight();
childState.yTranslation = yPosition; if (childrenExpanded) {
childState.zTranslation = 0; // 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.height = intrinsicHeight;
childState.isBottomClipped = false;
}
childState.yTranslation = yPosition;
// 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.dimmed = parentState.dimmed;
childState.dark = parentState.dark; childState.dark = parentState.dark;
childState.hideSensitive = parentState.hideSensitive; childState.hideSensitive = parentState.hideSensitive;
@@ -422,10 +502,44 @@ public class NotificationChildrenContainer extends ViewGroup {
mGroupOverFlowState.alpha = mirrorView.getAlpha(); mGroupOverFlowState.alpha = mirrorView.getAlpha();
} }
} else { } else {
mGroupOverFlowState.yTranslation += mNotificationHeaderHeight; mGroupOverFlowState.yTranslation += mNotificationHeaderMargin;
mGroupOverFlowState.alpha = 0.0f; 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() { private int getMaxAllowedVisibleChildren() {
@@ -450,6 +564,8 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mUserLocked) { if (mUserLocked) {
expandFraction = getGroupExpandFraction(); expandFraction = getGroupExpandFraction();
} }
final boolean dividersVisible = mUserLocked
|| mNotificationParent.isGroupExpansionChanging();
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i); ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child); StackViewState viewState = state.getViewStateForView(child);
@@ -464,6 +580,7 @@ public class NotificationChildrenContainer extends ViewGroup {
alpha = NotificationUtils.interpolate(0, 0.5f, alpha = NotificationUtils.interpolate(0, 0.5f,
Math.min(viewState.alpha, expandFraction)); Math.min(viewState.alpha, expandFraction));
} }
tmpState.hidden = !dividersVisible;
tmpState.alpha = alpha; tmpState.alpha = alpha;
state.applyViewState(divider, tmpState); state.applyViewState(divider, tmpState);
// There is no fake shadow to be drawn on the children // There is no fake shadow to be drawn on the children
@@ -473,6 +590,9 @@ public class NotificationChildrenContainer extends ViewGroup {
state.applyViewState(mOverflowNumber, mGroupOverFlowState); state.applyViewState(mOverflowNumber, mGroupOverFlowState);
mNeverAppliedGroupState = false; mNeverAppliedGroupState = false;
} }
if (mNotificationHeader != null) {
state.applyViewState(mNotificationHeader, mHeaderViewState);
}
} }
/** /**
@@ -491,6 +611,8 @@ public class NotificationChildrenContainer extends ViewGroup {
int childCount = mChildren.size(); int childCount = mChildren.size();
ViewState tmpState = new ViewState(); ViewState tmpState = new ViewState();
float expandFraction = getGroupExpandFraction(); float expandFraction = getGroupExpandFraction();
final boolean dividersVisible = mUserLocked
|| mNotificationParent.isGroupExpansionChanging();
for (int i = childCount - 1; i >= 0; i--) { for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i); ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child); StackViewState viewState = state.getViewStateForView(child);
@@ -505,6 +627,7 @@ public class NotificationChildrenContainer extends ViewGroup {
alpha = NotificationUtils.interpolate(0, 0.5f, alpha = NotificationUtils.interpolate(0, 0.5f,
Math.min(viewState.alpha, expandFraction)); Math.min(viewState.alpha, expandFraction));
} }
tmpState.hidden = !dividersVisible;
tmpState.alpha = alpha; tmpState.alpha = alpha;
stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration); stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
// There is no fake shadow to be drawn on the children // There is no fake shadow to be drawn on the children
@@ -521,6 +644,9 @@ public class NotificationChildrenContainer extends ViewGroup {
stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState, stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState,
baseDelay, duration); baseDelay, duration);
} }
if (mNotificationHeader != null) {
state.applyViewState(mNotificationHeader, mHeaderViewState);
}
} }
public ExpandableNotificationRow getViewAtPosition(float y) { public ExpandableNotificationRow getViewAtPosition(float y) {
@@ -541,14 +667,45 @@ public class NotificationChildrenContainer extends ViewGroup {
public void setChildrenExpanded(boolean childrenExpanded) { public void setChildrenExpanded(boolean childrenExpanded) {
mChildrenExpanded = childrenExpanded; mChildrenExpanded = childrenExpanded;
updateExpansionStates(); updateExpansionStates();
if (mNotificationHeader != null) {
mNotificationHeader.setExpanded(childrenExpanded);
}
} }
public void setNotificationParent(ExpandableNotificationRow parent) { public void setNotificationParent(ExpandableNotificationRow parent) {
mNotificationParent = 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() { public int getMaxContentHeight() {
int maxContentHeight = mNotificationHeaderHeight + mNotificatonTopPadding; int maxContentHeight = mNotificationHeaderMargin + mNotificatonTopPadding;
int visibleChildren = 0; int visibleChildren = 0;
int childCount = mChildren.size(); int childCount = mChildren.size();
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
@@ -601,7 +758,7 @@ public class NotificationChildrenContainer extends ViewGroup {
} }
private int getVisibleChildrenExpandHeight() { private int getVisibleChildrenExpandHeight() {
int intrinsicHeight = mNotificationHeaderHeight + mNotificatonTopPadding + mDividerHeight; int intrinsicHeight = mNotificationHeaderMargin + mNotificatonTopPadding + mDividerHeight;
int visibleChildren = 0; int visibleChildren = 0;
int childCount = mChildren.size(); int childCount = mChildren.size();
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */); int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
@@ -628,7 +785,7 @@ public class NotificationChildrenContainer extends ViewGroup {
} }
private int getMinHeight(int maxAllowedVisibleChildren) { private int getMinHeight(int maxAllowedVisibleChildren) {
int minExpandHeight = mNotificationHeaderHeight; int minExpandHeight = mNotificationHeaderMargin;
int visibleChildren = 0; int visibleChildren = 0;
boolean firstChild = true; boolean firstChild = true;
int childCount = mChildren.size(); int childCount = mChildren.size();
@@ -653,9 +810,13 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mOverflowNumber != null) { if (mOverflowNumber != null) {
mOverflowInvertHelper.setInverted(dark, fade, delay); 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(); initDimens();
for (int i = 0; i < mDividers.size(); i++) { for (int i = 0; i < mDividers.size(); i++) {
View prevDivider = mDividers.get(i); View prevDivider = mDividers.get(i);

View File

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

View File

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

View File

@@ -223,7 +223,7 @@ public class StackStateAnimator {
startViewAnimations(child, viewState, delay, duration); startViewAnimations(child, viewState, delay, duration);
// start height animation // start height animation
if (heightChanging && child.getActualHeight() != 0) { if (heightChanging) {
startHeightAnimation(child, viewState, duration, delay); startHeightAnimation(child, viewState, duration, delay);
} }
@@ -270,7 +270,8 @@ public class StackStateAnimator {
public void startViewAnimations(View child, ViewState viewState, long delay, long duration) { public void startViewAnimations(View child, ViewState viewState, long delay, long duration) {
boolean wasVisible = child.getVisibility() == View.VISIBLE; boolean wasVisible = child.getVisibility() == View.VISIBLE;
final float alpha = viewState.alpha; 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); child.setVisibility(View.VISIBLE);
} }
boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation; boolean yTranslationChanging = child.getTranslationY() != viewState.yTranslation;
@@ -477,11 +478,27 @@ public class StackStateAnimator {
animator.addListener(getGlobalAnimationFinishedListener()); animator.addListener(getGlobalAnimationFinishedListener());
// remove the tag when the animation is finished // remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() { animator.addListener(new AnimatorListenerAdapter() {
boolean mWasCancelled;
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
child.setTag(TAG_ANIMATOR_HEIGHT, null); child.setTag(TAG_ANIMATOR_HEIGHT, null);
child.setTag(TAG_START_HEIGHT, null); child.setTag(TAG_START_HEIGHT, null);
child.setTag(TAG_END_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); startAnimator(animator);

View File

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