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