diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d1226f225ed07..056aff04375e0 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4962,9 +4962,6 @@ public class Notification implements Parcelable
*/
public static class BigTextStyle extends Style {
- private static final int MAX_LINES = 13;
- private static final int LINES_CONSUMED_BY_ACTIONS = 4;
-
private CharSequence mBigText;
public BigTextStyle() {
@@ -5070,18 +5067,8 @@ public class Notification implements Parcelable
builder.setTextViewColorSecondary(contentView, R.id.big_text);
contentView.setViewVisibility(R.id.big_text,
TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
- contentView.setInt(R.id.big_text, "setMaxLines", calculateMaxLines(builder));
contentView.setBoolean(R.id.big_text, "setHasImage", builder.mN.hasLargeIcon());
}
-
- private static int calculateMaxLines(Builder builder) {
- int lineCount = MAX_LINES;
- boolean hasActions = builder.mActions.size() > 0;
- if (hasActions) {
- lineCount -= LINES_CONSUMED_BY_ACTIONS;
- }
- return lineCount;
- }
}
/**
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index a5d2bf3b68d3c..80207ee854b8f 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -42,6 +42,10 @@ public class ImageFloatingTextView extends TextView {
/** Resolved layout direction */
private int mResolvedDirection = LAYOUT_DIRECTION_UNDEFINED;
+ private int mMaxLinesForHeight = -1;
+ private boolean mFirstMeasure = true;
+ private int mLayoutMaxLines = -1;
+ private boolean mBlockLayouts;
public ImageFloatingTextView(Context context) {
this(context, null);
@@ -72,8 +76,15 @@ public class ImageFloatingTextView extends TextView {
.setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
.setIncludePad(getIncludeFontPadding())
.setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
- .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL)
- .setMaxLines(getMaxLines() >= 0 ? getMaxLines() : Integer.MAX_VALUE);
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
+ int maxLines;
+ if (mMaxLinesForHeight > 0) {
+ maxLines = mMaxLinesForHeight;
+ } else {
+ maxLines = getMaxLines() >= 0 ? getMaxLines() : Integer.MAX_VALUE;
+ }
+ builder.setMaxLines(maxLines);
+ mLayoutMaxLines = maxLines;
if (shouldEllipsize) {
builder.setEllipsize(effectiveEllipsize)
.setEllipsizedWidth(ellipsisWidth);
@@ -98,6 +109,34 @@ public class ImageFloatingTextView extends TextView {
return builder.build();
}
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int height = MeasureSpec.getSize(heightMeasureSpec);
+ // Lets calculate how many lines the given measurement allows us.
+ int availableHeight = height - mPaddingTop - mPaddingBottom;
+ int maxLines = availableHeight / getLineHeight();
+ if (getMaxLines() > 0) {
+ maxLines = Math.min(getMaxLines(), maxLines);
+ }
+ if (maxLines != mMaxLinesForHeight) {
+ mMaxLinesForHeight = maxLines;
+ if (getLayout() != null && mMaxLinesForHeight != mLayoutMaxLines) {
+ // Invalidate layout.
+ mBlockLayouts = true;
+ setHint(getHint());
+ mBlockLayouts = false;
+ }
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ public void requestLayout() {
+ if (!mBlockLayouts) {
+ super.requestLayout();
+ }
+ }
+
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index cb123a13ad1da..b259ad1643f84 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -36,6 +36,7 @@ import android.widget.RemoteViews;
@RemoteViews.RemoteView
public class MessagingLinearLayout extends ViewGroup {
+ private static final int NOT_MEASURED_BEFORE = -1;
/**
* Spacing to be applied between views.
*/
@@ -52,6 +53,11 @@ public class MessagingLinearLayout extends ViewGroup {
* Id of the child that's also visible in the contracted layout.
*/
private int mContractedChildId;
+ /**
+ * The last measured with in a layout pass if it was measured before or
+ * {@link #NOT_MEASURED_BEFORE} if this is the first layout pass.
+ */
+ private int mLastMeasuredWidth = NOT_MEASURED_BEFORE;
public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -64,20 +70,12 @@ public class MessagingLinearLayout extends ViewGroup {
for (int i = 0; i < N; i++) {
int attr = a.getIndex(i);
switch (attr) {
- case R.styleable.MessagingLinearLayout_maxHeight:
- mMaxHeight = a.getDimensionPixelSize(i, 0);
- break;
case R.styleable.MessagingLinearLayout_spacing:
mSpacing = a.getDimensionPixelSize(i, 0);
break;
}
}
- if (mMaxHeight <= 0) {
- throw new IllegalStateException(
- "MessagingLinearLayout: Must specify positive maxHeight");
- }
-
a.recycle();
}
@@ -86,62 +84,63 @@ public class MessagingLinearLayout extends ViewGroup {
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// This is essentially a bottom-up linear layout that only adds children that fit entirely
// up to a maximum height.
-
+ int targetHeight = MeasureSpec.getSize(heightMeasureSpec);
switch (MeasureSpec.getMode(heightMeasureSpec)) {
- case MeasureSpec.AT_MOST:
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- Math.min(mMaxHeight, MeasureSpec.getSize(heightMeasureSpec)),
- MeasureSpec.AT_MOST);
- break;
case MeasureSpec.UNSPECIFIED:
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(
- mMaxHeight,
- MeasureSpec.AT_MOST);
- break;
- case MeasureSpec.EXACTLY:
+ targetHeight = Integer.MAX_VALUE;
break;
}
- final int targetHeight = MeasureSpec.getSize(heightMeasureSpec);
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ boolean recalculateVisibility = mLastMeasuredWidth == NOT_MEASURED_BEFORE
+ || getMeasuredHeight() != targetHeight
+ || mLastMeasuredWidth != widthSize;
+
final int count = getChildCount();
-
- for (int i = 0; i < count; ++i) {
- final View child = getChildAt(i);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.hide = true;
- }
-
- int totalHeight = mPaddingTop + mPaddingBottom;
- boolean first = true;
-
- // Starting from the bottom: we measure every view as if it were the only one. If it still
- // fits, we take it, otherwise we stop there.
- for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
- if (getChildAt(i).getVisibility() == GONE) {
- continue;
- }
- final View child = getChildAt(i);
- LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
-
- if (child instanceof ImageFloatingTextView) {
- // Pretend we need the image padding for all views, we don't know which
- // one will end up needing to do this (might end up not using all the space,
- // but calculating this exactly would be more expensive).
- ((ImageFloatingTextView) child).setNumIndentLines(
- mIndentLines == 2 ? 3 : mIndentLines);
+ if (recalculateVisibility) {
+ // We only need to recalculate the view visibilities if the view wasn't measured already
+ // in this pass, otherwise we may drop messages here already since we are measured
+ // exactly with what we returned before, which was optimized already with the
+ // line-indents.
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.hide = true;
}
- measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+ int totalHeight = mPaddingTop + mPaddingBottom;
+ boolean first = true;
- final int childHeight = child.getMeasuredHeight();
- int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
- lp.bottomMargin + (first ? 0 : mSpacing));
- first = false;
+ // Starting from the bottom: we measure every view as if it were the only one. If it still
- if (newHeight <= targetHeight) {
- totalHeight = newHeight;
- lp.hide = false;
- } else {
- break;
+ // fits, we take it, otherwise we stop there.
+ for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
+ if (getChildAt(i).getVisibility() == GONE) {
+ continue;
+ }
+ final View child = getChildAt(i);
+ LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+
+ if (child instanceof ImageFloatingTextView) {
+ // Pretend we need the image padding for all views, we don't know which
+ // one will end up needing to do this (might end up not using all the space,
+ // but calculating this exactly would be more expensive).
+ ((ImageFloatingTextView) child).setNumIndentLines(
+ mIndentLines == 2 ? 3 : mIndentLines);
+ }
+
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
+
+ final int childHeight = child.getMeasuredHeight();
+ int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
+ lp.bottomMargin + (first ? 0 : mSpacing));
+ first = false;
+
+ if (newHeight <= targetHeight) {
+ totalHeight = newHeight;
+ lp.hide = false;
+ } else {
+ break;
+ }
}
}
@@ -149,8 +148,8 @@ public class MessagingLinearLayout extends ViewGroup {
int measuredWidth = mPaddingLeft + mPaddingRight;
int imageLines = mIndentLines;
// Need to redo the height because it may change due to changing indents.
- totalHeight = mPaddingTop + mPaddingBottom;
- first = true;
+ int totalHeight = mPaddingTop + mPaddingBottom;
+ boolean first = true;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -168,7 +167,7 @@ public class MessagingLinearLayout extends ViewGroup {
imageLines = 3;
}
boolean changed = textChild.setNumIndentLines(Math.max(0, imageLines));
- if (changed) {
+ if (changed || !recalculateVisibility) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
}
imageLines -= textChild.getLineCount();
@@ -188,6 +187,7 @@ public class MessagingLinearLayout extends ViewGroup {
widthMeasureSpec),
resolveSize(Math.max(getSuggestedMinimumHeight(), totalHeight),
heightMeasureSpec));
+ mLastMeasuredWidth = widthSize;
}
@Override
@@ -236,6 +236,7 @@ public class MessagingLinearLayout extends ViewGroup {
first = false;
}
+ mLastMeasuredWidth = NOT_MEASURED_BEFORE;
}
@Override
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index f4f783ecc6fb3..1aca99feb872f 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -48,12 +48,11 @@
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index 07b1100ee93b6..b91021172f90a 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -50,8 +50,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/notification_content_margin_bottom"
- android:spacing="@dimen/notification_messaging_spacing"
- android:maxHeight="165dp">
+ android:spacing="@dimen/notification_messaging_spacing" >
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 34f78f3947bb8..f1f3409a2a248 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8355,7 +8355,6 @@
-