Merge changes I11400a55,I49461363,Ia18b2dc3,I8c554755 into sc-dev
* changes: Simplify SmartReplyView padding layout logic Smart action buttons now have 8dp corner radius Fix measure logic so that priority children can have more than 1/N space. Update the style of emphasized notification actions.
This commit is contained in:
@@ -5662,11 +5662,6 @@ public class Notification implements Parcelable
|
||||
R.dimen.call_notification_collapsible_indent);
|
||||
}
|
||||
big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode);
|
||||
if (p.mCallStyleActions) {
|
||||
// Use "wrap_content" (unlike normal emphasized mode) and allow prioritizing the
|
||||
// required actions (Answer, Decline, and Hang Up).
|
||||
big.setBoolean(R.id.actions, "setPrioritizedWrapMode", true);
|
||||
}
|
||||
if (numActions > 0 && !p.mHideActions) {
|
||||
big.setViewVisibility(R.id.actions_container, View.VISIBLE);
|
||||
big.setViewVisibility(R.id.actions, View.VISIBLE);
|
||||
@@ -5683,7 +5678,7 @@ public class Notification implements Parcelable
|
||||
// Clear the drawable
|
||||
button.setInt(R.id.action0, "setBackgroundResource", 0);
|
||||
}
|
||||
if (p.mCallStyleActions && i > 0) {
|
||||
if (emphazisedMode && i > 0) {
|
||||
// Clear start margin from non-first buttons to reduce the gap between them.
|
||||
// (8dp remaining gap is from all buttons' standard 4dp inset).
|
||||
button.setViewLayoutMarginDimen(R.id.action0, RemoteViews.MARGIN_START, 0);
|
||||
@@ -6103,26 +6098,21 @@ public class Notification implements Parcelable
|
||||
// change the background bgColor
|
||||
CharSequence title = action.title;
|
||||
ColorStateList[] outResultColor = new ColorStateList[1];
|
||||
int background = getBackgroundColor(p);
|
||||
int background = getSecondaryAccentColor(p);
|
||||
if (isLegacy()) {
|
||||
title = ContrastColorUtil.clearColorSpans(title);
|
||||
} else {
|
||||
title = ensureColorSpanContrast(title, background, outResultColor);
|
||||
}
|
||||
button.setTextViewText(R.id.action0, processTextSpans(title));
|
||||
final int textColor;
|
||||
boolean hasColorOverride = outResultColor[0] != null;
|
||||
if (hasColorOverride) {
|
||||
// There's a span spanning the full text, let's take it and use it as the
|
||||
// background color
|
||||
background = outResultColor[0].getDefaultColor();
|
||||
textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
|
||||
background, mInNightMode);
|
||||
} else if (mTintActionButtons && !mInNightMode && !isBackgroundColorized(p)) {
|
||||
textColor = getAccentColor(p);
|
||||
} else {
|
||||
textColor = getPrimaryTextColor(p);
|
||||
}
|
||||
final int textColor = ContrastColorUtil.resolvePrimaryColor(mContext,
|
||||
background, mInNightMode);
|
||||
button.setTextColor(R.id.action0, textColor);
|
||||
// We only want about 20% alpha for the ripple
|
||||
final int rippleColor = (textColor & 0x00ffffff) | 0x33000000;
|
||||
@@ -6130,11 +6120,10 @@ public class Notification implements Parcelable
|
||||
ColorStateList.valueOf(rippleColor));
|
||||
button.setColorStateList(R.id.action0, "setButtonBackground",
|
||||
ColorStateList.valueOf(background));
|
||||
button.setBoolean(R.id.action0, "setHasStroke", !hasColorOverride);
|
||||
if (p.mCallStyleActions) {
|
||||
button.setImageViewIcon(R.id.action0, action.getIcon());
|
||||
boolean priority = action.getExtras().getBoolean(CallStyle.KEY_ACTION_PRIORITY);
|
||||
button.setBoolean(R.id.action0, "setWrapModePriority", priority);
|
||||
button.setBoolean(R.id.action0, "setIsPriority", priority);
|
||||
int minWidthDimen =
|
||||
priority ? R.dimen.call_notification_system_action_min_width : 0;
|
||||
button.setIntDimen(R.id.action0, "setMinimumWidth", minWidthDimen);
|
||||
@@ -6319,6 +6308,22 @@ public class Notification implements Parcelable
|
||||
return getContrastColor(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the secondary accent color for colored UI elements. If we're tinting with the theme
|
||||
* accent, this is the theme accent color, otherwise this would be identical to
|
||||
* {@link #getSmallIconColor(StandardTemplateParams)}.
|
||||
*/
|
||||
private @ColorInt int getSecondaryAccentColor(StandardTemplateParams p) {
|
||||
if (isBackgroundColorized(p)) {
|
||||
return getSecondaryTextColor(p);
|
||||
}
|
||||
int color = obtainThemeColor(R.attr.colorAccentSecondary, COLOR_INVALID);
|
||||
if (color != COLOR_INVALID) {
|
||||
return color;
|
||||
}
|
||||
return getContrastColor(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "surface protection" color from the theme, or a variant of the normal background
|
||||
* color when colorized, or when not using theme color tints.
|
||||
|
||||
@@ -27,9 +27,7 @@ import android.graphics.drawable.Icon;
|
||||
import android.graphics.drawable.RippleDrawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.RemotableViewMethod;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import com.android.internal.R;
|
||||
@@ -42,8 +40,6 @@ import com.android.internal.R;
|
||||
@RemoteViews.RemoteView
|
||||
public class EmphasizedNotificationButton extends Button {
|
||||
private final RippleDrawable mRipple;
|
||||
private final int mStrokeWidth;
|
||||
private final int mStrokeColor;
|
||||
private boolean mPriority;
|
||||
|
||||
public EmphasizedNotificationButton(Context context) {
|
||||
@@ -63,9 +59,6 @@ public class EmphasizedNotificationButton extends Button {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
DrawableWrapper background = (DrawableWrapper) getBackground().mutate();
|
||||
mRipple = (RippleDrawable) background.getDrawable();
|
||||
mStrokeWidth = getResources().getDimensionPixelSize(
|
||||
com.android.internal.R.dimen.emphasized_button_stroke_width);
|
||||
mStrokeColor = getContext().getColor(com.android.internal.R.color.material_grey_300);
|
||||
mRipple.mutate();
|
||||
}
|
||||
|
||||
@@ -82,13 +75,6 @@ public class EmphasizedNotificationButton extends Button {
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@RemotableViewMethod
|
||||
public void setHasStroke(boolean hasStroke) {
|
||||
GradientDrawable inner = (GradientDrawable) mRipple.getDrawable(0);
|
||||
inner.setStroke(hasStroke ? mStrokeWidth : 0, mStrokeColor);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an image icon which will have its size constrained and will be set to the same color as
|
||||
* the text. Must be called after {@link #setTextColor(int)} for the latter to work.
|
||||
@@ -121,18 +107,13 @@ public class EmphasizedNotificationButton extends Button {
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the LayoutParams.width to WRAP_CONTENT, with the argument representing if this view
|
||||
* is a priority over its peers (which affects weight).
|
||||
* Sets whether this view is a priority over its peers (which affects width).
|
||||
* Specifically, this is used by {@link NotificationActionListLayout} to give this view width
|
||||
* priority ahead of user-defined buttons when allocating horizontal space.
|
||||
*/
|
||||
@RemotableViewMethod
|
||||
public void setWrapModePriority(boolean priority) {
|
||||
public void setIsPriority(boolean priority) {
|
||||
mPriority = priority;
|
||||
ViewGroup.LayoutParams layoutParams = getLayoutParams();
|
||||
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
if (layoutParams instanceof LinearLayout.LayoutParams) {
|
||||
((LinearLayout.LayoutParams) layoutParams).weight = 0;
|
||||
}
|
||||
setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,10 +43,9 @@ 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 boolean mPrioritizedWrapMode;
|
||||
private int mDefaultPaddingBottom;
|
||||
private int mDefaultPaddingTop;
|
||||
private int mEmphasizedHeight;
|
||||
@@ -70,16 +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) {
|
||||
if (mEmphasizedMode && !mPrioritizedWrapMode) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
@@ -90,6 +91,9 @@ public class NotificationActionListLayout extends LinearLayout {
|
||||
}
|
||||
if (c.getVisibility() != GONE) {
|
||||
notGoneChildren++;
|
||||
if (isPriority(c)) {
|
||||
priorityChildren++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -122,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;
|
||||
@@ -143,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;
|
||||
}
|
||||
@@ -153,6 +173,9 @@ public class NotificationActionListLayout extends LinearLayout {
|
||||
|
||||
usedWidth += c.getMeasuredWidth() + lp.rightMargin + lp.leftMargin;
|
||||
measuredChildren++;
|
||||
if (isPriority) {
|
||||
measuredPriorityChildren++;
|
||||
}
|
||||
}
|
||||
|
||||
int collapsibleIndent = mCollapsibleIndentDimen == 0 ? 0
|
||||
@@ -175,13 +198,8 @@ public class NotificationActionListLayout extends LinearLayout {
|
||||
final int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View c = getChildAt(i);
|
||||
if (c instanceof EmphasizedNotificationButton
|
||||
&& ((EmphasizedNotificationButton) c).isPriority()) {
|
||||
// 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);
|
||||
}
|
||||
@@ -213,10 +231,6 @@ public class NotificationActionListLayout extends LinearLayout {
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
if (mEmphasizedMode && !mPrioritizedWrapMode) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
return;
|
||||
}
|
||||
final boolean isLayoutRtl = isLayoutRtl();
|
||||
final int paddingTop = mPaddingTop;
|
||||
final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
|
||||
@@ -292,16 +306,6 @@ public class NotificationActionListLayout extends LinearLayout {
|
||||
com.android.internal.R.dimen.notification_action_list_height);
|
||||
}
|
||||
|
||||
/**
|
||||
* When used with emphasizedMode, changes the button sizing behavior to prioritize certain
|
||||
* buttons (which are system generated) to not scrunch, and leave the remaining space for
|
||||
* custom actions.
|
||||
*/
|
||||
@RemotableViewMethod
|
||||
public void setPrioritizedWrapMode(boolean prioritizedWrapMode) {
|
||||
mPrioritizedWrapMode = prioritizedWrapMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* When buttons are in wrap mode, this is a padding that will be applied at the start of the
|
||||
* layout of the actions, but only when those actions would fit with the entire padding
|
||||
@@ -353,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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,13 +24,11 @@
|
||||
<item>
|
||||
<shape android:shape="rectangle">
|
||||
<corners android:radius="@dimen/notification_action_button_radius" />
|
||||
<padding android:left="@dimen/button_padding_horizontal_material"
|
||||
<padding android:left="12dp"
|
||||
android:top="@dimen/button_padding_vertical_material"
|
||||
android:right="@dimen/button_padding_horizontal_material"
|
||||
android:right="12dp"
|
||||
android:bottom="@dimen/button_padding_vertical_material" />
|
||||
<solid android:color="@color/white" />
|
||||
<stroke android:width="@dimen/emphasized_button_stroke_width"
|
||||
android:color="@color/material_grey_300"/>
|
||||
</shape>
|
||||
</item>
|
||||
</ripple>
|
||||
|
||||
@@ -18,10 +18,9 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
style="@style/NotificationEmphasizedAction"
|
||||
android:id="@+id/action0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_weight="1"
|
||||
android:drawablePadding="6dp"
|
||||
android:gravity="center"
|
||||
android:textColor="@color/notification_default_color"
|
||||
|
||||
@@ -224,14 +224,14 @@
|
||||
<!-- The margin on the end of the top-line content views (accommodates the expander) -->
|
||||
<dimen name="notification_heading_margin_end">56dp</dimen>
|
||||
|
||||
<!-- The height of the notification action list -->
|
||||
<!-- The total height of the notification action list -->
|
||||
<dimen name="notification_action_list_height">60dp</dimen>
|
||||
|
||||
<!-- The margin of the notification action list at the top -->
|
||||
<dimen name="notification_action_list_margin_top">0dp</dimen>
|
||||
|
||||
<!-- The height of the notification action list -->
|
||||
<dimen name="notification_action_emphasized_height">48dp</dimen>
|
||||
<!-- The visual height of the emphasized notification action -->
|
||||
<dimen name="notification_action_emphasized_height">36dp</dimen>
|
||||
|
||||
<!-- The padding of the actions in non-conversation layout. For conversations, the analogous
|
||||
value is calculated in ConversationLayout#updateActionListPadding() -->
|
||||
@@ -252,7 +252,7 @@
|
||||
<dimen name="notification_actions_icon_drawable_size">20dp</dimen>
|
||||
|
||||
<!-- The corner radius if the emphasized action buttons in a notification -->
|
||||
<dimen name="notification_action_button_radius">8dp</dimen>
|
||||
<dimen name="notification_action_button_radius">18dp</dimen>
|
||||
|
||||
<!-- Size of the stroke with for the emphasized notification button style -->
|
||||
<dimen name="emphasized_button_stroke_width">1dp</dimen>
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
android:textSize="@dimen/smart_reply_button_font_size"
|
||||
android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
|
||||
android:textColor="@color/smart_reply_button_text"
|
||||
android:paddingLeft="@dimen/smart_reply_button_action_padding_left"
|
||||
android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
|
||||
android:drawablePadding="@dimen/smart_action_button_icon_padding"
|
||||
android:textStyle="normal"
|
||||
android:ellipsize="none"/>
|
||||
|
||||
@@ -31,5 +31,7 @@
|
||||
android:textSize="@dimen/smart_reply_button_font_size"
|
||||
android:lineSpacingExtra="@dimen/smart_reply_button_line_spacing_extra"
|
||||
android:textColor="@color/smart_reply_button_text"
|
||||
android:paddingLeft="@dimen/smart_reply_button_padding_horizontal"
|
||||
android:paddingRight="@dimen/smart_reply_button_padding_horizontal"
|
||||
android:textStyle="normal"
|
||||
android:ellipsize="none"/>
|
||||
|
||||
@@ -24,8 +24,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
systemui:spacing="@dimen/smart_reply_button_spacing"
|
||||
systemui:singleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_single_line"
|
||||
systemui:doubleLineButtonPaddingHorizontal="@dimen/smart_reply_button_padding_horizontal_double_line"
|
||||
systemui:buttonStrokeWidth="@dimen/smart_reply_button_stroke_width">
|
||||
<!-- smart_reply_button(s) will be added here. -->
|
||||
</com.android.systemui.statusbar.policy.SmartReplyView>
|
||||
|
||||
@@ -131,8 +131,6 @@
|
||||
|
||||
<declare-styleable name="SmartReplyView">
|
||||
<attr name="spacing" format="dimension" />
|
||||
<attr name="singleLineButtonPaddingHorizontal" format="dimension" />
|
||||
<attr name="doubleLineButtonPaddingHorizontal" format="dimension" />
|
||||
<attr name="buttonStrokeWidth" format="dimension" />
|
||||
</declare-styleable>
|
||||
|
||||
|
||||
@@ -1147,15 +1147,14 @@
|
||||
<!-- Smart reply button. Total height 48dp, visible height 32dp. -->
|
||||
<dimen name="smart_reply_button_spacing">8dp</dimen>
|
||||
<dimen name="smart_reply_button_padding_vertical">14dp</dimen>
|
||||
<!-- Note: The following two paddings need to be different until b/78876518 is fixed. -->
|
||||
<dimen name="smart_reply_button_padding_horizontal_single_line">20dp</dimen>
|
||||
<dimen name="smart_reply_button_padding_horizontal_double_line">19dp</dimen>
|
||||
<dimen name="smart_reply_button_padding_horizontal">16dp</dimen>
|
||||
<dimen name="smart_reply_button_action_padding_left">8dp</dimen>
|
||||
<dimen name="smart_reply_button_min_height">48dp</dimen>
|
||||
<dimen name="smart_reply_button_stroke_width">1dp</dimen>
|
||||
<dimen name="smart_reply_button_font_size">14sp</dimen>
|
||||
<dimen name="smart_reply_button_line_spacing_extra">6sp</dimen> <!-- Total line height 20sp. -->
|
||||
<!-- Corner radius = half of min_height to create rounded sides. -->
|
||||
<dimen name="smart_reply_button_corner_radius">24dp</dimen>
|
||||
<dimen name="smart_reply_button_corner_radius">8dp</dimen>
|
||||
<dimen name="smart_action_button_icon_size">18dp</dimen>
|
||||
<dimen name="smart_action_button_icon_padding">8dp</dimen>
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.ContrastColorUtil;
|
||||
@@ -58,15 +59,6 @@ public class SmartReplyView extends ViewGroup {
|
||||
/** Spacing to be applied between views. */
|
||||
private final int mSpacing;
|
||||
|
||||
/** Horizontal padding of smart reply buttons if all of them use only one line of text. */
|
||||
private final int mSingleLineButtonPaddingHorizontal;
|
||||
|
||||
/** Horizontal padding of smart reply buttons if at least one of them uses two lines of text. */
|
||||
private final int mDoubleLineButtonPaddingHorizontal;
|
||||
|
||||
/** Increase in width of a smart reply button as a result of using two lines instead of one. */
|
||||
private final int mSingleToDoubleLineButtonWidthIncrease;
|
||||
|
||||
private final BreakIterator mBreakIterator;
|
||||
|
||||
private PriorityQueue<Button> mCandidateButtonQueueForSqueezing;
|
||||
@@ -114,8 +106,6 @@ public class SmartReplyView extends ViewGroup {
|
||||
mDefaultBackgroundColor);
|
||||
|
||||
int spacing = 0;
|
||||
int singleLineButtonPaddingHorizontal = 0;
|
||||
int doubleLineButtonPaddingHorizontal = 0;
|
||||
int strokeWidth = 0;
|
||||
|
||||
final TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.SmartReplyView,
|
||||
@@ -125,10 +115,6 @@ public class SmartReplyView extends ViewGroup {
|
||||
int attr = arr.getIndex(i);
|
||||
if (attr == R.styleable.SmartReplyView_spacing) {
|
||||
spacing = arr.getDimensionPixelSize(i, 0);
|
||||
} else if (attr == R.styleable.SmartReplyView_singleLineButtonPaddingHorizontal) {
|
||||
singleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
|
||||
} else if (attr == R.styleable.SmartReplyView_doubleLineButtonPaddingHorizontal) {
|
||||
doubleLineButtonPaddingHorizontal = arr.getDimensionPixelSize(i, 0);
|
||||
} else if (attr == R.styleable.SmartReplyView_buttonStrokeWidth) {
|
||||
strokeWidth = arr.getDimensionPixelSize(i, 0);
|
||||
}
|
||||
@@ -137,10 +123,6 @@ public class SmartReplyView extends ViewGroup {
|
||||
|
||||
mStrokeWidth = strokeWidth;
|
||||
mSpacing = spacing;
|
||||
mSingleLineButtonPaddingHorizontal = singleLineButtonPaddingHorizontal;
|
||||
mDoubleLineButtonPaddingHorizontal = doubleLineButtonPaddingHorizontal;
|
||||
mSingleToDoubleLineButtonWidthIncrease =
|
||||
2 * (doubleLineButtonPaddingHorizontal - singleLineButtonPaddingHorizontal);
|
||||
|
||||
mBreakIterator = BreakIterator.getLineInstance();
|
||||
|
||||
@@ -222,6 +204,12 @@ public class SmartReplyView extends ViewGroup {
|
||||
return new LayoutParams(params.width, params.height);
|
||||
}
|
||||
|
||||
private void clearLayoutLineCount(View view) {
|
||||
if (view instanceof TextView) {
|
||||
((TextView) view).nullLayouts();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final int targetWidth = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED
|
||||
@@ -237,8 +225,7 @@ public class SmartReplyView extends ViewGroup {
|
||||
|
||||
SmartSuggestionMeasures accumulatedMeasures = new SmartSuggestionMeasures(
|
||||
mPaddingLeft + mPaddingRight,
|
||||
0 /* maxChildHeight */,
|
||||
mSingleLineButtonPaddingHorizontal);
|
||||
0 /* maxChildHeight */);
|
||||
int displayedChildCount = 0;
|
||||
|
||||
// Set up a list of suggestions where actions come before replies. Note that the Buttons
|
||||
@@ -268,8 +255,7 @@ public class SmartReplyView extends ViewGroup {
|
||||
continue;
|
||||
}
|
||||
|
||||
child.setPadding(accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingTop(),
|
||||
accumulatedMeasures.mButtonPaddingHorizontal, child.getPaddingBottom());
|
||||
clearLayoutLineCount(child);
|
||||
child.measure(MEASURE_SPEC_ANY_LENGTH, heightMeasureSpec);
|
||||
|
||||
coveredSuggestions.add(child);
|
||||
@@ -299,18 +285,6 @@ public class SmartReplyView extends ViewGroup {
|
||||
accumulatedMeasures.mMaxChildHeight =
|
||||
Math.max(accumulatedMeasures.mMaxChildHeight, childHeight);
|
||||
|
||||
// Do we need to increase the number of lines in smart reply buttons to two?
|
||||
final boolean increaseToTwoLines =
|
||||
(accumulatedMeasures.mButtonPaddingHorizontal
|
||||
== mSingleLineButtonPaddingHorizontal)
|
||||
&& (lineCount == 2 || accumulatedMeasures.mMeasuredWidth > targetWidth);
|
||||
if (increaseToTwoLines) {
|
||||
accumulatedMeasures.mMeasuredWidth +=
|
||||
(displayedChildCount + 1) * mSingleToDoubleLineButtonWidthIncrease;
|
||||
accumulatedMeasures.mButtonPaddingHorizontal =
|
||||
mDoubleLineButtonPaddingHorizontal;
|
||||
}
|
||||
|
||||
// If the last button doesn't fit into the remaining width, try squeezing preceding
|
||||
// smart reply buttons.
|
||||
if (accumulatedMeasures.mMeasuredWidth > targetWidth) {
|
||||
@@ -372,18 +346,11 @@ public class SmartReplyView extends ViewGroup {
|
||||
mCandidateButtonQueueForSqueezing.clear();
|
||||
|
||||
// Finally, we need to re-measure some buttons.
|
||||
remeasureButtonsIfNecessary(accumulatedMeasures.mButtonPaddingHorizontal,
|
||||
accumulatedMeasures.mMaxChildHeight);
|
||||
remeasureButtonsIfNecessary(accumulatedMeasures.mMaxChildHeight);
|
||||
|
||||
int buttonHeight = Math.max(getSuggestedMinimumHeight(), mPaddingTop
|
||||
+ accumulatedMeasures.mMaxChildHeight + mPaddingBottom);
|
||||
|
||||
// Set the corner radius to half the button height to make the side of the buttons look like
|
||||
// a semicircle.
|
||||
for (View smartSuggestionButton : smartSuggestions) {
|
||||
setCornerRadius((Button) smartSuggestionButton, ((float) buttonHeight) / 2);
|
||||
}
|
||||
|
||||
setMeasuredDimension(
|
||||
resolveSize(Math.max(getSuggestedMinimumWidth(),
|
||||
accumulatedMeasures.mMeasuredWidth),
|
||||
@@ -411,18 +378,14 @@ public class SmartReplyView extends ViewGroup {
|
||||
private static class SmartSuggestionMeasures {
|
||||
int mMeasuredWidth = -1;
|
||||
int mMaxChildHeight = -1;
|
||||
int mButtonPaddingHorizontal = -1;
|
||||
|
||||
SmartSuggestionMeasures(int measuredWidth, int maxChildHeight,
|
||||
int buttonPaddingHorizontal) {
|
||||
SmartSuggestionMeasures(int measuredWidth, int maxChildHeight) {
|
||||
this.mMeasuredWidth = measuredWidth;
|
||||
this.mMaxChildHeight = maxChildHeight;
|
||||
this.mButtonPaddingHorizontal = buttonPaddingHorizontal;
|
||||
}
|
||||
|
||||
public SmartSuggestionMeasures clone() {
|
||||
return new SmartSuggestionMeasures(
|
||||
mMeasuredWidth, mMaxChildHeight, mButtonPaddingHorizontal);
|
||||
return new SmartSuggestionMeasures(mMeasuredWidth, mMaxChildHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,17 +516,11 @@ public class SmartReplyView extends ViewGroup {
|
||||
|
||||
private int squeezeButtonToTextWidth(Button button, int heightMeasureSpec, int textWidth) {
|
||||
int oldWidth = button.getMeasuredWidth();
|
||||
if (button.getPaddingLeft() != mDoubleLineButtonPaddingHorizontal) {
|
||||
// Correct for the fact that the button was laid out with single-line horizontal
|
||||
// padding.
|
||||
oldWidth += mSingleToDoubleLineButtonWidthIncrease;
|
||||
}
|
||||
|
||||
// Re-measure the squeezed smart reply button.
|
||||
button.setPadding(mDoubleLineButtonPaddingHorizontal, button.getPaddingTop(),
|
||||
mDoubleLineButtonPaddingHorizontal, button.getPaddingBottom());
|
||||
clearLayoutLineCount(button);
|
||||
final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(
|
||||
2 * mDoubleLineButtonPaddingHorizontal + textWidth
|
||||
button.getPaddingLeft() + button.getPaddingRight() + textWidth
|
||||
+ getLeftCompoundDrawableWidthWithPadding(button), MeasureSpec.AT_MOST);
|
||||
button.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
@@ -579,8 +536,7 @@ public class SmartReplyView extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
private void remeasureButtonsIfNecessary(
|
||||
int buttonPaddingHorizontal, int maxChildHeight) {
|
||||
private void remeasureButtonsIfNecessary(int maxChildHeight) {
|
||||
final int maxChildHeightMeasure =
|
||||
MeasureSpec.makeMeasureSpec(maxChildHeight, MeasureSpec.EXACTLY);
|
||||
|
||||
@@ -602,24 +558,7 @@ public class SmartReplyView extends ViewGroup {
|
||||
newWidth = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
// Re-measure reason 2: The button's horizontal padding is incorrect (because it was
|
||||
// measured with the wrong number of lines).
|
||||
if (child.getPaddingLeft() != buttonPaddingHorizontal) {
|
||||
requiresNewMeasure = true;
|
||||
if (newWidth != Integer.MAX_VALUE) {
|
||||
if (buttonPaddingHorizontal == mSingleLineButtonPaddingHorizontal) {
|
||||
// Change padding (2->1 line).
|
||||
newWidth -= mSingleToDoubleLineButtonWidthIncrease;
|
||||
} else {
|
||||
// Change padding (1->2 lines).
|
||||
newWidth += mSingleToDoubleLineButtonWidthIncrease;
|
||||
}
|
||||
}
|
||||
child.setPadding(buttonPaddingHorizontal, child.getPaddingTop(),
|
||||
buttonPaddingHorizontal, child.getPaddingBottom());
|
||||
}
|
||||
|
||||
// Re-measure reason 3: The button's height is less than the max height of all buttons
|
||||
// Re-measure reason 2: The button's height is less than the max height of all buttons
|
||||
// (all should have the same height).
|
||||
if (child.getMeasuredHeight() != maxChildHeight) {
|
||||
requiresNewMeasure = true;
|
||||
@@ -725,23 +664,6 @@ public class SmartReplyView extends ViewGroup {
|
||||
button.setTextColor(mCurrentTextColor);
|
||||
}
|
||||
|
||||
private void setCornerRadius(Button button, float radius) {
|
||||
Drawable drawable = button.getBackground();
|
||||
if (drawable instanceof RippleDrawable) {
|
||||
// Mutate in case other notifications are using this drawable.
|
||||
drawable = drawable.mutate();
|
||||
RippleDrawable ripple = (RippleDrawable) drawable;
|
||||
Drawable inset = ripple.getDrawable(0);
|
||||
if (inset instanceof InsetDrawable) {
|
||||
Drawable background = ((InsetDrawable) inset).getDrawable();
|
||||
if (background instanceof GradientDrawable) {
|
||||
GradientDrawable gradientDrawable = (GradientDrawable) background;
|
||||
gradientDrawable.setCornerRadius(radius);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SmartButtonType {
|
||||
REPLY,
|
||||
ACTION
|
||||
|
||||
@@ -20,7 +20,6 @@ import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.never;
|
||||
@@ -100,8 +99,6 @@ public class SmartReplyViewTest extends SysuiTestCase {
|
||||
|
||||
private Icon mActionIcon;
|
||||
|
||||
private int mSingleLinePaddingHorizontal;
|
||||
private int mDoubleLinePaddingHorizontal;
|
||||
private int mSpacing;
|
||||
|
||||
private NotificationEntry mEntry;
|
||||
@@ -141,10 +138,6 @@ public class SmartReplyViewTest extends SysuiTestCase {
|
||||
mView = SmartReplyView.inflate(mContext, mConstants);
|
||||
|
||||
final Resources res = mContext.getResources();
|
||||
mSingleLinePaddingHorizontal = res.getDimensionPixelSize(
|
||||
R.dimen.smart_reply_button_padding_horizontal_single_line);
|
||||
mDoubleLinePaddingHorizontal = res.getDimensionPixelSize(
|
||||
R.dimen.smart_reply_button_padding_horizontal_double_line);
|
||||
mSpacing = res.getDimensionPixelSize(R.dimen.smart_reply_button_spacing);
|
||||
|
||||
mNotification = new Notification.Builder(mContext, "")
|
||||
@@ -588,18 +581,6 @@ public class SmartReplyViewTest extends SysuiTestCase {
|
||||
layout.setBaselineAligned(false);
|
||||
|
||||
final boolean isRtl = mView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
|
||||
final int paddingHorizontal;
|
||||
switch (lineCount) {
|
||||
case 1:
|
||||
paddingHorizontal = mSingleLinePaddingHorizontal;
|
||||
break;
|
||||
case 2:
|
||||
paddingHorizontal = mDoubleLinePaddingHorizontal;
|
||||
break;
|
||||
default:
|
||||
fail("Invalid line count " + lineCount);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Add smart replies
|
||||
Button previous = null;
|
||||
@@ -617,8 +598,6 @@ public class SmartReplyViewTest extends SysuiTestCase {
|
||||
true /* delayOnClickListener */))
|
||||
.iterator()));
|
||||
for (Button current : inflatedReplies) {
|
||||
current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal,
|
||||
current.getPaddingBottom());
|
||||
if (previous != null) {
|
||||
ViewGroup.MarginLayoutParams lp =
|
||||
(ViewGroup.MarginLayoutParams) previous.getLayoutParams();
|
||||
@@ -647,8 +626,6 @@ public class SmartReplyViewTest extends SysuiTestCase {
|
||||
|
||||
// Add smart actions
|
||||
for (Button current : inflatedSmartActions) {
|
||||
current.setPadding(paddingHorizontal, current.getPaddingTop(), paddingHorizontal,
|
||||
current.getPaddingBottom());
|
||||
if (previous != null) {
|
||||
ViewGroup.MarginLayoutParams lp =
|
||||
(ViewGroup.MarginLayoutParams) previous.getLayoutParams();
|
||||
|
||||
Reference in New Issue
Block a user