Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6d567d2 authored by Jeff DeCew's avatar Jeff DeCew
Browse files

Fix measure logic so that priority children can have more than 1/N space.

The priority previously just put the view at the front of the list, which ensured that super long user-provided actions couldn't cause the priority action at the end to be truncated.  However, this still meant that a priority action at the start whose text would have it be longer than 1/3 of the action space would be capped at 1/3 instead of taking on some of the user-defined child's space.

Bug: 187533622
Test: Post Notify2 app's Call style w/ Screen action; notice that "Decline" is not truncated.

Change-Id: Ia18b2dc366ba7cac13ed845acac59d89206e7d5e
parent 2ca6b439
Loading
Loading
Loading
Loading
+61 −15
Original line number Diff line number Diff line
@@ -17,11 +17,11 @@
package com.android.internal.widget;

import android.annotation.DimenRes;
import android.app.Notification;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.Gravity;
import android.view.RemotableViewMethod;
import android.view.View;
@@ -43,7 +43,7 @@ public class NotificationActionListLayout extends LinearLayout {
    private final int mGravity;
    private int mTotalWidth = 0;
    private int mExtraStartPadding = 0;
    private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>();
    private ArrayList<TextViewInfo> mMeasureOrderTextViews = new ArrayList<>();
    private ArrayList<View> mMeasureOrderOther = new ArrayList<>();
    private boolean mEmphasizedMode;
    private int mDefaultPaddingBottom;
@@ -69,12 +69,18 @@ public class NotificationActionListLayout extends LinearLayout {
        ta.recycle();
    }

    private static boolean isPriority(View actionView) {
        return actionView instanceof EmphasizedNotificationButton
                && ((EmphasizedNotificationButton) actionView).isPriority();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int N = getChildCount();
        int textViews = 0;
        int otherViews = 0;
        int notGoneChildren = 0;
        int priorityChildren = 0;

        for (int i = 0; i < N; i++) {
            View c = getChildAt(i);
@@ -85,6 +91,9 @@ public class NotificationActionListLayout extends LinearLayout {
            }
            if (c.getVisibility() != GONE) {
                notGoneChildren++;
                if (isPriority(c)) {
                    priorityChildren++;
                }
            }
        }

@@ -98,9 +107,9 @@ public class NotificationActionListLayout extends LinearLayout {
        if (!needRebuild) {
            final int size = mMeasureOrderTextViews.size();
            for (int i = 0; i < size; i++) {
                Pair<Integer, TextView> pair = mMeasureOrderTextViews.get(i);
                if (pair.first != pair.second.getText().length()) {
                if (mMeasureOrderTextViews.get(i).needsRebuild()) {
                    needRebuild = true;
                    break;
                }
            }
        }
@@ -117,14 +126,19 @@ public class NotificationActionListLayout extends LinearLayout {
        int usedWidth = 0;

        int measuredChildren = 0;
        int measuredPriorityChildren = 0;
        for (int i = 0; i < N; i++) {
            // Measure shortest children first. To avoid measuring twice, we approximate by looking
            // at the text length.
            View c;
            final boolean isPriority;
            final View c;
            if (i < otherSize) {
                c = mMeasureOrderOther.get(i);
                isPriority = false;
            } else {
                c = mMeasureOrderTextViews.get(i - otherSize).second;
                TextViewInfo info = mMeasureOrderTextViews.get(i - otherSize);
                c = info.mTextView;
                isPriority = info.mIsPriority;
            }
            if (c.getVisibility() == GONE) {
                continue;
@@ -138,7 +152,18 @@ public class NotificationActionListLayout extends LinearLayout {
                // measure in the order of (approx.) size, a large view can still take more than its
                // share if the others are small.
                int availableWidth = innerWidth - usedWidth;
                int maxWidthForChild = availableWidth / (notGoneChildren - measuredChildren);
                int unmeasuredChildren = notGoneChildren - measuredChildren;
                int maxWidthForChild = availableWidth / unmeasuredChildren;
                if (isPriority) {
                    // Priority children get a larger maximum share of the total space:
                    //  maximum priority share = (nPriority + 1) / (MAX + 1)
                    int unmeasuredPriorityChildren = priorityChildren - measuredPriorityChildren;
                    int unmeasuredOtherChildren = unmeasuredChildren - unmeasuredPriorityChildren;
                    int widthReservedForOtherChildren = innerWidth * unmeasuredOtherChildren
                            / (Notification.MAX_ACTION_BUTTONS + 1);
                    int widthAvailableForPriority = availableWidth - widthReservedForOtherChildren;
                    maxWidthForChild = widthAvailableForPriority / unmeasuredPriorityChildren;
                }

                usedWidthForChild = innerWidth - maxWidthForChild;
            }
@@ -148,6 +173,9 @@ public class NotificationActionListLayout extends LinearLayout {

            usedWidth += c.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
            measuredChildren++;
            if (isPriority) {
                measuredPriorityChildren++;
            }
        }

        int collapsibleIndent = mCollapsibleIndentDimen == 0 ? 0
@@ -170,12 +198,8 @@ public class NotificationActionListLayout extends LinearLayout {
        final int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View c = getChildAt(i);
            if (isPriority(c)) {
                // add with 0 length to ensure that this view is measured before others.
                mMeasureOrderTextViews.add(Pair.create(0, (TextView) c));
            } else if (c instanceof TextView && ((TextView) c).getText().length() > 0) {
                mMeasureOrderTextViews.add(Pair.create(((TextView) c).getText().length(),
                        (TextView)c));
            if (c instanceof TextView && ((TextView) c).getText().length() > 0) {
                mMeasureOrderTextViews.add(new TextViewInfo((TextView) c));
            } else {
                mMeasureOrderOther.add(c);
            }
@@ -333,6 +357,28 @@ public class NotificationActionListLayout extends LinearLayout {
        return 0;
    }

    public static final Comparator<Pair<Integer, TextView>> MEASURE_ORDER_COMPARATOR
            = (a, b) -> a.first.compareTo(b.first);
    public static final Comparator<TextViewInfo> MEASURE_ORDER_COMPARATOR = (a, b) -> {
        int priorityComparison = -Boolean.compare(a.mIsPriority, b.mIsPriority);
        return priorityComparison != 0
                ? priorityComparison
                : Integer.compare(a.mTextLength, b.mTextLength);
    };

    private static final class TextViewInfo {
        final boolean mIsPriority;
        final int mTextLength;
        final TextView mTextView;

        TextViewInfo(TextView textView) {
            this.mIsPriority = isPriority(textView);
            this.mTextLength = textView.getText().length();
            this.mTextView = textView;
        }

        boolean needsRebuild() {
            return mTextView.getText().length() != mTextLength
                    || isPriority(mTextView) != mIsPriority;
        }
    }

}