AOD: Notification groups on Ambient Display
Bug: 36690937
Test: receive notification group on ambient display
Change-Id: I9dd91b85432e3d4309e0eb78a7b03ada87c3554e
diff --git a/packages/SystemUI/res/layout/hybrid_notification.xml b/packages/SystemUI/res/layout/hybrid_notification.xml
index 476f52b..f4501da 100644
--- a/packages/SystemUI/res/layout/hybrid_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_notification.xml
@@ -19,23 +19,22 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="@*android:dimen/notification_content_margin_start"
- android:paddingEnd="12dp"
- android:gravity="bottom|start">
+ android:gravity="bottom|start"
+ style="?attr/hybridNotificationStyle">
<TextView
android:id="@+id/notification_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:paddingEnd="4dp"
- android:singleLine="true"
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
+ android:singleLine="true"
+ style="?attr/hybridNotificationTitleStyle"
/>
<TextView
android:id="@+id/notification_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingEnd="4dp"
- android:textAppearance="@*android:style/TextAppearance.Material.Notification"
android:singleLine="true"
- />
-</com.android.systemui.statusbar.notification.HybridNotificationView>
+ android:textAppearance="@*android:style/TextAppearance.Material.Notification"
+ style="?attr/hybridNotificationTextStyle"
+ />
+</com.android.systemui.statusbar.notification.HybridNotificationView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/hybrid_overflow_number.xml b/packages/SystemUI/res/layout/hybrid_overflow_number.xml
index f3dde8d..792f424 100644
--- a/packages/SystemUI/res/layout/hybrid_overflow_number.xml
+++ b/packages/SystemUI/res/layout/hybrid_overflow_number.xml
@@ -20,7 +20,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@*android:style/TextAppearance.Material.Notification"
- android:paddingEnd="@*android:dimen/notification_content_margin_end"
+ android:paddingEnd="@dimen/group_overflow_number_padding"
android:gravity="end"
android:singleLine="true"
/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 008fcf0..a57b17e 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -108,6 +108,12 @@
<attr name="android:layout" />
</declare-styleable>
+ <declare-styleable name="HybridNotificationTheme">
+ <attr name="hybridNotificationStyle" format="reference" />
+ <attr name="hybridNotificationTitleStyle" format="reference" />
+ <attr name="hybridNotificationTextStyle" format="reference" />
+ </declare-styleable>
+
<declare-styleable name="AutoSizingList">
<!-- Whether AutoSizingList will show only as many items as fit on screen and
remove extra items instead of scrolling. -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f072849..5374673 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -57,6 +57,11 @@
<!-- The amount to scale each of the status bar icons by. A value of 1 means no scaling. -->
<item name="status_bar_icon_scale_factor" format="float" type="dimen">1.0</item>
+ <dimen name="group_overflow_number_size">@*android:dimen/notification_text_size</dimen>
+ <dimen name="group_overflow_number_size_dark">16sp</dimen>
+ <dimen name="group_overflow_number_padding">@*android:dimen/notification_content_margin_end</dimen>
+ <dimen name="group_overflow_number_extra_padding_dark">@*android:dimen/notification_extra_margin_ambient</dimen>
+
<!-- max height of a notification such that the content can still fade out when closing -->
<dimen name="max_notification_fadeout_height">100dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index dbdbd1e..9650cea 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -82,6 +82,56 @@
<item name="android:activityCloseExitAnimation">@anim/forced_resizable_exit</item>
</style>
+ <!-- HybridNotification themes and styles -->
+
+ <style name="HybridNotification">
+ <item name="hybridNotificationStyle">@style/hybrid_notification</item>
+ <item name="hybridNotificationTitleStyle">@style/hybrid_notification_title</item>
+ <item name="hybridNotificationTextStyle">@style/hybrid_notification_text</item>
+ </style>
+
+ <style name="HybridNotification.Ambient">
+ <item name="hybridNotificationStyle">@style/hybrid_notification_ambient</item>
+ <item name="hybridNotificationTitleStyle">@style/hybrid_notification_title_ambient</item>
+ <item name="hybridNotificationTextStyle">@style/hybrid_notification_text_ambient</item>
+ </style>
+
+ <style name="hybrid_notification_ambient">
+ <item name="android:paddingStart">@*android:dimen/notification_extra_margin_ambient</item>
+ <item name="android:paddingEnd">@*android:dimen/notification_extra_margin_ambient</item>
+ <item name="android:orientation">vertical</item>
+ <item name="android:paddingBottom">23.5dp</item>
+ </style>
+
+ <style name="hybrid_notification">
+ <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
+ <item name="android:paddingEnd">12dp</item>
+ </style>
+
+ <style name="hybrid_notification_title_ambient">
+ <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
+ <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
+ <item name="android:textSize">20sp</item>
+ <item name="android:textColor">#ffffffff</item>
+ </style>
+
+ <style name="hybrid_notification_title">
+ <item name="android:paddingEnd">4dp</item>
+ </style>
+
+ <style name="hybrid_notification_text_ambient">
+ <item name="android:paddingStart">@*android:dimen/notification_content_margin_start</item>
+ <item name="android:paddingEnd">@*android:dimen/notification_content_margin_end</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:textColor">#eeffffff</item>
+ <item name="android:layout_marginTop">4dp</item>
+ </style>
+
+ <style name="hybrid_notification_text">
+ <item name="android:paddingEnd">4dp</item>
+ </style>
+
+
<style name="TextAppearance.StatusBar.HeadsUp"
parent="@*android:style/TextAppearance.StatusBar">
</style>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 9368747..208be8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -227,6 +227,7 @@
private boolean mUseIncreasedHeadsUpHeight;
private float mTranslationWhenRemoved;
private boolean mWasChildInGroupWhenRemoved;
+ private int mNotificationColorAmbient;
@Override
public boolean isGroupExpansionChanging() {
@@ -862,12 +863,18 @@
mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
getStatusBarNotification().getNotification().color,
getBackgroundColorWithoutTint());
+ mNotificationColorAmbient = NotificationColorUtil.resolveAmbientColor(mContext,
+ getStatusBarNotification().getNotification().color);
}
public HybridNotificationView getSingleLineView() {
return mPrivateLayout.getSingleLineView();
}
+ public HybridNotificationView getAmbientSingleLineView() {
+ return getShowingLayout().getAmbientSingleLineChild();
+ }
+
public boolean isOnKeyguard() {
return mOnKeyguard;
}
@@ -1131,6 +1138,10 @@
return mNotificationInflater;
}
+ public int getNotificationColorAmbient() {
+ return mNotificationColorAmbient;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -1509,13 +1520,11 @@
return mGuts.getIntrinsicHeight();
} else if ((isChildInGroup() && !isGroupExpanded())) {
return mPrivateLayout.getMinHeight();
- } else if (mShowAmbient) {
- return getAmbientHeight();
} else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
return getMinHeight();
- } else if (mIsSummaryWithChildren && !mOnKeyguard) {
+ } else if (mIsSummaryWithChildren && (!mOnKeyguard || mShowAmbient)) {
return mChildrenContainer.getIntrinsicHeight();
- } else if (!mOnKeyguard && (mIsHeadsUp || mHeadsupDisappearRunning)) {
+ } else if (isHeadsUpAllowed() && (mIsHeadsUp || mHeadsupDisappearRunning)) {
if (isPinned() || mHeadsupDisappearRunning) {
return getPinnedHeadsUpHeight(true /* atLeastMinHeight */);
} else if (isExpanded()) {
@@ -1530,6 +1539,10 @@
}
}
+ private boolean isHeadsUpAllowed() {
+ return !mOnKeyguard && !mShowAmbient;
+ }
+
@Override
public boolean isGroupExpanded() {
return mGroupManager.isGroupExpanded(mStatusBarNotification);
@@ -1849,24 +1862,17 @@
public int getMinHeight() {
if (mGuts != null && mGuts.isExposed()) {
return mGuts.getIntrinsicHeight();
- } else if (!mOnKeyguard && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
+ } else if (isHeadsUpAllowed() && mIsHeadsUp && mHeadsUpManager.isTrackingHeadsUp()) {
return getPinnedHeadsUpHeight(false /* atLeastMinHeight */);
} else if (mIsSummaryWithChildren && !isGroupExpanded() && !mShowingPublic) {
return mChildrenContainer.getMinHeight();
- } else if (!mOnKeyguard && mIsHeadsUp) {
+ } else if (isHeadsUpAllowed() && mIsHeadsUp) {
return mHeadsUpHeight;
}
NotificationContentView showingLayout = getShowingLayout();
return showingLayout.getMinHeight();
}
- private int getAmbientHeight() {
- NotificationContentView showingLayout = getShowingLayout();
- return showingLayout.getAmbientChild() != null
- ? showingLayout.getAmbientChild().getHeight()
- : getCollapsedHeight();
- }
-
@Override
public int getCollapsedHeight() {
if (mIsSummaryWithChildren && !mShowingPublic) {
@@ -2101,10 +2107,17 @@
public void setShowAmbient(boolean showAmbient) {
if (showAmbient != mShowAmbient) {
mShowAmbient = showAmbient;
+ if (mChildrenContainer != null) {
+ mChildrenContainer.notifyShowAmbientChanged();
+ }
notifyHeightChanged(false /* needsAnimation */);
}
}
+ public boolean isShowingAmbient() {
+ return mShowAmbient;
+ }
+
public void setAboveShelf(boolean aboveShelf) {
mAboveShelf = aboveShelf;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index e7bf983..baf0c2c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -54,6 +54,7 @@
private static final int VISIBLE_TYPE_HEADSUP = 2;
private static final int VISIBLE_TYPE_SINGLELINE = 3;
private static final int VISIBLE_TYPE_AMBIENT = 4;
+ private static final int VISIBLE_TYPE_AMBIENT_SINGLELINE = 5;
public static final int UNDEFINED = -1;
private final Rect mClipBounds = new Rect();
@@ -65,6 +66,7 @@
private View mHeadsUpChild;
private HybridNotificationView mSingleLineView;
private View mAmbientChild;
+ private HybridNotificationView mAmbientSingleLineChild;
private RemoteInputView mExpandedRemoteInput;
private RemoteInputView mHeadsUpRemoteInput;
@@ -252,6 +254,27 @@
: MeasureSpec.AT_MOST));
maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
}
+ if (mAmbientSingleLineChild != null) {
+ int size = Math.min(maxSize, mNotificationAmbientHeight);
+ ViewGroup.LayoutParams layoutParams = mAmbientSingleLineChild.getLayoutParams();
+ boolean useExactly = false;
+ if (layoutParams.height >= 0) {
+ // An actual height is set
+ size = Math.min(size, layoutParams.height);
+ useExactly = true;
+ }
+ int ambientSingleLineWidthSpec = widthMeasureSpec;
+ if (mSingleLineWidthIndention != 0
+ && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
+ ambientSingleLineWidthSpec = MeasureSpec.makeMeasureSpec(
+ width - mSingleLineWidthIndention + mAmbientSingleLineChild.getPaddingEnd(),
+ MeasureSpec.EXACTLY);
+ }
+ mAmbientSingleLineChild.measure(ambientSingleLineWidthSpec,
+ MeasureSpec.makeMeasureSpec(size, useExactly ? MeasureSpec.EXACTLY
+ : MeasureSpec.AT_MOST));
+ maxChildHeight = Math.max(maxChildHeight, mAmbientSingleLineChild.getMeasuredHeight());
+ }
int ownHeight = Math.min(maxChildHeight, maxSize);
setMeasuredDimension(width, ownHeight);
}
@@ -345,6 +368,10 @@
return mAmbientChild;
}
+ public HybridNotificationView getAmbientSingleLineChild() {
+ return mAmbientSingleLineChild;
+ }
+
public void setContractedChild(View child) {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
@@ -533,6 +560,9 @@
int hint;
if (mAmbientChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
hint = mAmbientChild.getHeight();
+ } else if (mAmbientSingleLineChild != null && isVisibleOrTransitioning(
+ VISIBLE_TYPE_AMBIENT_SINGLELINE)) {
+ hint = mAmbientSingleLineChild.getHeight();
} else if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
hint = mHeadsUpChild.getHeight();
} else if (mExpandedChild != null) {
@@ -622,7 +652,9 @@
}
public int getMaxHeight() {
- if (mExpandedChild != null) {
+ if (mContainingNotification.isShowingAmbient()) {
+ return getShowingAmbientView().getHeight();
+ } else if (mExpandedChild != null) {
return mExpandedChild.getHeight();
} else if (mIsHeadsUp && mHeadsUpChild != null && !mContainingNotification.isOnKeyguard()) {
return mHeadsUpChild.getHeight();
@@ -635,13 +667,24 @@
}
public int getMinHeight(boolean likeGroupExpanded) {
- if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
+ if (mContainingNotification.isShowingAmbient()) {
+ return getShowingAmbientView().getHeight();
+ } else if (likeGroupExpanded || !mIsChildInGroup || isGroupExpanded()) {
return mContractedChild.getHeight();
} else {
return mSingleLineView.getHeight();
}
}
+ public View getShowingAmbientView() {
+ View v = mIsChildInGroup ? mAmbientSingleLineChild : mAmbientChild;
+ if (v != null) {
+ return v;
+ } else {
+ return mContractedChild;
+ }
+ }
+
private boolean isGroupExpanded() {
return mGroupManager.isGroupExpanded(mStatusBarNotification);
}
@@ -723,6 +766,8 @@
forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
+ forceUpdateVisibility(VISIBLE_TYPE_AMBIENT_SINGLELINE, mAmbientSingleLineChild,
+ mAmbientSingleLineChild);
fireExpandedVisibleListenerIfVisible();
// forceUpdateVisibilities cancels outstanding animations without updating the
// mAnimationStartVisibleType. Do so here instead.
@@ -791,6 +836,8 @@
mSingleLineView, mSingleLineView);
updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
mAmbientChild, mAmbientWrapper);
+ updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT_SINGLELINE,
+ mAmbientSingleLineChild, mAmbientSingleLineChild);
fireExpandedVisibleListenerIfVisible();
// updateViewVisibilities cancels outstanding animations without updating the
// mAnimationStartVisibleType. Do so here instead.
@@ -853,6 +900,8 @@
return mSingleLineView;
case VISIBLE_TYPE_AMBIENT:
return mAmbientWrapper;
+ case VISIBLE_TYPE_AMBIENT_SINGLELINE:
+ return mAmbientSingleLineChild;
default:
return mContractedWrapper;
}
@@ -872,6 +921,8 @@
return mSingleLineView;
case VISIBLE_TYPE_AMBIENT:
return mAmbientChild;
+ case VISIBLE_TYPE_AMBIENT_SINGLELINE:
+ return mAmbientSingleLineChild;
default:
return mContractedChild;
}
@@ -896,9 +947,14 @@
* @return one of the static enum types in this view, calculated form the current state
*/
public int calculateVisibleType() {
- if (mDark && !mIsChildInGroup) {
- // TODO: Handle notification groups
- return VISIBLE_TYPE_AMBIENT;
+ if (mContainingNotification.isShowingAmbient()) {
+ if (mIsChildInGroup && mAmbientSingleLineChild != null) {
+ return VISIBLE_TYPE_AMBIENT_SINGLELINE;
+ } else if (mAmbientChild != null) {
+ return VISIBLE_TYPE_AMBIENT;
+ } else {
+ return VISIBLE_TYPE_CONTRACTED;
+ }
}
if (mUserExpanding) {
int height = !mIsChildInGroup || isGroupExpanded()
@@ -1021,13 +1077,13 @@
if (mAmbientChild != null) {
mAmbientWrapper.setIsChildInGroup(mIsChildInGroup);
}
- updateSingleLineView();
+ updateAllSingleLineViews();
}
public void onNotificationUpdated(NotificationData.Entry entry) {
mStatusBarNotification = entry.notification;
mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
- updateSingleLineView();
+ updateAllSingleLineViews();
if (mContractedChild != null) {
mContractedWrapper.notifyContentUpdated(entry.row);
}
@@ -1048,6 +1104,10 @@
mPreviousHeadsUpRemoteInputIntent = null;
}
+ private void updateAllSingleLineViews() {
+ updateSingleLineView();
+ updateAmbientSingleLineView();
+ }
private void updateSingleLineView() {
if (mIsChildInGroup) {
mSingleLineView = mHybridGroupManager.bindFromNotification(
@@ -1058,6 +1118,16 @@
}
}
+ private void updateAmbientSingleLineView() {
+ if (mIsChildInGroup) {
+ mAmbientSingleLineChild = mHybridGroupManager.bindAmbientFromNotification(
+ mAmbientSingleLineChild, mStatusBarNotification.getNotification());
+ } else if (mAmbientSingleLineChild != null) {
+ removeView(mAmbientSingleLineChild);
+ mAmbientSingleLineChild = null;
+ }
+ }
+
private void applyRemoteInput(final NotificationData.Entry entry) {
if (mRemoteInputController == null) {
return;
@@ -1255,7 +1325,7 @@
if (mIsChildInGroup && mSingleLineView != null) {
removeView(mSingleLineView);
mSingleLineView = null;
- updateSingleLineView();
+ updateAllSingleLineViews();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
index 7373607..3ed8cce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
@@ -18,20 +18,14 @@
import android.app.Notification;
import android.content.Context;
-import android.text.BidiFormatter;
-import android.text.Spannable;
-import android.text.SpannableStringBuilder;
-import android.text.TextUtils;
-import android.text.style.TextAppearanceSpan;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.systemui.R;
-import com.android.systemui.statusbar.ExpandableNotificationRow;
-
-import java.util.List;
/**
* A class managing hybrid groups that include {@link HybridNotificationView} and the notification
@@ -40,16 +34,37 @@
public class HybridGroupManager {
private final Context mContext;
- private ViewGroup mParent;
+ private final NotificationDozeHelper mDozer;
+ private final ViewGroup mParent;
+
+ private final float mOverflowNumberSizeDark;
+ private final int mOverflowNumberPaddingDark;
+ private final float mOverflowNumberSize;
+ private final int mOverflowNumberPadding;
+
private int mOverflowNumberColor;
+ private int mOverflowNumberColorDark;
+ private float mDarkAmount = 0f;
public HybridGroupManager(Context ctx, ViewGroup parent) {
mContext = ctx;
mParent = parent;
+ mDozer = new NotificationDozeHelper();
+
+ Resources res = mContext.getResources();
+ mOverflowNumberSize = res.getDimensionPixelSize(
+ R.dimen.group_overflow_number_size);
+ mOverflowNumberSizeDark = res.getDimensionPixelSize(
+ R.dimen.group_overflow_number_size_dark);
+ mOverflowNumberPadding = res.getDimensionPixelSize(
+ R.dimen.group_overflow_number_padding);
+ mOverflowNumberPaddingDark = mOverflowNumberPadding + res.getDimensionPixelSize(
+ R.dimen.group_overflow_number_extra_padding_dark);
}
- private HybridNotificationView inflateHybridView() {
- LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+ private HybridNotificationView inflateHybridViewWithStyle(int style) {
+ LayoutInflater inflater = new ContextThemeWrapper(mContext, style)
+ .getSystemService(LayoutInflater.class);
HybridNotificationView hybrid = (HybridNotificationView) inflater.inflate(
R.layout.hybrid_notification, mParent, false);
mParent.addView(hybrid);
@@ -66,11 +81,13 @@
}
private void updateOverFlowNumberColor(TextView numberView) {
- numberView.setTextColor(mOverflowNumberColor);
+ numberView.setTextColor(NotificationUtils.interpolateColors(
+ mOverflowNumberColor, mOverflowNumberColorDark, mDarkAmount));
}
- public void setOverflowNumberColor(TextView numberView, int overflowNumberColor) {
- mOverflowNumberColor = overflowNumberColor;
+ public void setOverflowNumberColor(TextView numberView, int colorRegular, int colorDark) {
+ mOverflowNumberColor = colorRegular;
+ mOverflowNumberColorDark = colorDark;
if (numberView != null) {
updateOverFlowNumberColor(numberView);
}
@@ -78,8 +95,20 @@
public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
Notification notification) {
+ return bindFromNotificationWithStyle(reusableView, notification,
+ R.style.HybridNotification);
+ }
+
+ public HybridNotificationView bindAmbientFromNotification(HybridNotificationView reusableView,
+ Notification notification) {
+ return bindFromNotificationWithStyle(reusableView, notification,
+ R.style.HybridNotification_Ambient);
+ }
+
+ private HybridNotificationView bindFromNotificationWithStyle(
+ HybridNotificationView reusableView, Notification notification, int style) {
if (reusableView == null) {
- reusableView = inflateHybridView();
+ reusableView = inflateHybridViewWithStyle(style);
}
CharSequence titleText = resolveTitle(notification);
CharSequence contentText = resolveText(notification);
@@ -118,4 +147,16 @@
reusableView.setContentDescription(contentDescription);
return reusableView;
}
+
+ public void setOverflowNumberDark(TextView view, boolean dark, boolean fade, long delay) {
+ mDozer.setIntensityDark((f)->{
+ mDarkAmount = f;
+ updateOverFlowNumberColor(view);
+ }, dark, fade, delay);
+ view.setTextSize(TypedValue.COMPLEX_UNIT_PX,
+ dark ? mOverflowNumberSizeDark : mOverflowNumberSize);
+ int paddingEnd = dark ? mOverflowNumberPaddingDark : mOverflowNumberPadding;
+ view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(), paddingEnd,
+ view.getPaddingBottom());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index fe249a6..cb1f44e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -30,7 +30,6 @@
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;
@@ -39,7 +38,6 @@
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.phone.NotificationPanelView;
import java.util.ArrayList;
import java.util.List;
@@ -52,6 +50,7 @@
private static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
+ private static final int NUMBER_OF_CHILDREN_WHEN_AMBIENT = 3;
private static final AnimationProperties ALPHA_FADE_IN = new AnimationProperties() {
private AnimationFilter mAnimationFilter = new AnimationFilter().animateAlpha();
@@ -70,7 +69,6 @@
private int mNotificationHeaderMargin;
private int mNotificatonTopPadding;
private float mCollapsedBottompadding;
- private ViewInvertHelper mOverflowInvertHelper;
private boolean mChildrenExpanded;
private ExpandableNotificationRow mContainingNotification;
private TextView mOverflowNumber;
@@ -85,12 +83,14 @@
private NotificationViewWrapper mNotificationHeaderWrapper;
private NotificationHeaderView mNotificationHeaderLowPriority;
private NotificationViewWrapper mNotificationHeaderWrapperLowPriority;
+ private ViewGroup mNotificationHeaderAmbient;
+ private NotificationViewWrapper mNotificationHeaderWrapperAmbient;
private NotificationHeaderUtil mHeaderUtil;
private ViewState mHeaderViewState;
private int mClipBottomAmount;
private boolean mIsLowPriority;
private OnClickListener mHeaderClickListener;
- private boolean mShowingNormalHeader;
+ private ViewGroup mCurrentHeader;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -152,6 +152,11 @@
mNotificationHeaderLowPriority.getMeasuredWidth(),
mNotificationHeaderLowPriority.getMeasuredHeight());
}
+ if (mNotificationHeaderAmbient != null) {
+ mNotificationHeaderAmbient.layout(0, 0,
+ mNotificationHeaderAmbient.getMeasuredWidth(),
+ mNotificationHeaderAmbient.getMeasuredHeight());
+ }
}
@Override
@@ -203,6 +208,10 @@
headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
mNotificationHeaderLowPriority.measure(widthMeasureSpec, headerHeightSpec);
}
+ if (mNotificationHeaderAmbient != null) {
+ headerHeightSpec = MeasureSpec.makeMeasureSpec(mHeaderHeight, MeasureSpec.EXACTLY);
+ mNotificationHeaderAmbient.measure(widthMeasureSpec, headerHeightSpec);
+ }
setMeasuredDimension(width, height);
}
@@ -273,7 +282,7 @@
StatusBarNotification notification = mContainingNotification.getStatusBarNotification();
final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
notification.getNotification());
- RemoteViews header = builder.makeNotificationHeader();
+ RemoteViews header = builder.makeNotificationHeader(false /* ambient */);
if (mNotificationHeader == null) {
mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this);
final View expandButton = mNotificationHeader.findViewById(
@@ -289,10 +298,33 @@
}
mNotificationHeaderWrapper.notifyContentUpdated(mContainingNotification);
recreateLowPriorityHeader(builder);
- updateHeaderVisibility(false /* animate */);
+ recreateAmbientHeader(builder);
+ resetHeaderVisibilityIfNeeded(mNotificationHeader, calculateDesiredHeader());
updateChildrenHeaderAppearance();
}
+ private void recreateAmbientHeader(Notification.Builder builder) {
+ RemoteViews header;
+ StatusBarNotification notification = mContainingNotification.getStatusBarNotification();
+ if (builder == null) {
+ builder = Notification.Builder.recoverBuilder(getContext(),
+ notification.getNotification());
+ }
+ header = builder.makeNotificationHeader(true /* ambient */);
+ if (mNotificationHeaderAmbient == null) {
+ mNotificationHeaderAmbient = (ViewGroup) header.apply(getContext(), this);
+ mNotificationHeaderWrapperAmbient = NotificationViewWrapper.wrap(getContext(),
+ mNotificationHeaderAmbient, mContainingNotification);
+ mNotificationHeaderWrapperAmbient.notifyContentUpdated(mContainingNotification);
+ addView(mNotificationHeaderAmbient, 0);
+ invalidate();
+ } else {
+ header.reapply(getContext(), mNotificationHeaderAmbient);
+ }
+ resetHeaderVisibilityIfNeeded(mNotificationHeaderAmbient, calculateDesiredHeader());
+ mNotificationHeaderWrapperAmbient.notifyContentUpdated(mContainingNotification);
+ }
+
/**
* Recreate the low-priority header.
*
@@ -322,6 +354,7 @@
header.reapply(getContext(), mNotificationHeaderLowPriority);
}
mNotificationHeaderWrapperLowPriority.notifyContentUpdated(mContainingNotification);
+ resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, calculateDesiredHeader());
} else {
removeView(mNotificationHeaderLowPriority);
mNotificationHeaderLowPriority = null;
@@ -339,10 +372,6 @@
if (childCount > maxAllowedVisibleChildren) {
mOverflowNumber = mHybridGroupManager.bindOverflowNumber(
mOverflowNumber, childCount - maxAllowedVisibleChildren);
- if (mOverflowInvertHelper == null) {
- mOverflowInvertHelper = new ViewInvertHelper(mOverflowNumber,
- NotificationPanelView.DOZE_ANIMATION_DURATION);
- }
if (mGroupOverFlowState == null) {
mGroupOverFlowState = new ViewState();
mNeverAppliedGroupState = true;
@@ -360,7 +389,6 @@
});
}
mOverflowNumber = null;
- mOverflowInvertHelper = null;
mGroupOverFlowState = null;
}
}
@@ -449,6 +477,7 @@
if (mUserLocked) {
expandFactor = getGroupExpandFraction();
}
+ boolean childrenExpanded = mChildrenExpanded || mContainingNotification.isShowingAmbient();
for (int i = 0; i < childCount; i++) {
if (visibleChildren >= maxAllowedVisibleChildren) {
break;
@@ -458,7 +487,7 @@
intrinsicHeight += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
expandFactor);
} else {
- intrinsicHeight += mChildrenExpanded ? mDividerHeight : mChildPadding;
+ intrinsicHeight += childrenExpanded ? mDividerHeight : mChildPadding;
}
} else {
if (mUserLocked) {
@@ -467,7 +496,7 @@
mNotificatonTopPadding + mDividerHeight,
expandFactor);
} else {
- intrinsicHeight += mChildrenExpanded
+ intrinsicHeight += childrenExpanded
? mNotificatonTopPadding + mDividerHeight
: 0;
}
@@ -480,7 +509,7 @@
if (mUserLocked) {
intrinsicHeight += NotificationUtils.interpolate(mCollapsedBottompadding, 0.0f,
expandFactor);
- } else if (!mChildrenExpanded) {
+ } else if (!childrenExpanded) {
intrinsicHeight += mCollapsedBottompadding;
}
return intrinsicHeight;
@@ -515,7 +544,7 @@
yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
expandFactor);
} else {
- yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
+ yPosition += childrenExpanded ? mDividerHeight : mChildPadding;
}
} else {
if (expandingToExpandedGroup) {
@@ -524,7 +553,7 @@
mNotificatonTopPadding + mDividerHeight,
expandFactor);
} else {
- yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
+ yPosition += childrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
}
firstChild = false;
}
@@ -560,15 +589,21 @@
ExpandableNotificationRow overflowView = mChildren.get(Math.min(
getMaxAllowedVisibleChildren(true /* likeCollpased */), childCount) - 1);
mGroupOverFlowState.copyFrom(resultState.getViewStateForView(overflowView));
- if (!mChildrenExpanded) {
- if (mUserLocked) {
- HybridNotificationView singleLineView = overflowView.getSingleLineView();
- View mirrorView = singleLineView.getTextView();
+
+ if (mContainingNotification.isShowingAmbient() || !mChildrenExpanded) {
+ HybridNotificationView alignView = null;
+ if (mContainingNotification.isShowingAmbient()) {
+ alignView = overflowView.getAmbientSingleLineView();
+ } else if (mUserLocked) {
+ alignView = overflowView.getSingleLineView();
+ }
+ if (alignView != null) {
+ View mirrorView = alignView.getTextView();
if (mirrorView.getVisibility() == GONE) {
- mirrorView = singleLineView.getTitleView();
+ mirrorView = alignView.getTitleView();
}
if (mirrorView.getVisibility() == GONE) {
- mirrorView = singleLineView;
+ mirrorView = alignView;
}
mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset(
mirrorView, overflowView);
@@ -620,6 +655,9 @@
}
private int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
+ if (mContainingNotification.isShowingAmbient()) {
+ return NUMBER_OF_CHILDREN_WHEN_AMBIENT;
+ }
if (!likeCollapsed && (mChildrenExpanded || mContainingNotification.isUserLocked())) {
return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
}
@@ -794,40 +832,78 @@
return mNotificationHeaderLowPriority;
}
+ public void notifyShowAmbientChanged() {
+ updateHeaderVisibility(false);
+ }
+
private void updateHeaderVisibility(boolean animate) {
- NotificationHeaderView visibleHeader = mNotificationHeader;
- NotificationHeaderView hiddenHeader = mNotificationHeaderLowPriority;
- boolean normalHeaderVisible = true;
- if (showingAsLowPriority()) {
- visibleHeader = mNotificationHeaderLowPriority;
- hiddenHeader = mNotificationHeader;
- normalHeaderVisible = false;
+ ViewGroup desiredHeader;
+ ViewGroup currentHeader = mCurrentHeader;
+ desiredHeader = calculateDesiredHeader();
+
+ if (currentHeader == desiredHeader) {
+ return;
}
+ if (desiredHeader == mNotificationHeaderAmbient
+ || currentHeader == mNotificationHeaderAmbient) {
+ animate = false;
+ }
+
if (animate) {
- if (visibleHeader != null && hiddenHeader != null
- && mShowingNormalHeader != normalHeaderVisible) {
- hiddenHeader.setVisibility(VISIBLE);
- visibleHeader.setVisibility(VISIBLE);
- NotificationViewWrapper visibleWrapper = getWrapperForView(visibleHeader);
- NotificationViewWrapper hiddenWrapper = getWrapperForView(hiddenHeader);
+ if (desiredHeader != null && currentHeader != null) {
+ currentHeader.setVisibility(VISIBLE);
+ desiredHeader.setVisibility(VISIBLE);
+ NotificationViewWrapper visibleWrapper = getWrapperForView(desiredHeader);
+ NotificationViewWrapper hiddenWrapper = getWrapperForView(currentHeader);
visibleWrapper.transformFrom(hiddenWrapper);
hiddenWrapper.transformTo(visibleWrapper, () -> updateHeaderVisibility(false));
- startChildAlphaAnimations(normalHeaderVisible);
+ startChildAlphaAnimations(desiredHeader == mNotificationHeader);
} else {
animate = false;
}
}
if (!animate) {
- if (visibleHeader != null) {
- getWrapperForView(visibleHeader).setVisible(true);
- visibleHeader.setVisibility(VISIBLE);
+ if (desiredHeader != null) {
+ getWrapperForView(desiredHeader).setVisible(true);
+ desiredHeader.setVisibility(VISIBLE);
}
- if (hiddenHeader != null) {
- getWrapperForView(hiddenHeader).setVisible(false);
- hiddenHeader.setVisibility(INVISIBLE);
+ if (currentHeader != null) {
+ getWrapperForView(currentHeader).setVisible(false);
+ currentHeader.setVisibility(INVISIBLE);
}
}
- mShowingNormalHeader = normalHeaderVisible;
+
+ resetHeaderVisibilityIfNeeded(mNotificationHeader, desiredHeader);
+ resetHeaderVisibilityIfNeeded(mNotificationHeaderAmbient, desiredHeader);
+ resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, desiredHeader);
+
+ mCurrentHeader = currentHeader;
+ }
+
+ private void resetHeaderVisibilityIfNeeded(View header, View desiredHeader) {
+ if (header == null) {
+ return;
+ }
+ if (header != mCurrentHeader && header != desiredHeader) {
+ getWrapperForView(header).setVisible(false);
+ header.setVisibility(INVISIBLE);
+ }
+ if (header == desiredHeader && header.getVisibility() != VISIBLE) {
+ getWrapperForView(header).setVisible(true);
+ header.setVisibility(VISIBLE);
+ }
+ }
+
+ private ViewGroup calculateDesiredHeader() {
+ ViewGroup desiredHeader;
+ if (mContainingNotification.isShowingAmbient()) {
+ desiredHeader = mNotificationHeaderAmbient;
+ } else if (showingAsLowPriority()) {
+ desiredHeader = mNotificationHeaderLowPriority;
+ } else {
+ desiredHeader = mNotificationHeader;
+ }
+ return desiredHeader;
}
private void startChildAlphaAnimations(boolean toVisible) {
@@ -861,10 +937,13 @@
}
- private NotificationViewWrapper getWrapperForView(NotificationHeaderView visibleHeader) {
+ private NotificationViewWrapper getWrapperForView(View visibleHeader) {
if (visibleHeader == mNotificationHeader) {
return mNotificationHeaderWrapper;
}
+ if (visibleHeader == mNotificationHeaderAmbient) {
+ return mNotificationHeaderWrapperAmbient;
+ }
return mNotificationHeaderWrapperLowPriority;
}
@@ -971,7 +1050,9 @@
}
public int getMinHeight() {
- return getMinHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED, false /* likeHighPriority */);
+ return getMinHeight(mContainingNotification.isShowingAmbient()
+ ? NUMBER_OF_CHILDREN_WHEN_AMBIENT
+ : NUMBER_OF_CHILDREN_WHEN_COLLAPSED, false /* likeHighPriority */);
}
public int getCollapsedHeight() {
@@ -1016,7 +1097,7 @@
public void setDark(boolean dark, boolean fade, long delay) {
if (mOverflowNumber != null) {
- mOverflowInvertHelper.setInverted(dark, fade, delay);
+ mHybridGroupManager.setOverflowNumberDark(mOverflowNumber, dark, fade, delay);
}
mNotificationHeaderWrapper.setDark(dark, fade, delay);
}
@@ -1030,6 +1111,10 @@
removeView(mNotificationHeaderLowPriority);
mNotificationHeaderLowPriority = null;
}
+ if (mNotificationHeaderAmbient != null) {
+ removeView(mNotificationHeaderAmbient);
+ mNotificationHeaderAmbient = null;
+ }
recreateNotificationHeader(listener);
initDimens();
for (int i = 0; i < mDividers.size(); i++) {
@@ -1042,7 +1127,6 @@
}
removeView(mOverflowNumber);
mOverflowNumber = null;
- mOverflowInvertHelper = null;
mGroupOverFlowState = null;
updateGroupOverflow();
}
@@ -1061,7 +1145,8 @@
public void onNotificationUpdated() {
mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
- mContainingNotification.getNotificationColor());
+ mContainingNotification.getNotificationColor(),
+ mContainingNotification.getNotificationColorAmbient());
}
public int getPositionInLinearLayout(View childInGroup) {