AOD: Notification groups on Ambient Display

Bug: 36690937
Test: receive notification group on ambient display
Change-Id: I9dd91b85432e3d4309e0eb78a7b03ada87c3554e
This commit is contained in:
Adrian Roos
2017-05-02 16:22:53 -07:00
parent be030126fe
commit 6f6e159484
12 changed files with 400 additions and 99 deletions

View File

@@ -4257,15 +4257,17 @@ public class Notification implements Parcelable
* Construct a RemoteViews for the final notification header only. This will not be
* colorized.
*
* @param ambient if true, generate the header for the ambient display layout.
* @hide
*/
public RemoteViews makeNotificationHeader() {
public RemoteViews makeNotificationHeader(boolean ambient) {
Boolean colorized = (Boolean) mN.extras.get(EXTRA_COLORIZED);
mN.extras.putBoolean(EXTRA_COLORIZED, false);
RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
R.layout.notification_template_header);
ambient ? R.layout.notification_template_ambient_header
: R.layout.notification_template_header);
resetNotificationHeader(header);
bindNotificationHeader(header, false /* ambient */);
bindNotificationHeader(header, ambient);
if (colorized != null) {
mN.extras.putBoolean(EXTRA_COLORIZED, colorized);
} else {
@@ -4407,7 +4409,7 @@ public class Notification implements Parcelable
}
}
RemoteViews header = makeNotificationHeader();
RemoteViews header = makeNotificationHeader(false /* ambient */);
header.setBoolean(R.id.notification_header, "setAcceptAllTouches", true);
if (summary != null) {
mN.extras.putCharSequence(EXTRA_SUB_TEXT, summary);

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!-- hack to work around <include /> not being supported at the top level -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:paddingStart="@dimen/notification_extra_margin_ambient"
android:paddingEnd="@dimen/notification_extra_margin_ambient"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<include
layout="@layout/notification_template_header"
android:theme="@style/Theme.Material.Notification.Ambient"/>
</FrameLayout>

View File

@@ -2933,6 +2933,8 @@
<java-symbol type="string" name="time_picker_text_input_mode_description"/>
<java-symbol type="string" name="time_picker_radial_mode_description"/>
<java-symbol type="layout" name="notification_template_ambient_header" />
<!-- resolver activity -->
<java-symbol type="drawable" name="resolver_icon_placeholder" />

View File

@@ -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>

View File

@@ -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"
/>

View File

@@ -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. -->

View File

@@ -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>

View File

@@ -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>

View File

@@ -227,6 +227,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private boolean mUseIncreasedHeadsUpHeight;
private float mTranslationWhenRemoved;
private boolean mWasChildInGroupWhenRemoved;
private int mNotificationColorAmbient;
@Override
public boolean isGroupExpansionChanging() {
@@ -862,12 +863,18 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
return mNotificationInflater;
}
public int getNotificationColorAmbient() {
return mNotificationColorAmbient;
}
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -1509,13 +1520,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
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 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
}
private boolean isHeadsUpAllowed() {
return !mOnKeyguard && !mShowAmbient;
}
@Override
public boolean isGroupExpanded() {
return mGroupManager.isGroupExpanded(mStatusBarNotification);
@@ -1849,24 +1862,17 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
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 class ExpandableNotificationRow extends ActivatableNotificationView
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;
}

View File

@@ -54,6 +54,7 @@ public class NotificationContentView extends FrameLayout {
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 @@ public class NotificationContentView extends FrameLayout {
private View mHeadsUpChild;
private HybridNotificationView mSingleLineView;
private View mAmbientChild;
private HybridNotificationView mAmbientSingleLineChild;
private RemoteInputView mExpandedRemoteInput;
private RemoteInputView mHeadsUpRemoteInput;
@@ -252,6 +254,27 @@ public class NotificationContentView extends FrameLayout {
: 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 @@ public class NotificationContentView extends FrameLayout {
return mAmbientChild;
}
public HybridNotificationView getAmbientSingleLineChild() {
return mAmbientSingleLineChild;
}
public void setContractedChild(View child) {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
@@ -533,6 +560,9 @@ public class NotificationContentView extends FrameLayout {
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 class NotificationContentView extends FrameLayout {
}
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 class NotificationContentView extends FrameLayout {
}
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 @@ public class NotificationContentView extends FrameLayout {
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 @@ public class NotificationContentView extends FrameLayout {
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 @@ public class NotificationContentView extends FrameLayout {
return mSingleLineView;
case VISIBLE_TYPE_AMBIENT:
return mAmbientWrapper;
case VISIBLE_TYPE_AMBIENT_SINGLELINE:
return mAmbientSingleLineChild;
default:
return mContractedWrapper;
}
@@ -872,6 +921,8 @@ public class NotificationContentView extends FrameLayout {
return mSingleLineView;
case VISIBLE_TYPE_AMBIENT:
return mAmbientChild;
case VISIBLE_TYPE_AMBIENT_SINGLELINE:
return mAmbientSingleLineChild;
default:
return mContractedChild;
}
@@ -896,9 +947,14 @@ public class NotificationContentView extends FrameLayout {
* @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 @@ public class NotificationContentView extends FrameLayout {
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 @@ public class NotificationContentView extends FrameLayout {
mPreviousHeadsUpRemoteInputIntent = null;
}
private void updateAllSingleLineViews() {
updateSingleLineView();
updateAmbientSingleLineView();
}
private void updateSingleLineView() {
if (mIsChildInGroup) {
mSingleLineView = mHybridGroupManager.bindFromNotification(
@@ -1058,6 +1118,16 @@ public class NotificationContentView extends FrameLayout {
}
}
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 @@ public class NotificationContentView extends FrameLayout {
if (mIsChildInGroup && mSingleLineView != null) {
removeView(mSingleLineView);
mSingleLineView = null;
updateSingleLineView();
updateAllSingleLineViews();
}
}

View File

@@ -18,20 +18,14 @@ package com.android.systemui.statusbar.notification;
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 @@ import java.util.List;
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 @@ public class HybridGroupManager {
}
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 class HybridGroupManager {
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 @@ public class HybridGroupManager {
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());
}
}

View File

@@ -30,7 +30,6 @@ import android.widget.RemoteViews;
import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.ViewInvertHelper;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationHeaderUtil;
@@ -39,7 +38,6 @@ import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import java.util.ArrayList;
import java.util.List;
@@ -52,6 +50,7 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
mNotificationHeaderLowPriority.getMeasuredWidth(),
mNotificationHeaderLowPriority.getMeasuredHeight());
}
if (mNotificationHeaderAmbient != null) {
mNotificationHeaderAmbient.layout(0, 0,
mNotificationHeaderAmbient.getMeasuredWidth(),
mNotificationHeaderAmbient.getMeasuredHeight());
}
}
@Override
@@ -203,6 +208,10 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
}
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 @@ public class NotificationChildrenContainer extends ViewGroup {
header.reapply(getContext(), mNotificationHeaderLowPriority);
}
mNotificationHeaderWrapperLowPriority.notifyContentUpdated(mContainingNotification);
resetHeaderVisibilityIfNeeded(mNotificationHeaderLowPriority, calculateDesiredHeader());
} else {
removeView(mNotificationHeaderLowPriority);
mNotificationHeaderLowPriority = null;
@@ -339,10 +372,6 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
});
}
mOverflowNumber = null;
mOverflowInvertHelper = null;
mGroupOverFlowState = null;
}
}
@@ -449,6 +477,7 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mUserLocked) {
expandFactor = getGroupExpandFraction();
}
boolean childrenExpanded = mChildrenExpanded || mContainingNotification.isShowingAmbient();
for (int i = 0; i < childCount; i++) {
if (visibleChildren >= maxAllowedVisibleChildren) {
break;
@@ -458,7 +487,7 @@ public class NotificationChildrenContainer extends ViewGroup {
intrinsicHeight += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
expandFactor);
} else {
intrinsicHeight += mChildrenExpanded ? mDividerHeight : mChildPadding;
intrinsicHeight += childrenExpanded ? mDividerHeight : mChildPadding;
}
} else {
if (mUserLocked) {
@@ -467,7 +496,7 @@ public class NotificationChildrenContainer extends ViewGroup {
mNotificatonTopPadding + mDividerHeight,
expandFactor);
} else {
intrinsicHeight += mChildrenExpanded
intrinsicHeight += childrenExpanded
? mNotificatonTopPadding + mDividerHeight
: 0;
}
@@ -480,7 +509,7 @@ public class NotificationChildrenContainer extends ViewGroup {
if (mUserLocked) {
intrinsicHeight += NotificationUtils.interpolate(mCollapsedBottompadding, 0.0f,
expandFactor);
} else if (!mChildrenExpanded) {
} else if (!childrenExpanded) {
intrinsicHeight += mCollapsedBottompadding;
}
return intrinsicHeight;
@@ -515,7 +544,7 @@ public class NotificationChildrenContainer extends ViewGroup {
yPosition += NotificationUtils.interpolate(mChildPadding, mDividerHeight,
expandFactor);
} else {
yPosition += mChildrenExpanded ? mDividerHeight : mChildPadding;
yPosition += childrenExpanded ? mDividerHeight : mChildPadding;
}
} else {
if (expandingToExpandedGroup) {
@@ -524,7 +553,7 @@ public class NotificationChildrenContainer extends ViewGroup {
mNotificatonTopPadding + mDividerHeight,
expandFactor);
} else {
yPosition += mChildrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
yPosition += childrenExpanded ? mNotificatonTopPadding + mDividerHeight : 0;
}
firstChild = false;
}
@@ -560,15 +589,21 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
}
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 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
}
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 class NotificationChildrenContainer extends ViewGroup {
}
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 class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
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 @@ public class NotificationChildrenContainer extends ViewGroup {
}
removeView(mOverflowNumber);
mOverflowNumber = null;
mOverflowInvertHelper = null;
mGroupOverFlowState = null;
updateGroupOverflow();
}
@@ -1061,7 +1145,8 @@ public class NotificationChildrenContainer extends ViewGroup {
public void onNotificationUpdated() {
mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
mContainingNotification.getNotificationColor());
mContainingNotification.getNotificationColor(),
mContainingNotification.getNotificationColorAmbient());
}
public int getPositionInLinearLayout(View childInGroup) {