Fixed measuring of messages with excess space
Sometimes the layout was measured too big, with additional
white space that wasn't needed because of the way excess
space was handled.
Test: manual write 3 single line messages and 2 two line
Bug: 63708826
Change-Id: I09e728e87e316cb770d5c65bf355a68848e58f0b
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index f33efff..f0ef370 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -36,7 +36,6 @@
@RemoteViews.RemoteView
public class MessagingLinearLayout extends ViewGroup {
- private static final int NOT_MEASURED_BEFORE = -1;
/**
* Spacing to be applied between views.
*/
@@ -44,15 +43,6 @@
private int mMaxDisplayedLines = Integer.MAX_VALUE;
- /**
- * 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;
private MessagingLayout mMessagingLayout;
public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) {
@@ -86,79 +76,67 @@
break;
}
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- boolean recalculateVisibility = mLastMeasuredWidth == NOT_MEASURED_BEFORE
- || getMeasuredHeight() != targetHeight
- || mLastMeasuredWidth != widthSize;
// Now that we know which views to take, fix up the indents and see what width we get.
int measuredWidth = mPaddingLeft + mPaddingRight;
final int count = getChildCount();
- int totalHeight = getMeasuredHeight();
- 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;
+ int totalHeight;
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ lp.hide = true;
+ }
+
+ totalHeight = mPaddingTop + mPaddingBottom;
+ boolean first = true;
+ int linesRemaining = mMaxDisplayedLines;
+
+ // 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();
+ MessagingChild messagingChild = null;
+ if (child instanceof MessagingChild) {
+ messagingChild = (MessagingChild) child;
+ messagingChild.setMaxDisplayedLines(linesRemaining);
+ }
+ int spacing = first ? 0 : mSpacing;
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
+ - mPaddingTop - mPaddingBottom + spacing);
- totalHeight = mPaddingTop + mPaddingBottom;
- boolean first = true;
- int linesRemaining = mMaxDisplayedLines;
-
- // 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();
- MessagingChild messagingChild = null;
- if (child instanceof MessagingChild) {
- messagingChild = (MessagingChild) child;
- messagingChild.setMaxDisplayedLines(linesRemaining);
- }
- int spacing = first ? 0 : mSpacing;
- measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
- - mPaddingTop - mPaddingBottom + spacing);
-
- final int childHeight = child.getMeasuredHeight();
- int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
- lp.bottomMargin + spacing);
- first = false;
- int measureType = MessagingChild.MEASURED_NORMAL;
- if (messagingChild != null) {
- measureType = messagingChild.getMeasuredType();
- linesRemaining -= messagingChild.getConsumedLines();
- }
- boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED;
- boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL;
- if (newHeight <= targetHeight && !isTooSmall) {
- totalHeight = newHeight;
- measuredWidth = Math.max(measuredWidth,
- child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
- + mPaddingLeft + mPaddingRight);
- lp.hide = false;
- if (isShortened || linesRemaining <= 0) {
- break;
- }
- } else {
+ final int childHeight = child.getMeasuredHeight();
+ int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
+ lp.bottomMargin + spacing);
+ first = false;
+ int measureType = MessagingChild.MEASURED_NORMAL;
+ if (messagingChild != null) {
+ measureType = messagingChild.getMeasuredType();
+ linesRemaining -= messagingChild.getConsumedLines();
+ }
+ boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED;
+ boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL;
+ if (newHeight <= targetHeight && !isTooSmall) {
+ totalHeight = newHeight;
+ measuredWidth = Math.max(measuredWidth,
+ child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
+ + mPaddingLeft + mPaddingRight);
+ lp.hide = false;
+ if (isShortened || linesRemaining <= 0) {
break;
}
+ } else {
+ break;
}
}
setMeasuredDimension(
resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth),
widthMeasureSpec),
- resolveSize(Math.max(getSuggestedMinimumHeight(), totalHeight),
- heightMeasureSpec));
- mLastMeasuredWidth = widthSize;
+ Math.max(getSuggestedMinimumHeight(), totalHeight));
}
@Override
@@ -216,7 +194,6 @@
first = false;
}
- mLastMeasuredWidth = NOT_MEASURED_BEFORE;
}
@Override
diff --git a/core/java/com/android/internal/widget/RemeasuringLinearLayout.java b/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
new file mode 100644
index 0000000..e352b45
--- /dev/null
+++ b/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+
+/**
+ * A LinearLayout that sets it's height again after the last measure pass. This is needed for
+ * MessagingLayouts where groups need to be able to snap it's height to.
+ */
+@RemoteViews.RemoteView
+public class RemeasuringLinearLayout extends LinearLayout {
+
+ public RemeasuringLinearLayout(Context context) {
+ super(context);
+ }
+
+ public RemeasuringLinearLayout(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public RemeasuringLinearLayout(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public RemeasuringLinearLayout(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int count = getChildCount();
+ int height = 0;
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ if (child == null || child.getVisibility() == View.GONE) {
+ continue;
+ }
+
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ height = Math.max(height, height + child.getMeasuredHeight() + lp.topMargin +
+ lp.bottomMargin);
+ }
+ setMeasuredDimension(getMeasuredWidth(), height);
+ }
+}
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
index 5adf7a3..8973ceb 100644
--- a/core/res/res/layout/notification_template_messaging_group.xml
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -27,7 +27,7 @@
android:layout_marginEnd="8dp"
android:scaleType="centerCrop"
android:importantForAccessibility="no" />
- <LinearLayout
+ <com.android.internal.widget.RemeasuringLinearLayout
android:id="@+id/message_group_and_sender_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -46,5 +46,5 @@
android:paddingEnd="8dp"
android:paddingTop="2dp"
/>
- </LinearLayout>
+ </com.android.internal.widget.RemeasuringLinearLayout>
</com.android.internal.widget.MessagingGroup>