Changed the appearance of notification bundles
Children now show up as one line notifications even if the summary is not expanded. The childrenContainer shows a summary if there are some which don't fit in there currently. Bug: 24866646 Change-Id: I0cfae9342722c9f8941f51704618190cfe4e76b4
This commit is contained in:
39
packages/SystemUI/res/layout/hybrid_notification.xml
Normal file
39
packages/SystemUI/res/layout/hybrid_notification.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2015 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
|
||||
-->
|
||||
|
||||
<com.android.systemui.statusbar.notification.HybridNotificationView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/notification_max_height">
|
||||
<TextView
|
||||
android:id="@+id/notification_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
|
||||
android:paddingEnd="4dp"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/notification_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:textAppearance="@*android:style/TextAppearance.Material.Notification"
|
||||
android:singleLine="true"
|
||||
/>
|
||||
</com.android.systemui.statusbar.notification.HybridNotificationView>
|
||||
@@ -36,6 +36,18 @@
|
||||
<!-- The font size for the clock -->
|
||||
<dimen name="status_bar_clock_size">14sp</dimen>
|
||||
|
||||
<!-- The margin on the start of the content view -->
|
||||
<dimen name="notification_content_margin_start">16dp</dimen>
|
||||
|
||||
<!-- The maximum size of the title when in single line mode -->
|
||||
<dimen name="notification_maximum_title_length">150sp</dimen>
|
||||
|
||||
<!-- The margin on the end of the content view -->
|
||||
<dimen name="notification_content_margin_end">8dp</dimen>
|
||||
|
||||
<!-- Height of a single line notification in the status bar -->
|
||||
<dimen name="notification_single_line_height">32sp</dimen>
|
||||
|
||||
<!-- Height of a small notification in the status bar -->
|
||||
<dimen name="notification_min_height">64dp</dimen>
|
||||
|
||||
|
||||
@@ -1026,6 +1026,9 @@
|
||||
<!-- VolumeUI restoration notification: text -->
|
||||
<string name="volumeui_notification_text">Touch to restore the original.</string>
|
||||
|
||||
<!-- Describes the way 2 names are concatenated. An example would be ", " to produce "Peter Muller, Paul Curry". Please also include a space here if it's appropriate in the language and if it's a RTL language include it on the left. [CHAR LIMIT=3] -->
|
||||
<string name="group_summary_concadenation">, </string>
|
||||
|
||||
<!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
|
||||
<string name="managed_profile_foreground_toast">You\'re using your work profile</string>
|
||||
|
||||
|
||||
@@ -1929,27 +1929,29 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
for (int i = 0; i < N; i++) {
|
||||
NotificationData.Entry entry = activeNotifications.get(i);
|
||||
if (onKeyguard) {
|
||||
entry.row.setExpansionDisabled(true);
|
||||
entry.row.setOnKeyguard(true);
|
||||
} else {
|
||||
entry.row.setExpansionDisabled(false);
|
||||
if (!entry.row.isUserLocked()) {
|
||||
boolean top = (i == 0);
|
||||
entry.row.setSystemExpanded(top);
|
||||
}
|
||||
entry.row.setOnKeyguard(false);
|
||||
boolean top = (i == 0);
|
||||
entry.row.setSystemExpanded(top);
|
||||
}
|
||||
boolean isInvisibleChild = !mGroupManager.isVisible(entry.notification);
|
||||
boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
|
||||
boolean childWithVisibleSummary = childNotification
|
||||
&& mGroupManager.getGroupSummary(entry.notification).getVisibility()
|
||||
== View.VISIBLE;
|
||||
boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
|
||||
if ((isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
|
||||
(onKeyguard && (visibleNotifications >= maxKeyguardNotifications
|
||||
|| !showOnKeyguard || isInvisibleChild))) {
|
||||
&& !childWithVisibleSummary
|
||||
|| !showOnKeyguard))) {
|
||||
entry.row.setVisibility(View.GONE);
|
||||
if (onKeyguard && showOnKeyguard && !isInvisibleChild) {
|
||||
if (onKeyguard && showOnKeyguard && !childNotification) {
|
||||
mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
|
||||
}
|
||||
} else {
|
||||
boolean wasGone = entry.row.getVisibility() == View.GONE;
|
||||
entry.row.setVisibility(View.VISIBLE);
|
||||
if (!isInvisibleChild) {
|
||||
if (!childNotification) {
|
||||
if (wasGone) {
|
||||
// notify the scroller of a child addition
|
||||
mStackScroller.generateAddAnimation(entry.row, true /* fromMoreCard */);
|
||||
|
||||
@@ -70,9 +70,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
private boolean mIsSystemExpanded;
|
||||
|
||||
/**
|
||||
* Whether the notification expansion is disabled. This is the case on Keyguard.
|
||||
* Whether the notification is on the keyguard and the expansion is disabled.
|
||||
*/
|
||||
private boolean mExpansionDisabled;
|
||||
private boolean mOnKeyguard;
|
||||
|
||||
private NotificationContentView mPublicLayout;
|
||||
private NotificationContentView mPrivateLayout;
|
||||
@@ -162,6 +162,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
|
||||
private void setStatusBarNotification(StatusBarNotification statusBarNotification) {
|
||||
mStatusBarNotification = statusBarNotification;
|
||||
mPrivateLayout.setStatusBarNotification(statusBarNotification);
|
||||
updateVetoButton();
|
||||
onChildrenCountChanged();
|
||||
}
|
||||
@@ -185,6 +186,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
|
||||
public void setGroupManager(NotificationGroupManager groupManager) {
|
||||
mGroupManager = groupManager;
|
||||
mPrivateLayout.setGroupManager(groupManager);
|
||||
}
|
||||
|
||||
public void addChildNotification(ExpandableNotificationRow row) {
|
||||
@@ -225,6 +227,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {
|
||||
mChildInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
|
||||
mShowNoBackground = mChildInGroup && hasSameBgColor(parent);
|
||||
mPrivateLayout.setIsChildInGroup(mShowNoBackground);
|
||||
updateBackground();
|
||||
}
|
||||
|
||||
@@ -265,34 +268,34 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
}
|
||||
|
||||
public void getChildrenStates(StackScrollState resultState) {
|
||||
if (mChildrenExpanded) {
|
||||
if (mIsSummaryWithChildren) {
|
||||
StackViewState parentState = resultState.getViewStateForView(this);
|
||||
mChildrenContainer.getState(resultState, parentState);
|
||||
}
|
||||
}
|
||||
|
||||
public void applyChildrenState(StackScrollState state) {
|
||||
if (mChildrenExpanded) {
|
||||
if (mIsSummaryWithChildren) {
|
||||
mChildrenContainer.applyState(state);
|
||||
}
|
||||
}
|
||||
|
||||
public void prepareExpansionChanged(StackScrollState state) {
|
||||
if (mChildrenExpanded) {
|
||||
if (mIsSummaryWithChildren) {
|
||||
mChildrenContainer.prepareExpansionChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
public void startChildAnimation(StackScrollState finalState,
|
||||
StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
|
||||
if (mChildrenExpanded) {
|
||||
if (mIsSummaryWithChildren) {
|
||||
mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
|
||||
duration);
|
||||
}
|
||||
}
|
||||
|
||||
public ExpandableNotificationRow getViewAtPosition(float y) {
|
||||
if (!mChildrenExpanded) {
|
||||
if (!mIsSummaryWithChildren || !mChildrenExpanded) {
|
||||
return this;
|
||||
} else {
|
||||
ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
|
||||
@@ -416,7 +419,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
mSensitive = false;
|
||||
mShowingPublicInitialized = false;
|
||||
mIsSystemExpanded = false;
|
||||
mExpansionDisabled = false;
|
||||
mOnKeyguard = false;
|
||||
mPublicLayout.reset(mIsHeadsUp);
|
||||
mPrivateLayout.reset(mIsHeadsUp);
|
||||
resetHeight();
|
||||
@@ -580,16 +583,19 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
mIsSystemExpanded = expand;
|
||||
notifyHeightChanged(false /* needsAnimation */);
|
||||
logExpansionEvent(false, wasExpanded);
|
||||
if (mChildrenContainer != null) {
|
||||
mChildrenContainer.updateGroupOverflow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param expansionDisabled whether to prevent notification expansion
|
||||
* @param onKeyguard whether to prevent notification expansion
|
||||
*/
|
||||
public void setExpansionDisabled(boolean expansionDisabled) {
|
||||
if (expansionDisabled != mExpansionDisabled) {
|
||||
public void setOnKeyguard(boolean onKeyguard) {
|
||||
if (onKeyguard != mOnKeyguard) {
|
||||
final boolean wasExpanded = isExpanded();
|
||||
mExpansionDisabled = expansionDisabled;
|
||||
mOnKeyguard = onKeyguard;
|
||||
logExpansionEvent(false, wasExpanded);
|
||||
if (wasExpanded != isExpanded()) {
|
||||
notifyHeightChanged(false /* needsAnimation */);
|
||||
@@ -622,23 +628,22 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
return getActualHeight();
|
||||
}
|
||||
boolean inExpansionState = isExpanded();
|
||||
int maxContentHeight;
|
||||
if (mSensitive && mHideSensitiveForIntrinsicHeight) {
|
||||
return mRowMinHeight;
|
||||
} else if (mIsSummaryWithChildren && !mOnKeyguard) {
|
||||
return mChildrenContainer.getIntrinsicHeight()
|
||||
+ mNotificationHeader.getHeight();
|
||||
} else if (mIsHeadsUp) {
|
||||
if (inExpansionState) {
|
||||
maxContentHeight = Math.max(mMaxExpandHeight, mHeadsUpHeight);
|
||||
return Math.max(mMaxExpandHeight, mHeadsUpHeight);
|
||||
} else {
|
||||
maxContentHeight = Math.max(mRowMinHeight, mHeadsUpHeight);
|
||||
return Math.max(mRowMinHeight, mHeadsUpHeight);
|
||||
}
|
||||
} else if ((!inExpansionState && !mChildrenExpanded)) {
|
||||
maxContentHeight = mRowMinHeight;
|
||||
} else if (mChildrenExpanded) {
|
||||
maxContentHeight = mChildrenContainer.getIntrinsicHeight();
|
||||
} else if (!inExpansionState || (mChildInGroup && !isGroupExpanded())) {
|
||||
return getMinHeight();
|
||||
} else {
|
||||
maxContentHeight = getMaxExpandHeight();
|
||||
return getMaxExpandHeight();
|
||||
}
|
||||
return maxContentHeight;
|
||||
}
|
||||
|
||||
private boolean isGroupExpanded() {
|
||||
@@ -670,8 +675,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
*
|
||||
* @return whether the view state is currently expanded.
|
||||
*/
|
||||
private boolean isExpanded() {
|
||||
return !mExpansionDisabled
|
||||
public boolean isExpanded() {
|
||||
return !mOnKeyguard
|
||||
&& (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
|
||||
|| isUserExpanded());
|
||||
}
|
||||
@@ -778,6 +783,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
|
||||
public void setChildrenExpanded(boolean expanded, boolean animate) {
|
||||
mChildrenExpanded = expanded;
|
||||
if (mChildrenContainer != null) {
|
||||
mChildrenContainer.setChildrenExpanded(expanded);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateNotificationHeader() {
|
||||
@@ -844,12 +852,20 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
|
||||
|
||||
@Override
|
||||
public int getMaxContentHeight() {
|
||||
if (mIsSummaryWithChildren && !mShowingPublic) {
|
||||
return mChildrenContainer.getMaxContentHeight()
|
||||
+ mNotificationHeader.getHeight();
|
||||
}
|
||||
NotificationContentView showingLayout = getShowingLayout();
|
||||
return showingLayout.getMaxHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight() {
|
||||
if (mIsSummaryWithChildren && !mOnKeyguard) {
|
||||
return mChildrenContainer.getMinHeight()
|
||||
+ mNotificationHeader.getHeight();
|
||||
}
|
||||
NotificationContentView showingLayout = getShowingLayout();
|
||||
return showingLayout.getMinHeight();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -32,6 +33,9 @@ import android.view.animation.LinearInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.notification.HybridNotificationView;
|
||||
import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
|
||||
import com.android.systemui.statusbar.phone.NotificationGroupManager;
|
||||
|
||||
/**
|
||||
* A frame layout containing the actual payload of the notification, including the contracted,
|
||||
@@ -44,8 +48,10 @@ public class NotificationContentView extends FrameLayout {
|
||||
private static final int VISIBLE_TYPE_CONTRACTED = 0;
|
||||
private static final int VISIBLE_TYPE_EXPANDED = 1;
|
||||
private static final int VISIBLE_TYPE_HEADSUP = 2;
|
||||
private static final int VISIBLE_TYPE_SINGLELINE = 3;
|
||||
|
||||
private final Rect mClipBounds = new Rect();
|
||||
private final int mSingleLineHeight;
|
||||
private final int mSmallHeight;
|
||||
private final int mHeadsUpHeight;
|
||||
private final int mRoundRectRadius;
|
||||
@@ -55,10 +61,12 @@ public class NotificationContentView extends FrameLayout {
|
||||
private View mContractedChild;
|
||||
private View mExpandedChild;
|
||||
private View mHeadsUpChild;
|
||||
private HybridNotificationView mSingleLineView;
|
||||
|
||||
private NotificationViewWrapper mContractedWrapper;
|
||||
private NotificationViewWrapper mExpandedWrapper;
|
||||
private NotificationViewWrapper mHeadsUpWrapper;
|
||||
private HybridNotificationViewManager mHybridViewManager;
|
||||
private int mClipTopAmount;
|
||||
private int mContentHeight;
|
||||
private int mUnrestrictedContentHeight;
|
||||
@@ -68,6 +76,8 @@ public class NotificationContentView extends FrameLayout {
|
||||
private boolean mAnimate;
|
||||
private boolean mIsHeadsUp;
|
||||
private boolean mShowingLegacyBackground;
|
||||
private boolean mIsChildInGroup;
|
||||
private StatusBarNotification mStatusBarNotification;
|
||||
|
||||
private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
|
||||
= new ViewTreeObserver.OnPreDrawListener() {
|
||||
@@ -86,10 +96,14 @@ public class NotificationContentView extends FrameLayout {
|
||||
mRoundRectRadius);
|
||||
}
|
||||
};
|
||||
private NotificationGroupManager mGroupManager;
|
||||
|
||||
public NotificationContentView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
|
||||
mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
|
||||
mSingleLineHeight = getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_single_line_height);
|
||||
mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
|
||||
mHeadsUpHeight = getResources().getDimensionPixelSize(R.dimen.notification_mid_height);
|
||||
mRoundRectRadius = getResources().getDimensionPixelSize(
|
||||
@@ -140,6 +154,12 @@ public class NotificationContentView extends FrameLayout {
|
||||
MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
|
||||
maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
|
||||
}
|
||||
if (mSingleLineView != null) {
|
||||
int size = Math.min(maxSize, mSingleLineHeight);
|
||||
mSingleLineView.measure(widthMeasureSpec,
|
||||
MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY));
|
||||
maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
|
||||
}
|
||||
int ownHeight = Math.min(maxChildHeight, maxSize);
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
setMeasuredDimension(width, ownHeight);
|
||||
@@ -271,7 +291,15 @@ public class NotificationContentView extends FrameLayout {
|
||||
}
|
||||
|
||||
public int getMinHeight() {
|
||||
return mSmallHeight;
|
||||
if (mIsChildInGroup && !isGroupExpanded()) {
|
||||
return mSingleLineHeight;
|
||||
} else {
|
||||
return mSmallHeight;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGroupExpanded() {
|
||||
return mGroupManager.isGroupExpanded(mStatusBarNotification);
|
||||
}
|
||||
|
||||
public void setClipTopAmount(int clipTopAmount) {
|
||||
@@ -313,6 +341,7 @@ public class NotificationContentView extends FrameLayout {
|
||||
if (visibleType != mVisibleType || force) {
|
||||
if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
|
||||
|| (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
|
||||
|| (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
|
||||
|| visibleType == VISIBLE_TYPE_CONTRACTED)) {
|
||||
runSwitchAnimation(visibleType);
|
||||
} else {
|
||||
@@ -339,6 +368,12 @@ public class NotificationContentView extends FrameLayout {
|
||||
mHeadsUpChild.setAlpha(headsUpVisible ? 1f : 0f);
|
||||
mHeadsUpChild.setLayerType(LAYER_TYPE_NONE, null);
|
||||
}
|
||||
if (mSingleLineView != null) {
|
||||
boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
|
||||
mSingleLineView.setVisibility(singleLineVisible ? View.VISIBLE : View.INVISIBLE);
|
||||
mSingleLineView.setAlpha(singleLineVisible ? 1f : 0f);
|
||||
mSingleLineView.setLayerType(LAYER_TYPE_NONE, null);
|
||||
}
|
||||
setLayerType(LAYER_TYPE_NONE, null);
|
||||
updateRoundRectClipping();
|
||||
}
|
||||
@@ -379,6 +414,8 @@ public class NotificationContentView extends FrameLayout {
|
||||
return mExpandedChild;
|
||||
case VISIBLE_TYPE_HEADSUP:
|
||||
return mHeadsUpChild;
|
||||
case VISIBLE_TYPE_SINGLELINE:
|
||||
return mSingleLineView;
|
||||
default:
|
||||
return mContractedChild;
|
||||
}
|
||||
@@ -396,7 +433,9 @@ public class NotificationContentView extends FrameLayout {
|
||||
return VISIBLE_TYPE_EXPANDED;
|
||||
}
|
||||
} else {
|
||||
if (mContentHeight <= mSmallHeight || noExpandedChild) {
|
||||
if (mIsChildInGroup && !isGroupExpanded()) {
|
||||
return VISIBLE_TYPE_SINGLELINE;
|
||||
} else if (mContentHeight <= mSmallHeight || noExpandedChild) {
|
||||
return VISIBLE_TYPE_CONTRACTED;
|
||||
} else {
|
||||
return VISIBLE_TYPE_EXPANDED;
|
||||
@@ -405,6 +444,7 @@ public class NotificationContentView extends FrameLayout {
|
||||
}
|
||||
|
||||
public void notifyContentUpdated() {
|
||||
updateSingleLineView();
|
||||
selectLayout(false /* animate */, true /* force */);
|
||||
if (mContractedChild != null) {
|
||||
mContractedWrapper.notifyContentUpdated();
|
||||
@@ -443,6 +483,23 @@ public class NotificationContentView extends FrameLayout {
|
||||
mShowingLegacyBackground = showing;
|
||||
}
|
||||
|
||||
public void setIsChildInGroup(boolean isChildInGroup) {
|
||||
mIsChildInGroup = isChildInGroup;
|
||||
updateSingleLineView();
|
||||
}
|
||||
|
||||
public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
|
||||
mStatusBarNotification = statusBarNotification;
|
||||
updateSingleLineView();
|
||||
}
|
||||
|
||||
private void updateSingleLineView() {
|
||||
if (mIsChildInGroup) {
|
||||
mSingleLineView = mHybridViewManager.bindFromNotification(
|
||||
mSingleLineView, mStatusBarNotification.getNotification());
|
||||
}
|
||||
}
|
||||
|
||||
public void setSubTextVisible(boolean visible) {
|
||||
if (mExpandedChild != null) {
|
||||
mExpandedWrapper.setSubTextVisible(visible);
|
||||
@@ -454,4 +511,8 @@ public class NotificationContentView extends FrameLayout {
|
||||
mHeadsUpWrapper.setSubTextVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
public void setGroupManager(NotificationGroupManager groupManager) {
|
||||
mGroupManager = groupManager;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.notification;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
|
||||
|
||||
/**
|
||||
* A hybrid view which may contain information about one ore more notifications.
|
||||
*/
|
||||
public class HybridNotificationView extends AlphaOptimizedFrameLayout {
|
||||
|
||||
protected final int mSingleLineHeight;
|
||||
protected final int mStartMargin;
|
||||
protected final int mEndMargin;
|
||||
protected TextView mTitleView;
|
||||
protected TextView mTextView;
|
||||
|
||||
public HybridNotificationView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public HybridNotificationView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public HybridNotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr, 0);
|
||||
}
|
||||
|
||||
public HybridNotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
|
||||
int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
mSingleLineHeight = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_single_line_height);
|
||||
mStartMargin = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_content_margin_start);
|
||||
mEndMargin = context.getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_content_margin_end);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int totalWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int remainingWidth = totalWidth - mStartMargin - mEndMargin;
|
||||
int newHeightSpec = MeasureSpec.makeMeasureSpec(
|
||||
MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST);
|
||||
int newWidthSpec = MeasureSpec.makeMeasureSpec(remainingWidth, MeasureSpec.AT_MOST);
|
||||
mTitleView.measure(newWidthSpec, newHeightSpec);
|
||||
int maxTitleLength = getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_maximum_title_length);
|
||||
int titleWidth = mTitleView.getMeasuredWidth();
|
||||
int heightSpec = MeasureSpec.makeMeasureSpec(mSingleLineHeight, MeasureSpec.AT_MOST);
|
||||
boolean hasText = !TextUtils.isEmpty(mTextView.getText());
|
||||
if (titleWidth > maxTitleLength && hasText) {
|
||||
titleWidth = maxTitleLength;
|
||||
int widthSpec = MeasureSpec.makeMeasureSpec(titleWidth, MeasureSpec.EXACTLY);
|
||||
mTitleView.measure(widthSpec, heightSpec);
|
||||
}
|
||||
if (hasText) {
|
||||
remainingWidth -= titleWidth;
|
||||
int widthSpec = MeasureSpec.makeMeasureSpec(remainingWidth, MeasureSpec.AT_MOST);
|
||||
mTextView.measure(widthSpec, newHeightSpec);
|
||||
}
|
||||
setMeasuredDimension(totalWidth, mSingleLineHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
int childLeft = mStartMargin;
|
||||
int childRight = childLeft + mTitleView.getMeasuredWidth();
|
||||
int childBottom = (mSingleLineHeight + mTitleView.getMeasuredHeight()) / 2;
|
||||
int childTop = childBottom - mTitleView.getMeasuredHeight();
|
||||
int rtlLeft = transformForRtl(childLeft);
|
||||
int rtlRight = transformForRtl(childRight);
|
||||
mTitleView.layout(Math.min(rtlLeft, rtlRight), childTop, Math.max(rtlLeft, rtlRight),
|
||||
childBottom);
|
||||
childLeft = childRight;
|
||||
childRight = childLeft + mTextView.getMeasuredWidth();
|
||||
childTop = mTitleView.getTop() + mTitleView.getBaseline() - mTextView.getBaseline();
|
||||
childBottom = childTop + mTextView.getMeasuredHeight();
|
||||
rtlLeft = transformForRtl(childLeft);
|
||||
rtlRight = transformForRtl(childRight);
|
||||
mTextView.layout(Math.min(rtlLeft, rtlRight), childTop, Math.max(rtlLeft, rtlRight),
|
||||
childBottom);
|
||||
}
|
||||
|
||||
private int transformForRtl(int left) {
|
||||
return isLayoutRtl() ? getWidth() - left : left;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mTitleView = (TextView) findViewById(R.id.notification_title);
|
||||
mTextView = (TextView) findViewById(R.id.notification_text);
|
||||
}
|
||||
|
||||
public void bind(CharSequence title) {
|
||||
bind(title, null);
|
||||
}
|
||||
|
||||
public void bind(CharSequence title, CharSequence text) {
|
||||
mTitleView.setText(title);
|
||||
mTextView.setText(text);
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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
|
||||
*/
|
||||
|
||||
package com.android.systemui.statusbar.notification;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.ExpandableNotificationRow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A class managing {@link HybridNotificationView} views
|
||||
*/
|
||||
public class HybridNotificationViewManager {
|
||||
|
||||
private final Context mContext;
|
||||
private ViewGroup mParent;
|
||||
private String mConcadenationString;
|
||||
|
||||
public HybridNotificationViewManager(Context ctx, ViewGroup parent) {
|
||||
mContext = ctx;
|
||||
mParent = parent;
|
||||
mConcadenationString = mContext.getString(R.string.group_summary_concadenation);
|
||||
}
|
||||
|
||||
private HybridNotificationView inflateHybridView() {
|
||||
LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
|
||||
HybridNotificationView hybrid = (HybridNotificationView) inflater.inflate(
|
||||
R.layout.hybrid_notification, mParent, false);
|
||||
mParent.addView(hybrid);
|
||||
return hybrid;
|
||||
}
|
||||
|
||||
public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
|
||||
Notification notification) {
|
||||
CharSequence titleText = resolveTitle(notification);
|
||||
if (titleText == null) {
|
||||
if (reusableView != null) {
|
||||
mParent.removeView(reusableView);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (reusableView == null) {
|
||||
reusableView = inflateHybridView();
|
||||
}
|
||||
CharSequence contentText = resolveText(notification);
|
||||
reusableView.bind(titleText, contentText);
|
||||
return reusableView;
|
||||
}
|
||||
|
||||
private CharSequence resolveText(Notification notification) {
|
||||
CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
|
||||
if (contentText == null) {
|
||||
contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
|
||||
}
|
||||
return contentText;
|
||||
}
|
||||
|
||||
private CharSequence resolveTitle(Notification notification) {
|
||||
CharSequence titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
|
||||
if (titleText == null) {
|
||||
titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG);
|
||||
}
|
||||
return titleText;
|
||||
}
|
||||
|
||||
public HybridNotificationView bindFromNotificationGroup(
|
||||
HybridNotificationView reusableView,
|
||||
List<ExpandableNotificationRow> group, int startIndex) {
|
||||
if (reusableView == null) {
|
||||
reusableView = inflateHybridView();
|
||||
}
|
||||
CharSequence summary = null;
|
||||
int childCount = group.size();
|
||||
for (int i = startIndex; i < childCount; i++) {
|
||||
ExpandableNotificationRow child = group.get(i);
|
||||
CharSequence titleText = resolveTitle(
|
||||
child.getStatusBarNotification().getNotification());
|
||||
if (titleText == null) {
|
||||
continue;
|
||||
}
|
||||
if (TextUtils.isEmpty(summary)) {
|
||||
summary = titleText;
|
||||
} else if (reusableView.isLayoutRtl()) {
|
||||
summary = titleText + mConcadenationString + summary;
|
||||
} else {
|
||||
summary = summary + mConcadenationString + titleText;
|
||||
}
|
||||
}
|
||||
reusableView.bind(summary);
|
||||
return reusableView;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import android.service.notification.StatusBarNotification;
|
||||
|
||||
import com.android.systemui.statusbar.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.NotificationData;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -93,21 +92,8 @@ public class NotificationGroupManager {
|
||||
if (group.children.isEmpty()) {
|
||||
if (group.summary == null) {
|
||||
mGroupMap.remove(groupKey);
|
||||
} else {
|
||||
if (group.expanded) {
|
||||
// only the summary is left. Change it to unexpanded in a few ms. We do this to
|
||||
// avoid raceconditions
|
||||
removed.row.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (group.children.isEmpty()) {
|
||||
setGroupExpanded(sbn, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
group.summary.row.updateNotificationHeader();
|
||||
}
|
||||
} else if (!group.expanded) {
|
||||
group.summary.row.updateNotificationHeader();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,9 +141,6 @@ public class NotificationGroupManager {
|
||||
}
|
||||
|
||||
public boolean hasGroupChildren(StatusBarNotification sbn) {
|
||||
if (areGroupsProhibited()) {
|
||||
return false;
|
||||
}
|
||||
if (!sbn.getNotification().isGroupSummary()) {
|
||||
return false;
|
||||
}
|
||||
@@ -168,29 +151,6 @@ public class NotificationGroupManager {
|
||||
return !group.children.isEmpty();
|
||||
}
|
||||
|
||||
public void setStatusBarState(int newState) {
|
||||
if (mBarState == newState) {
|
||||
return;
|
||||
}
|
||||
boolean prohibitedBefore = areGroupsProhibited();
|
||||
mBarState = newState;
|
||||
boolean nowProhibited = areGroupsProhibited();
|
||||
if (nowProhibited != prohibitedBefore) {
|
||||
if (nowProhibited) {
|
||||
for (NotificationGroup group : mGroupMap.values()) {
|
||||
if (group.expanded) {
|
||||
setGroupExpanded(group, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
mListener.onGroupsProhibitedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean areGroupsProhibited() {
|
||||
return mBarState == StatusBarState.KEYGUARD;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return whether a given notification is a child in a group which has a summary
|
||||
*/
|
||||
@@ -226,6 +186,18 @@ public class NotificationGroupManager {
|
||||
: group.summary.row;
|
||||
}
|
||||
|
||||
public void onEntryHeadsUped(NotificationData.Entry headsUp) {
|
||||
// TODO: handle this nicely
|
||||
}
|
||||
|
||||
public void toggleGroupExpansion(StatusBarNotification sbn) {
|
||||
NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
|
||||
if (group == null) {
|
||||
return;
|
||||
}
|
||||
setGroupExpanded(group, !group.expanded);
|
||||
}
|
||||
|
||||
public static class NotificationGroup {
|
||||
public final HashSet<NotificationData.Entry> children = new HashSet<>();
|
||||
public NotificationData.Entry summary;
|
||||
@@ -241,11 +213,6 @@ public class NotificationGroupManager {
|
||||
*/
|
||||
void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded);
|
||||
|
||||
/**
|
||||
* Children group policy has changed and children may no be prohibited or allowed.
|
||||
*/
|
||||
void onGroupsProhibitedChanged();
|
||||
|
||||
/**
|
||||
* A group of children just received a summary notification and should therefore become
|
||||
* children of it.
|
||||
|
||||
@@ -714,7 +714,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
|
||||
R.color.notification_panel_solid_background)));
|
||||
}
|
||||
|
||||
mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
|
||||
mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
|
||||
mHeadsUpManager.setBar(this);
|
||||
mHeadsUpManager.addListener(this);
|
||||
mHeadsUpManager.addListener(mNotificationPanel);
|
||||
@@ -3859,7 +3859,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
|
||||
clearNotificationEffects();
|
||||
}
|
||||
mState = state;
|
||||
mGroupManager.setStatusBarState(state);
|
||||
mFalsingManager.setStatusBarState(state);
|
||||
mStatusBarWindowManager.setStatusBarState(state);
|
||||
updateDozing();
|
||||
|
||||
@@ -33,6 +33,7 @@ import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.NotificationData;
|
||||
import com.android.systemui.statusbar.phone.NotificationGroupManager;
|
||||
import com.android.systemui.statusbar.phone.PhoneStatusBar;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
@@ -85,6 +86,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
|
||||
private final int mStatusBarHeight;
|
||||
private final int mNotificationsTopPadding;
|
||||
private final Context mContext;
|
||||
private final NotificationGroupManager mGroupManager;
|
||||
private PhoneStatusBar mBar;
|
||||
private int mSnoozeLengthMs;
|
||||
private ContentObserver mSettingsObserver;
|
||||
@@ -104,7 +106,8 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
|
||||
private boolean mIsObserving;
|
||||
private boolean mRemoteInputActive;
|
||||
|
||||
public HeadsUpManager(final Context context, View statusBarWindowView) {
|
||||
public HeadsUpManager(final Context context, View statusBarWindowView,
|
||||
NotificationGroupManager groupManager) {
|
||||
mContext = context;
|
||||
Resources resources = mContext.getResources();
|
||||
mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
|
||||
@@ -132,6 +135,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
|
||||
Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false,
|
||||
mSettingsObserver);
|
||||
mStatusBarWindowView = statusBarWindowView;
|
||||
mGroupManager = groupManager;
|
||||
mStatusBarHeight = resources.getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.status_bar_height);
|
||||
mNotificationsTopPadding = context.getResources()
|
||||
@@ -181,12 +185,12 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
|
||||
public void updateNotification(NotificationData.Entry headsUp, boolean alert) {
|
||||
if (DEBUG) Log.v(TAG, "updateNotification");
|
||||
|
||||
headsUp.row.setChildrenExpanded(false /* expanded */, false /* animated */);
|
||||
headsUp.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
|
||||
|
||||
if (alert) {
|
||||
HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(headsUp.key);
|
||||
headsUpEntry.updateEntry();
|
||||
mGroupManager.onEntryHeadsUped(headsUp);
|
||||
setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUp));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,8 @@ import android.view.ViewGroup;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.ExpandableView;
|
||||
import com.android.systemui.statusbar.notification.HybridNotificationView;
|
||||
import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -34,6 +35,10 @@ import java.util.List;
|
||||
*/
|
||||
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 final int mChildPadding;
|
||||
private final int mDividerHeight;
|
||||
private final int mMaxNotificationHeight;
|
||||
@@ -42,6 +47,12 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
private final int mNotificationHeaderHeight;
|
||||
private final int mNotificationAppearDistance;
|
||||
private final float mHeaderTopPaddingSubstraction;
|
||||
private final HybridNotificationViewManager mHybridViewManager;
|
||||
private final float mCollapsedBottompadding;
|
||||
private boolean mChildrenExpanded;
|
||||
private ExpandableNotificationRow mNotificationParent;
|
||||
private HybridNotificationView mGroupOverflowContainer;
|
||||
private ViewState mGroupOverFlowState;
|
||||
|
||||
public NotificationChildrenContainer(Context context) {
|
||||
this(context, null);
|
||||
@@ -69,6 +80,8 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
mNotificationHeaderHeight = getResources().getDimensionPixelSize(
|
||||
R.dimen.notification_header_height);
|
||||
mHeaderTopPaddingSubstraction = 2 * getResources().getDisplayMetrics().density;
|
||||
mCollapsedBottompadding = 10 * getResources().getDisplayMetrics().density;
|
||||
mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,14 +91,6 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View child = mChildren.get(i);
|
||||
boolean viewGone = child.getVisibility() == View.GONE;
|
||||
if (i != 0) {
|
||||
View divider = mDividers.get(i - 1);
|
||||
int dividerVisibility = divider.getVisibility();
|
||||
int newVisibility = viewGone ? INVISIBLE : VISIBLE;
|
||||
if (dividerVisibility != newVisibility) {
|
||||
divider.setVisibility(newVisibility);
|
||||
}
|
||||
}
|
||||
if (viewGone) {
|
||||
continue;
|
||||
}
|
||||
@@ -96,6 +101,10 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
firstChild = false;
|
||||
}
|
||||
}
|
||||
if (mGroupOverflowContainer != null) {
|
||||
mGroupOverflowContainer.layout(0, 0, getWidth(),
|
||||
mGroupOverflowContainer.getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -115,9 +124,6 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
boolean firstChild = true;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View child = mChildren.get(i);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
child.measure(widthMeasureSpec, newHeightSpec);
|
||||
height += child.getMeasuredHeight();
|
||||
if (!firstChild) {
|
||||
@@ -130,9 +136,9 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
}
|
||||
}
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
height = hasFixedHeight ? ownMaxHeight
|
||||
: isHeightLimited ? Math.min(ownMaxHeight, height)
|
||||
: height;
|
||||
if (mGroupOverflowContainer != null) {
|
||||
mGroupOverflowContainer.measure(widthMeasureSpec, newHeightSpec);
|
||||
}
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
@@ -151,8 +157,7 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
addView(divider);
|
||||
mDividers.add(Math.max(newIndex - 1, 0), divider);
|
||||
}
|
||||
// TODO: adapt background corners
|
||||
// TODO: fix overdraw
|
||||
updateGroupOverflow();
|
||||
}
|
||||
|
||||
public void removeNotification(ExpandableNotificationRow row) {
|
||||
@@ -164,7 +169,26 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
removeView(divider);
|
||||
}
|
||||
row.setSystemChildExpanded(false);
|
||||
// TODO: adapt background corners
|
||||
updateGroupOverflow();
|
||||
}
|
||||
|
||||
public void updateGroupOverflow() {
|
||||
int childCount = mChildren.size();
|
||||
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
|
||||
boolean hasOverflow = childCount > maxAllowedVisibleChildren;
|
||||
int lastVisibleIndex = hasOverflow ? maxAllowedVisibleChildren - 2
|
||||
: maxAllowedVisibleChildren - 1;
|
||||
if (hasOverflow) {
|
||||
mGroupOverflowContainer = mHybridViewManager.bindFromNotificationGroup(
|
||||
mGroupOverflowContainer, mChildren, lastVisibleIndex + 1);
|
||||
if (mGroupOverFlowState == null) {
|
||||
mGroupOverFlowState = new ViewState();
|
||||
}
|
||||
} else if (mGroupOverflowContainer != null) {
|
||||
removeView(mGroupOverflowContainer);
|
||||
mGroupOverflowContainer = null;
|
||||
mGroupOverFlowState = null;
|
||||
}
|
||||
}
|
||||
|
||||
private View inflateDivider() {
|
||||
@@ -196,25 +220,42 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's make the first child expanded!
|
||||
boolean first = true;
|
||||
for (int i = 0; i < childOrder.size(); i++) {
|
||||
ExpandableNotificationRow child = childOrder.get(i);
|
||||
child.setSystemChildExpanded(first);
|
||||
first = false;
|
||||
}
|
||||
updateExpansionStates();
|
||||
return result;
|
||||
}
|
||||
|
||||
private void updateExpansionStates() {
|
||||
// Let's make the first child expanded if the parent is
|
||||
for (int i = 0; i < mChildren.size(); i++) {
|
||||
ExpandableNotificationRow child = mChildren.get(i);
|
||||
child.setSystemChildExpanded(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the intrinsic size of this children container, i.e the natural fully expanded state
|
||||
*/
|
||||
public int getIntrinsicHeight() {
|
||||
int childCount = mChildren.size();
|
||||
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
|
||||
return getIntrinsicHeight(maxAllowedVisibleChildren);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the intrinsic height with a number of children given
|
||||
* in @param maxAllowedVisibleChildren
|
||||
*/
|
||||
private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
|
||||
int intrinsicHeight = 0;
|
||||
int visibleChildren = 0;
|
||||
int childCount = mChildren.size();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
if (visibleChildren >= maxAllowedVisibleChildren) {
|
||||
break;
|
||||
}
|
||||
ExpandableNotificationRow child = mChildren.get(i);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
if (i == 0 && child.hasSameBgColor(mNotificationParent)) {
|
||||
intrinsicHeight -= mHeaderTopPaddingSubstraction;
|
||||
}
|
||||
intrinsicHeight += child.getIntrinsicHeight();
|
||||
visibleChildren++;
|
||||
@@ -222,6 +263,9 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
if (visibleChildren > 0) {
|
||||
intrinsicHeight += (visibleChildren - 1) * mDividerHeight;
|
||||
}
|
||||
if (!mChildrenExpanded) {
|
||||
intrinsicHeight += mCollapsedBottompadding;
|
||||
}
|
||||
return intrinsicHeight;
|
||||
}
|
||||
|
||||
@@ -235,15 +279,21 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
int childCount = mChildren.size();
|
||||
int yPosition = mNotificationHeaderHeight;
|
||||
boolean firstChild = true;
|
||||
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
|
||||
boolean hasOverflow = !mChildrenExpanded && childCount > maxAllowedVisibleChildren
|
||||
&& maxAllowedVisibleChildren != NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
|
||||
int lastVisibleIndex = hasOverflow
|
||||
? maxAllowedVisibleChildren - 2
|
||||
: maxAllowedVisibleChildren - 1;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
ExpandableNotificationRow child = mChildren.get(i);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
if (!firstChild) {
|
||||
// There's a divider
|
||||
yPosition += mChildPadding;
|
||||
} else {
|
||||
if (child.hasSameBgColor(mNotificationParent)) {
|
||||
yPosition -= mHeaderTopPaddingSubstraction;
|
||||
}
|
||||
firstChild = false;
|
||||
}
|
||||
StackViewState childState = resultState.getViewStateForView(child);
|
||||
@@ -255,37 +305,62 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
childState.dark = parentState.dark;
|
||||
childState.hideSensitive = parentState.hideSensitive;
|
||||
childState.belowSpeedBump = parentState.belowSpeedBump;
|
||||
childState.scale = parentState.scale;
|
||||
childState.scale = 1.0f;
|
||||
childState.clipTopAmount = 0;
|
||||
childState.topOverLap = 0;
|
||||
boolean visible = i <= lastVisibleIndex;
|
||||
childState.alpha = visible ? 1 : 0;
|
||||
childState.location = parentState.location;
|
||||
yPosition += intrinsicHeight;
|
||||
}
|
||||
if (mGroupOverflowContainer != null) {
|
||||
mGroupOverFlowState.initFrom(mGroupOverflowContainer);
|
||||
if (hasOverflow) {
|
||||
StackViewState firstOverflowState =
|
||||
resultState.getViewStateForView(mChildren.get(lastVisibleIndex + 1));
|
||||
mGroupOverFlowState.yTranslation = firstOverflowState.yTranslation;
|
||||
}
|
||||
mGroupOverFlowState.alpha = mChildrenExpanded || !hasOverflow ? 0.0f : 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
private int getMaxAllowedVisibleChildren() {
|
||||
return getMaxAllowedVisibleChildren(false /* likeCollapsed */);
|
||||
}
|
||||
|
||||
private int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
|
||||
if (!likeCollapsed && (mChildrenExpanded || mNotificationParent.isUserLocked())) {
|
||||
return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
|
||||
}
|
||||
if (mNotificationParent.isExpanded()) {
|
||||
return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED;
|
||||
}
|
||||
return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
|
||||
}
|
||||
|
||||
public void applyState(StackScrollState state) {
|
||||
int childCount = mChildren.size();
|
||||
boolean firstChild = true;
|
||||
ViewState dividerState = new ViewState();
|
||||
ViewState tmpState = new ViewState();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
ExpandableNotificationRow child = mChildren.get(i);
|
||||
StackViewState viewState = state.getViewStateForView(child);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
if (!firstChild) {
|
||||
// layout the divider
|
||||
View divider = mDividers.get(i - 1);
|
||||
dividerState.initFrom(divider);
|
||||
dividerState.yTranslation = (int) (viewState.yTranslation
|
||||
tmpState.initFrom(divider);
|
||||
tmpState.yTranslation = (int) (viewState.yTranslation
|
||||
- (mChildPadding + mDividerHeight) / 2.0f);
|
||||
dividerState.alpha = 1;
|
||||
state.applyViewState(divider, dividerState);
|
||||
tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
|
||||
state.applyViewState(divider, tmpState);
|
||||
} else {
|
||||
firstChild = false;
|
||||
}
|
||||
state.applyState(child, viewState);
|
||||
}
|
||||
if (mGroupOverflowContainer != null) {
|
||||
state.applyViewState(mGroupOverflowContainer, mGroupOverFlowState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -295,6 +370,10 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
* @param state the new state we animate to
|
||||
*/
|
||||
public void prepareExpansionChanged(StackScrollState state) {
|
||||
if (true) {
|
||||
// TODO: do something that makes sense
|
||||
return;
|
||||
}
|
||||
int childCount = mChildren.size();
|
||||
boolean firstChild = true;
|
||||
StackViewState sourceState = new StackViewState();
|
||||
@@ -302,9 +381,6 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
ExpandableNotificationRow child = mChildren.get(i);
|
||||
StackViewState viewState = state.getViewStateForView(child);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
if (!firstChild) {
|
||||
// layout the divider
|
||||
View divider = mDividers.get(i - 1);
|
||||
@@ -321,23 +397,17 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
sourceState.yTranslation += mNotificationAppearDistance;
|
||||
state.applyState(child, sourceState);
|
||||
}
|
||||
mCollapseButton.setAlpha(0);
|
||||
mCollapseDivider.setAlpha(0);
|
||||
mCollapseDivider.setTranslationY(mNotificationAppearDistance / 4);
|
||||
}
|
||||
|
||||
public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator,
|
||||
boolean withDelays, long baseDelay, long duration) {
|
||||
int childCount = mChildren.size();
|
||||
boolean firstChild = true;
|
||||
ViewState dividerState = new ViewState();
|
||||
ViewState tmpState = new ViewState();
|
||||
int notGoneIndex = 0;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
ExpandableNotificationRow child = mChildren.get(i);
|
||||
StackViewState viewState = state.getViewStateForView(child);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
int difference = Math.min(StackStateAnimator.DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN,
|
||||
notGoneIndex + 1);
|
||||
long delay = withDelays
|
||||
@@ -347,17 +417,20 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
if (!firstChild) {
|
||||
// layout the divider
|
||||
View divider = mDividers.get(i - 1);
|
||||
dividerState.initFrom(divider);
|
||||
dividerState.yTranslation = viewState.yTranslation
|
||||
tmpState.initFrom(divider);
|
||||
tmpState.yTranslation = viewState.yTranslation
|
||||
- (mChildPadding + mDividerHeight) / 2.0f;
|
||||
dividerState.alpha = 1;
|
||||
stateAnimator.startViewAnimations(divider, dividerState, delay, duration);
|
||||
tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;;
|
||||
stateAnimator.startViewAnimations(divider, tmpState, delay, duration);
|
||||
} else {
|
||||
firstChild = false;
|
||||
}
|
||||
stateAnimator.startStackAnimations(child, viewState, state, -1, delay);
|
||||
notGoneIndex++;
|
||||
}
|
||||
if (mGroupOverflowContainer != null) {
|
||||
stateAnimator.startViewAnimations(mGroupOverflowContainer, mGroupOverFlowState, -1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public ExpandableNotificationRow getViewAtPosition(float y) {
|
||||
@@ -375,7 +448,15 @@ public class NotificationChildrenContainer extends ViewGroup {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setTintColor(int color) {
|
||||
ExpandableNotificationRow.applyTint(mCollapseDivider, color);
|
||||
public void setChildrenExpanded(boolean childrenExpanded) {
|
||||
mChildrenExpanded = childrenExpanded;
|
||||
}
|
||||
|
||||
public int getMaxContentHeight() {
|
||||
return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
|
||||
}
|
||||
|
||||
public int getMinHeight() {
|
||||
return getIntrinsicHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1726,7 +1726,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
ExpandableNotificationRow groupSummary =
|
||||
mGroupManager.getGroupSummary(row.getStatusBarNotification());
|
||||
if (groupSummary != null && groupSummary != row) {
|
||||
return !groupSummary.areChildrenExpanded();
|
||||
return row.getVisibility() == View.INVISIBLE;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -2799,10 +2799,6 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
onHeightChanged(changedRow, false /* needsAnimation */);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupsProhibitedChanged() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
|
||||
for (NotificationData.Entry entry : group.children) {
|
||||
|
||||
@@ -361,7 +361,7 @@ public class StackScrollAlgorithm {
|
||||
// handle the notgoneIndex for the children as well
|
||||
List<ExpandableNotificationRow> children =
|
||||
row.getNotificationChildren();
|
||||
if (row.areChildrenExpanded() && children != null) {
|
||||
if (row.isSummaryWithChildren() && children != null) {
|
||||
for (ExpandableNotificationRow childRow : children) {
|
||||
if (childRow.getVisibility() != View.GONE) {
|
||||
StackViewState childState
|
||||
|
||||
@@ -65,7 +65,7 @@ public class StackScrollState {
|
||||
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
|
||||
List<ExpandableNotificationRow> children =
|
||||
row.getNotificationChildren();
|
||||
if (row.areChildrenExpanded() && children != null) {
|
||||
if (row.isSummaryWithChildren() && children != null) {
|
||||
for (ExpandableNotificationRow childRow : children) {
|
||||
resetViewState(childRow);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user