Merge changes Ia9502056,I97dc60c4 into nyc-dev
* changes:
Fixed the group expand motion to better reflect the overflow
Introduced a number indicating more children in a group
diff --git a/packages/SystemUI/res/layout/hybrid_notification.xml b/packages/SystemUI/res/layout/hybrid_notification.xml
index f667859..476f52b 100644
--- a/packages/SystemUI/res/layout/hybrid_notification.xml
+++ b/packages/SystemUI/res/layout/hybrid_notification.xml
@@ -21,7 +21,7 @@
android:layout_height="wrap_content"
android:paddingStart="@*android:dimen/notification_content_margin_start"
android:paddingEnd="12dp"
- android:gravity="bottom">
+ android:gravity="bottom|start">
<TextView
android:id="@+id/notification_title"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/hybrid_overflow_number.xml b/packages/SystemUI/res/layout/hybrid_overflow_number.xml
new file mode 100644
index 0000000..f3dde8d
--- /dev/null
+++ b/packages/SystemUI/res/layout/hybrid_overflow_number.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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
+ -->
+<TextView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/notification_text"
+ 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:gravity="end"
+ android:singleLine="true"
+ />
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 5295ccb..2bde141 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -570,6 +570,9 @@
<!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
<string name="accessibility_clear_all">Clear all notifications.</string>
+ <!-- The overflow indicator shown when a group has more notification inside the group than the visible ones. An example is "+ 3" [CHAR LIMIT=5] -->
+ <string name="notification_group_overflow_indicator">+ <xliff:g id="number" example="3">%s</xliff:g></string>
+
<!-- Content description of button in notification inspector for system settings relating to
notifications from this application [CHAR LIMIT=NONE] -->
<string name="status_bar_notification_inspect_item_title">Notification settings</string>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index a3af0a4..2446535 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -43,6 +43,7 @@
import com.android.systemui.R;
import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -227,6 +228,7 @@
updateClearability();
if (mIsSummaryWithChildren) {
recreateNotificationHeader();
+ mChildrenContainer.onNotificationUpdated();
}
if (mIconAnimationRunning) {
setIconAnimationRunning(true);
@@ -584,6 +586,29 @@
mPublicLayout.closeRemoteInput();
}
+ /**
+ * Set by how much the single line view should be indented.
+ */
+ public void setSingleLineWidthIndention(int indention) {
+ mPrivateLayout.setSingleLineWidthIndention(indention);
+ }
+
+ public int getNotificationColor() {
+ int color = getStatusBarNotification().getNotification().color;
+ if (color == Notification.COLOR_DEFAULT) {
+ return mContext.getColor(com.android.internal.R.color.notification_icon_default_color);
+ }
+ return color;
+ }
+
+ public HybridNotificationView getSingleLineView() {
+ return mPrivateLayout.getSingleLineView();
+ }
+
+ public boolean isOnKeyguard() {
+ return mOnKeyguard;
+ }
+
public interface ExpansionLogger {
public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
}
@@ -677,6 +702,7 @@
public void onInflate(ViewStub stub, View inflated) {
mChildrenContainer = (NotificationChildrenContainer) inflated;
mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
+ mChildrenContainer.onNotificationUpdated();
mTranslateableViews.add(mChildrenContainer);
}
});
@@ -858,6 +884,7 @@
showing.setDark(dark, fade, delay);
}
if (mIsSummaryWithChildren) {
+ mChildrenContainer.setDark(dark, fade, delay);
mNotificationHeaderWrapper.setDark(dark, fade, delay);
}
}
@@ -954,6 +981,9 @@
mIsSystemExpanded = expand;
notifyHeightChanged(false /* needsAnimation */);
logExpansionEvent(false, wasExpanded);
+ if (mChildrenContainer != null) {
+ mChildrenContainer.updateGroupOverflow();
+ }
}
}
@@ -966,6 +996,9 @@
mOnKeyguard = onKeyguard;
logExpansionEvent(false, wasExpanded);
if (wasExpanded != isExpanded()) {
+ if (mIsSummaryWithChildren) {
+ mChildrenContainer.updateGroupOverflow();
+ }
notifyHeightChanged(false /* needsAnimation */);
}
}
@@ -1260,7 +1293,7 @@
@Override
public int getMinExpandHeight() {
if (mIsSummaryWithChildren && !mShowingPublic) {
- return mChildrenContainer.getMinExpandHeight(mOnKeyguard);
+ return mChildrenContainer.getMinExpandHeight();
}
return getMinHeight();
}
@@ -1347,7 +1380,7 @@
if (isGroupExpanded()) {
return 1.0f;
} else if (isUserLocked()) {
- return mChildrenContainer.getChildExpandFraction();
+ return mChildrenContainer.getGroupExpandFraction();
}
}
return 0.0f;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index c2df292..0a41e42 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -31,7 +31,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.notification.HybridNotificationView;
-import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
+import com.android.systemui.statusbar.notification.HybridGroupManager;
import com.android.systemui.statusbar.notification.NotificationCustomViewWrapper;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.notification.NotificationViewWrapper;
@@ -75,7 +75,7 @@
private NotificationViewWrapper mContractedWrapper;
private NotificationViewWrapper mExpandedWrapper;
private NotificationViewWrapper mHeadsUpWrapper;
- private HybridNotificationViewManager mHybridViewManager;
+ private HybridGroupManager mHybridGroupManager;
private int mClipTopAmount;
private int mContentHeight;
private int mUnrestrictedContentHeight;
@@ -116,10 +116,11 @@
private ExpandableNotificationRow mContainingNotification;
private int mTransformationStartVisibleType;
private boolean mUserExpanding;
+ private int mSingleLineWidthIndention;
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
- mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
+ mHybridGroupManager = new HybridGroupManager(getContext(), this);
mMinContractedHeight = getResources().getDimensionPixelSize(
R.dimen.min_notification_layout_height);
mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
@@ -139,6 +140,7 @@
boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
boolean isHeightLimited = heightMode == MeasureSpec.AT_MOST;
int maxSize = Integer.MAX_VALUE;
+ int width = MeasureSpec.getSize(widthMeasureSpec);
if (hasFixedHeight || isHeightLimited) {
maxSize = MeasureSpec.getSize(heightMeasureSpec);
}
@@ -187,12 +189,18 @@
maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
}
if (mSingleLineView != null) {
- mSingleLineView.measure(widthMeasureSpec,
+ int singleLineWidthSpec = widthMeasureSpec;
+ if (mSingleLineWidthIndention != 0
+ && MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED) {
+ singleLineWidthSpec = MeasureSpec.makeMeasureSpec(
+ width - mSingleLineWidthIndention + mSingleLineView.getPaddingEnd(),
+ MeasureSpec.AT_MOST);
+ }
+ mSingleLineView.measure(singleLineWidthSpec,
MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
}
int ownHeight = Math.min(maxChildHeight, maxSize);
- int width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, ownHeight);
}
@@ -715,7 +723,7 @@
private void updateSingleLineView() {
if (mIsChildInGroup) {
- mSingleLineView = mHybridViewManager.bindFromNotification(
+ mSingleLineView = mHybridGroupManager.bindFromNotification(
mSingleLineView, mStatusBarNotification.getNotification());
} else if (mSingleLineView != null) {
removeView(mSingleLineView);
@@ -878,4 +886,20 @@
updateBackgroundColor(false);
}
}
+
+ /**
+ * Set by how much the single line view should be indented. Used when a overflow indicator is
+ * present and only during measuring
+ */
+ public void setSingleLineWidthIndention(int singleLineWidthIndention) {
+ if (singleLineWidthIndention != mSingleLineWidthIndention) {
+ mSingleLineWidthIndention = singleLineWidthIndention;
+ mContainingNotification.forceLayout();
+ forceLayout();
+ }
+ }
+
+ public HybridNotificationView getSingleLineView() {
+ return mSingleLineView;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
new file mode 100644
index 0000000..8f2c81f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridGroupManager.java
@@ -0,0 +1,117 @@
+/*
+ * 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.BidiFormatter;
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
+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
+ * group overflow.
+ */
+public class HybridGroupManager {
+
+ private final Context mContext;
+ private ViewGroup mParent;
+ private int mOverflowNumberColor;
+
+ public HybridGroupManager(Context ctx, ViewGroup parent) {
+ mContext = ctx;
+ mParent = parent;
+ }
+
+ 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;
+ }
+
+ private TextView inflateOverflowNumber() {
+ LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+ TextView numberView = (TextView) inflater.inflate(
+ R.layout.hybrid_overflow_number, mParent, false);
+ mParent.addView(numberView);
+ updateOverFlowNumberColor(numberView);
+ return numberView;
+ }
+
+ private void updateOverFlowNumberColor(TextView numberView) {
+ numberView.setTextColor(mOverflowNumberColor);
+ }
+
+ public void setOverflowNumberColor(TextView numberView, int overflowNumberColor) {
+ mOverflowNumberColor = overflowNumberColor;
+ if (numberView != null) {
+ updateOverFlowNumberColor(numberView);
+ }
+ }
+
+ public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
+ Notification notification) {
+ if (reusableView == null) {
+ reusableView = inflateHybridView();
+ }
+ CharSequence titleText = resolveTitle(notification);
+ CharSequence contentText = resolveText(notification);
+ reusableView.bind(titleText, contentText);
+ return reusableView;
+ }
+
+ private CharSequence resolveText(Notification notification) {
+ CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
+ if (contentText == null) {
+ contentText = notification.extras.getCharSequence(Notification.EXTRA_BIG_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 TextView bindOverflowNumber(TextView reusableView, int number) {
+ if (reusableView == null) {
+ reusableView = inflateOverflowNumber();
+ }
+ String text = mContext.getResources().getString(
+ R.string.notification_group_overflow_indicator, number);
+ if (!text.equals(reusableView.getText())) {
+ reusableView.setText(text);
+ }
+ return reusableView;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
index c80cad8..0a1795f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -60,6 +60,14 @@
super(context, attrs, defStyleAttr, defStyleRes);
}
+ public TextView getTitleView() {
+ return mTitleView;
+ }
+
+ public TextView getTextView() {
+ return mTextView;
+ }
+
@Override
protected void onFinishInflate() {
super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java
deleted file mode 100644
index a17501d..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.view.LayoutInflater;
-import android.view.ViewGroup;
-
-import com.android.systemui.R;
-
-/**
- * A class managing {@link HybridNotificationView} views
- */
-public class HybridNotificationViewManager {
-
- private final Context mContext;
- private ViewGroup mParent;
- private String mDivider;
-
- public HybridNotificationViewManager(Context ctx, ViewGroup parent) {
- mContext = ctx;
- mParent = parent;
- mDivider = " • ";
- }
-
- 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) {
- if (reusableView == null) {
- reusableView = inflateHybridView();
- }
- CharSequence titleText = resolveTitle(notification);
- CharSequence contentText = resolveText(notification);
- reusableView.bind(titleText, contentText);
- return reusableView;
- }
-
- private CharSequence resolveText(Notification notification) {
- CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
- if (contentText == null) {
- contentText = notification.extras.getCharSequence(Notification.EXTRA_BIG_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;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 6ef61ec..844a2c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -17,15 +17,19 @@
package com.android.systemui.statusbar.notification;
import android.graphics.Color;
+import android.view.View;
import android.widget.ImageView;
import com.android.internal.util.NotificationColorUtil;
import com.android.systemui.R;
+import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
/**
* A util class for various reusable functions
*/
public class NotificationUtils {
+ private static final int[] sLocationBase = new int[2];
+ private static final int[] sLocationOffset = new int[2];
public static boolean isGrayscale(ImageView v, NotificationColorUtil colorUtil) {
Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
if (isGrayscale != null) {
@@ -47,4 +51,10 @@
(int) interpolate(Color.green(startColor), Color.green(endColor), amount),
(int) interpolate(Color.blue(startColor), Color.blue(endColor), amount));
}
+
+ public static float getRelativeYOffset(View offsetView, View baseView) {
+ baseView.getLocationOnScreen(sLocationBase);
+ offsetView.getLocationOnScreen(sLocationOffset);
+ return sLocationOffset[1] - sLocationBase[1];
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 176788b..dc567fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -22,13 +22,14 @@
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.ViewInvertHelper;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.notification.HybridGroupManager;
import com.android.systemui.statusbar.notification.HybridNotificationView;
-import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
import com.android.systemui.statusbar.notification.NotificationUtils;
import com.android.systemui.statusbar.phone.NotificationPanelView;
@@ -46,18 +47,22 @@
private final List<View> mDividers = new ArrayList<>();
private final List<ExpandableNotificationRow> mChildren = new ArrayList<>();
+ private final HybridGroupManager mHybridGroupManager;
private int mChildPadding;
private int mDividerHeight;
private int mMaxNotificationHeight;
private int mNotificationHeaderHeight;
private int mNotificatonTopPadding;
private float mCollapsedBottompadding;
+ private ViewInvertHelper mOverflowInvertHelper;
private boolean mChildrenExpanded;
private ExpandableNotificationRow mNotificationParent;
+ private TextView mOverflowNumber;
+ private ViewState mGroupOverFlowState;
private int mRealHeight;
- private int mLayoutDirection = LAYOUT_DIRECTION_UNDEFINED;
private boolean mUserLocked;
private int mActualHeight;
+ private boolean mNeverAppliedGroupState;
public NotificationChildrenContainer(Context context) {
this(context, null);
@@ -75,6 +80,7 @@
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initDimens();
+ mHybridGroupManager = new HybridGroupManager(getContext(), this);
}
private void initDimens() {
@@ -100,9 +106,13 @@
if (child.getVisibility() == View.GONE) {
continue;
}
- child.layout(0, 0, getWidth(), child.getMeasuredHeight());
+ child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
mDividers.get(i).layout(0, 0, getWidth(), mDividerHeight);
}
+ if (mOverflowNumber != null) {
+ mOverflowNumber.layout(getWidth() - mOverflowNumber.getMeasuredWidth(), 0, getWidth(),
+ mOverflowNumber.getMeasuredHeight());
+ }
}
@Override
@@ -116,11 +126,20 @@
ownMaxHeight = Math.min(ownMaxHeight, size);
}
int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+ if (mOverflowNumber != null) {
+ mOverflowNumber.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
+ newHeightSpec);
+ }
int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY);
int height = mNotificationHeaderHeight + mNotificatonTopPadding;
int childCount = Math.min(mChildren.size(), NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
+ int collapsedChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
+ int overflowIndex = childCount > collapsedChildren ? collapsedChildren - 1 : -1;
for (int i = 0; i < childCount; i++) {
- View child = mChildren.get(i);
+ ExpandableNotificationRow child = mChildren.get(i);
+ boolean isOverflow = i == overflowIndex;
+ child.setSingleLineWidthIndention(isOverflow ? mOverflowNumber.getMeasuredWidth() : 0);
child.measure(widthMeasureSpec, newHeightSpec);
height += child.getMeasuredHeight();
@@ -129,7 +148,6 @@
divider.measure(widthMeasureSpec, dividerHeightSpec);
height += mDividerHeight;
}
- int width = MeasureSpec.getSize(widthMeasureSpec);
mRealHeight = height;
if (heightMode != MeasureSpec.UNSPECIFIED) {
height = Math.min(height, size);
@@ -158,6 +176,8 @@
View divider = inflateDivider();
addView(divider);
mDividers.add(newIndex, divider);
+
+ updateGroupOverflow();
}
public void removeNotification(ExpandableNotificationRow row) {
@@ -177,15 +197,45 @@
row.setSystemChildExpanded(false);
row.setUserLocked(false);
+ updateGroupOverflow();
+ }
+
+ public void updateGroupOverflow() {
+ int childCount = mChildren.size();
+ int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
+ 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;
+ }
+ } else if (mOverflowNumber != null) {
+ removeView(mOverflowNumber);
+ if (isShown()) {
+ final View removedOverflowNumber = mOverflowNumber;
+ addTransientView(removedOverflowNumber, getTransientViewCount());
+ CrossFadeHelper.fadeOut(removedOverflowNumber, new Runnable() {
+ @Override
+ public void run() {
+ removeTransientView(removedOverflowNumber);
+ }
+ });
+ }
+ mOverflowNumber = null;
+ mOverflowInvertHelper = null;
+ mGroupOverFlowState = null;
+ }
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- int layoutDirection = getLayoutDirection();
- if (layoutDirection != mLayoutDirection) {
- mLayoutDirection = layoutDirection;
- }
+ updateGroupOverflow();
}
private View inflateDivider() {
@@ -253,7 +303,7 @@
boolean firstChild = true;
float expandFactor = 0;
if (mUserLocked) {
- expandFactor = getChildExpandFraction();
+ expandFactor = getGroupExpandFraction();
}
for (int i = 0; i < childCount; i++) {
if (visibleChildren >= maxAllowedVisibleChildren) {
@@ -304,9 +354,11 @@
boolean firstChild = true;
int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
int lastVisibleIndex = maxAllowedVisibleChildren - 1;
+ int firstOverflowIndex = lastVisibleIndex + 1;
float expandFactor = 0;
if (mUserLocked) {
- expandFactor = getChildExpandFraction();
+ expandFactor = getGroupExpandFraction();
+ firstOverflowIndex = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
}
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
@@ -339,11 +391,39 @@
childState.belowSpeedBump = parentState.belowSpeedBump;
childState.clipTopAmount = 0;
childState.topOverLap = 0;
- boolean visible = i <= lastVisibleIndex;
- childState.alpha = visible ? 1 : 0;
+ childState.alpha = 0;
+ if (i < firstOverflowIndex) {
+ childState.alpha = 1;
+ } else if (expandFactor == 1.0f && i <= lastVisibleIndex) {
+ childState.alpha = (mActualHeight - childState.yTranslation) / childState.height;
+ childState.alpha = Math.max(0.0f, Math.min(1.0f, childState.alpha));
+ }
childState.location = parentState.location;
yPosition += intrinsicHeight;
}
+ if (mOverflowNumber != null) {
+ 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 (mirrorView.getVisibility() == GONE) {
+ mirrorView = singleLineView.getTitleView();
+ }
+ if (mirrorView.getVisibility() == GONE) {
+ mirrorView = singleLineView;
+ }
+ mGroupOverFlowState.yTranslation += NotificationUtils.getRelativeYOffset(
+ mirrorView, overflowView);
+ mGroupOverFlowState.alpha = mirrorView.getAlpha();
+ }
+ } else {
+ mGroupOverFlowState.yTranslation += mNotificationHeaderHeight;
+ mGroupOverFlowState.alpha = 0.0f;
+ }
+ }
}
private int getMaxAllowedVisibleChildren() {
@@ -354,7 +434,8 @@
if (!likeCollapsed && (mChildrenExpanded || mNotificationParent.isUserLocked())) {
return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
}
- if (mNotificationParent.isExpanded() || mNotificationParent.isHeadsUp()) {
+ if (!mNotificationParent.isOnKeyguard()
+ && (mNotificationParent.isExpanded() || mNotificationParent.isHeadsUp())) {
return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED;
}
return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
@@ -363,7 +444,10 @@
public void applyState(StackScrollState state) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
- float expandFraction = getChildExpandFraction();
+ float expandFraction = 0.0f;
+ if (mUserLocked) {
+ expandFraction = getGroupExpandFraction();
+ }
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
@@ -375,13 +459,18 @@
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
if (mUserLocked && viewState.alpha != 0) {
- alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction);
+ alpha = NotificationUtils.interpolate(0, 0.5f,
+ Math.min(viewState.alpha, expandFraction));
}
tmpState.alpha = alpha;
state.applyViewState(divider, tmpState);
// There is no fake shadow to be drawn on the children
child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
}
+ if (mOverflowNumber != null) {
+ state.applyViewState(mOverflowNumber, mGroupOverFlowState);
+ mNeverAppliedGroupState = false;
+ }
}
/**
@@ -399,7 +488,7 @@
long baseDelay, long duration) {
int childCount = mChildren.size();
ViewState tmpState = new ViewState();
- float expandFraction = getChildExpandFraction();
+ float expandFraction = getGroupExpandFraction();
for (int i = childCount - 1; i >= 0; i--) {
ExpandableNotificationRow child = mChildren.get(i);
StackViewState viewState = state.getViewStateForView(child);
@@ -411,13 +500,25 @@
tmpState.yTranslation = viewState.yTranslation - mDividerHeight;
float alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
if (mUserLocked && viewState.alpha != 0) {
- alpha = NotificationUtils.interpolate(0, 0.5f, expandFraction);
+ alpha = NotificationUtils.interpolate(0, 0.5f,
+ Math.min(viewState.alpha, expandFraction));
}
tmpState.alpha = alpha;
stateAnimator.startViewAnimations(divider, tmpState, baseDelay, duration);
// There is no fake shadow to be drawn on the children
child.setFakeShadowIntensity(0.0f, 0.0f, 0, 0);
}
+ if (mOverflowNumber != null) {
+ if (mNeverAppliedGroupState) {
+ float alpha = mGroupOverFlowState.alpha;
+ mGroupOverFlowState.alpha = 0;
+ state.applyViewState(mOverflowNumber, mGroupOverFlowState);
+ mGroupOverFlowState.alpha = alpha;
+ mNeverAppliedGroupState = false;
+ }
+ stateAnimator.startViewAnimations(mOverflowNumber, mGroupOverFlowState,
+ baseDelay, duration);
+ }
}
public ExpandableNotificationRow getViewAtPosition(float y) {
@@ -470,44 +571,49 @@
return;
}
mActualHeight = actualHeight;
- float fraction = getChildExpandFraction();
+ float fraction = getGroupExpandFraction();
+ int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
int childCount = mChildren.size();
for (int i = 0; i < childCount; i++) {
ExpandableNotificationRow child = mChildren.get(i);
float childHeight = child.isExpanded(true /* allowOnKeyguard */)
? child.getMaxExpandHeight()
: child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
- float singleLineHeight = child.getShowingLayout().getMinHeight(
- false /* likeGroupExpanded */);
- child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight, childHeight,
- fraction), false);
+ if (i < maxAllowedVisibleChildren) {
+ float singleLineHeight = child.getShowingLayout().getMinHeight(
+ false /* likeGroupExpanded */);
+ child.setActualHeight((int) NotificationUtils.interpolate(singleLineHeight,
+ childHeight, fraction), false);
+ } else {
+ child.setActualHeight((int) childHeight, false);
+ }
}
}
- public float getChildExpandFraction() {
- int allChildrenVisibleHeight = getChildrenExpandStartHeight();
- int maxContentHeight = getMaxContentHeight();
- float factor = (mActualHeight - allChildrenVisibleHeight)
- / (float) (maxContentHeight - allChildrenVisibleHeight);
+ public float getGroupExpandFraction() {
+ int visibleChildrenExpandedHeight = getVisibleChildrenExpandHeight();
+ int minExpandHeight = getMinExpandHeight();
+ float factor = (mActualHeight - minExpandHeight)
+ / (float) (visibleChildrenExpandedHeight - minExpandHeight);
return Math.max(0.0f, Math.min(1.0f, factor));
}
- private int getChildrenExpandStartHeight() {
- int intrinsicHeight = mNotificationHeaderHeight;
+ private int getVisibleChildrenExpandHeight() {
+ int intrinsicHeight = mNotificationHeaderHeight + mNotificatonTopPadding + mDividerHeight;
int visibleChildren = 0;
int childCount = mChildren.size();
+ int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
for (int i = 0; i < childCount; i++) {
- if (visibleChildren >= NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED) {
+ if (visibleChildren >= maxAllowedVisibleChildren) {
break;
}
ExpandableNotificationRow child = mChildren.get(i);
- intrinsicHeight += child.getMinHeight();
+ float childHeight = child.isExpanded(true /* allowOnKeyguard */)
+ ? child.getMaxExpandHeight()
+ : child.getShowingLayout().getMinHeight(true /* likeGroupExpanded */);
+ intrinsicHeight += childHeight;
visibleChildren++;
}
- if (visibleChildren > 0) {
- intrinsicHeight += (visibleChildren - 1) * mChildPadding;
- }
- intrinsicHeight += mCollapsedBottompadding;
return intrinsicHeight;
}
@@ -515,9 +621,8 @@
return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
}
- public int getMinExpandHeight(boolean onKeyguard) {
- int maxAllowedVisibleChildren = onKeyguard ? NUMBER_OF_CHILDREN_WHEN_COLLAPSED
- : getMaxAllowedVisibleChildren(true /* forceCollapsed */);
+ public int getMinExpandHeight() {
+ int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* forceCollapsed */);
int minExpandHeight = mNotificationHeaderHeight;
int visibleChildren = 0;
boolean firstChild = true;
@@ -539,6 +644,12 @@
return minExpandHeight;
}
+ public void setDark(boolean dark, boolean fade, long delay) {
+ if (mOverflowNumber != null) {
+ mOverflowInvertHelper.setInverted(dark, fade, delay);
+ }
+ }
+
public void reInflateViews() {
initDimens();
for (int i = 0; i < mDividers.size(); i++) {
@@ -559,4 +670,9 @@
child.setUserLocked(userLocked);
}
}
+
+ public void onNotificationUpdated() {
+ mHybridGroupManager.setOverflowNumberColor(mOverflowNumber,
+ mNotificationParent.getNotificationColor());
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index cf4802d..dba5bbd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -972,10 +972,10 @@
}
/**
- * Get the end value of the height animation running on a view or the actualHeight
+ * Get the end value of the yTranslation animation running on a view or the yTranslation
* if no animation is running.
*/
- public static float getFinalTranslationY(ExpandableView view) {
+ public static float getFinalTranslationY(View view) {
if (view == null) {
return 0;
}