Merge "Clean up MessagingLayout notifications" into sc-dev
This commit is contained in:
@@ -5116,6 +5116,7 @@ public class Notification implements Parcelable
|
||||
TemplateBindResult result) {
|
||||
p.headerless(resId == getBaseLayoutResource()
|
||||
|| resId == getHeadsUpBaseLayoutResource()
|
||||
|| resId == getMessagingLayoutResource()
|
||||
|| resId == R.layout.notification_template_material_media);
|
||||
RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
|
||||
|
||||
@@ -6641,6 +6642,10 @@ public class Notification implements Parcelable
|
||||
return R.layout.notification_template_material_messaging;
|
||||
}
|
||||
|
||||
private int getBigMessagingLayoutResource() {
|
||||
return R.layout.notification_template_material_big_messaging;
|
||||
}
|
||||
|
||||
private int getConversationLayoutResource() {
|
||||
return R.layout.notification_template_material_conversation;
|
||||
}
|
||||
@@ -8151,12 +8156,14 @@ public class Notification implements Parcelable
|
||||
*/
|
||||
@Override
|
||||
public RemoteViews makeContentView(boolean increasedHeight) {
|
||||
// All messaging templates contain the actions
|
||||
ArrayList<Action> originalActions = mBuilder.mActions;
|
||||
mBuilder.mActions = new ArrayList<>();
|
||||
RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */,
|
||||
false /* hideLargeIcon */);
|
||||
mBuilder.mActions = originalActions;
|
||||
return remoteViews;
|
||||
try {
|
||||
mBuilder.mActions = new ArrayList<>();
|
||||
return makeMessagingView(StandardTemplateParams.VIEW_TYPE_NORMAL);
|
||||
} finally {
|
||||
mBuilder.mActions = originalActions;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8242,18 +8249,24 @@ public class Notification implements Parcelable
|
||||
*/
|
||||
@Override
|
||||
public RemoteViews makeBigContentView() {
|
||||
return makeMessagingView(false /* isCollapsed */, true /* hideLargeIcon */);
|
||||
return makeMessagingView(StandardTemplateParams.VIEW_TYPE_BIG);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a messaging layout.
|
||||
*
|
||||
* @param isCollapsed Should this use the collapsed layout
|
||||
* @param hideRightIcons Should the reply affordance be shown at the end of the notification
|
||||
* @param viewType one of StandardTemplateParams.VIEW_TYPE_NORMAL, VIEW_TYPE_BIG,
|
||||
* VIEW_TYPE_HEADS_UP
|
||||
* @return the created remoteView.
|
||||
*/
|
||||
@NonNull
|
||||
private RemoteViews makeMessagingView(boolean isCollapsed, boolean hideRightIcons) {
|
||||
private RemoteViews makeMessagingView(int viewType) {
|
||||
boolean isCollapsed = viewType != StandardTemplateParams.VIEW_TYPE_BIG;
|
||||
boolean hideRightIcons = viewType != StandardTemplateParams.VIEW_TYPE_NORMAL;
|
||||
boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
|
||||
boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
|
||||
boolean isHeaderless = !isConversationLayout && isCollapsed;
|
||||
|
||||
CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
|
||||
? super.mBigContentTitle
|
||||
: mConversationTitle;
|
||||
@@ -8271,23 +8284,26 @@ public class Notification implements Parcelable
|
||||
} else {
|
||||
isOneToOne = !isGroupConversation();
|
||||
}
|
||||
boolean isConversationLayout = mConversationType != CONVERSATION_TYPE_LEGACY;
|
||||
boolean isImportantConversation = mConversationType == CONVERSATION_TYPE_IMPORTANT;
|
||||
if (isHeaderless && isOneToOne && TextUtils.isEmpty(conversationTitle)) {
|
||||
conversationTitle = getOtherPersonName();
|
||||
}
|
||||
|
||||
Icon largeIcon = mBuilder.mN.mLargeIcon;
|
||||
TemplateBindResult bindResult = new TemplateBindResult();
|
||||
StandardTemplateParams p = mBuilder.mParams.reset()
|
||||
.viewType(isCollapsed ? StandardTemplateParams.VIEW_TYPE_NORMAL
|
||||
: StandardTemplateParams.VIEW_TYPE_BIG)
|
||||
.viewType(viewType)
|
||||
.highlightExpander(isConversationLayout)
|
||||
.hideProgress(true)
|
||||
.title(conversationTitle)
|
||||
.title(isHeaderless ? conversationTitle : null)
|
||||
.text(null)
|
||||
.hideLargeIcon(hideRightIcons || isOneToOne)
|
||||
.headerTextSecondary(conversationTitle);
|
||||
.headerTextSecondary(isHeaderless ? null : conversationTitle);
|
||||
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
|
||||
isConversationLayout
|
||||
? mBuilder.getConversationLayoutResource()
|
||||
: mBuilder.getMessagingLayoutResource(),
|
||||
: isCollapsed
|
||||
? mBuilder.getMessagingLayoutResource()
|
||||
: mBuilder.getBigMessagingLayoutResource(),
|
||||
p,
|
||||
bindResult);
|
||||
if (isConversationLayout) {
|
||||
@@ -8296,14 +8312,6 @@ public class Notification implements Parcelable
|
||||
}
|
||||
|
||||
addExtras(mBuilder.mN.extras);
|
||||
if (!isConversationLayout) {
|
||||
// also update the end margin if there is an image
|
||||
// NOTE: This template doesn't support moving this icon to the left, so we don't
|
||||
// need to fully apply the MarginSet
|
||||
contentView.setViewLayoutMargin(R.id.notification_messaging, RemoteViews.MARGIN_END,
|
||||
bindResult.mHeadingExtraMarginSet.getDpValue(),
|
||||
TypedValue.COMPLEX_UNIT_DIP);
|
||||
}
|
||||
contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
|
||||
mBuilder.getSmallIconColor(p));
|
||||
contentView.setInt(R.id.status_bar_latest_event_content, "setSenderTextColor",
|
||||
@@ -8329,6 +8337,10 @@ public class Notification implements Parcelable
|
||||
contentView.setBoolean(R.id.status_bar_latest_event_content,
|
||||
"setIsImportantConversation", isImportantConversation);
|
||||
}
|
||||
if (isHeaderless) {
|
||||
// Collapsed legacy messaging style has a 1-line limit.
|
||||
contentView.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
|
||||
}
|
||||
contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
|
||||
largeIcon);
|
||||
contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
|
||||
@@ -8336,6 +8348,22 @@ public class Notification implements Parcelable
|
||||
return contentView;
|
||||
}
|
||||
|
||||
private CharSequence getKey(Person person) {
|
||||
return person == null ? null
|
||||
: person.getKey() == null ? person.getName() : person.getKey();
|
||||
}
|
||||
|
||||
private CharSequence getOtherPersonName() {
|
||||
CharSequence userKey = getKey(mUser);
|
||||
for (int i = mMessages.size() - 1; i >= 0; i--) {
|
||||
Person sender = mMessages.get(i).getSenderPerson();
|
||||
if (sender != null && !TextUtils.equals(userKey, getKey(sender))) {
|
||||
return sender.getName();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean hasOnlyWhiteSpaceSenders() {
|
||||
for (int i = 0; i < mMessages.size(); i++) {
|
||||
Message m = mMessages.get(i);
|
||||
@@ -8370,12 +8398,7 @@ public class Notification implements Parcelable
|
||||
*/
|
||||
@Override
|
||||
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
|
||||
RemoteViews remoteViews = makeMessagingView(true /* isCollapsed */,
|
||||
true /* hideLargeIcon */);
|
||||
if (mConversationType == CONVERSATION_TYPE_LEGACY) {
|
||||
remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
|
||||
}
|
||||
return remoteViews;
|
||||
return makeMessagingView(StandardTemplateParams.VIEW_TYPE_HEADS_UP);
|
||||
}
|
||||
|
||||
public static final class Message {
|
||||
|
||||
@@ -64,6 +64,7 @@ import com.android.internal.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -530,13 +531,7 @@ public class ConversationLayout extends FrameLayout
|
||||
mConversationText.setText(conversationText);
|
||||
// Update if the groups can hide the sender if they are first (applies to 1:1 conversations)
|
||||
// This needs to happen after all of the above o update all of the groups
|
||||
for (int i = mGroups.size() - 1; i >= 0; i--) {
|
||||
MessagingGroup messagingGroup = mGroups.get(i);
|
||||
CharSequence messageSender = messagingGroup.getSenderName();
|
||||
boolean canHide = mIsOneToOne
|
||||
&& TextUtils.equals(conversationText, messageSender);
|
||||
messagingGroup.setCanHideSenderIfFirst(canHide);
|
||||
}
|
||||
mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, conversationText);
|
||||
updateAppName();
|
||||
updateIconPositionAndSize();
|
||||
updateImageMessages();
|
||||
@@ -779,35 +774,7 @@ public class ConversationLayout extends FrameLayout
|
||||
|
||||
private void updateTitleAndNamesDisplay() {
|
||||
// Map of unique names to their prefix
|
||||
ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
|
||||
// Map of single-character string prefix to the only name which uses it, or null if multiple
|
||||
ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>();
|
||||
for (int i = 0; i < mGroups.size(); i++) {
|
||||
MessagingGroup group = mGroups.get(i);
|
||||
CharSequence senderName = group.getSenderName();
|
||||
if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
|
||||
continue;
|
||||
}
|
||||
if (!uniqueNames.containsKey(senderName)) {
|
||||
String charPrefix = mPeopleHelper.findNamePrefix(senderName, null);
|
||||
if (charPrefix == null) {
|
||||
continue;
|
||||
}
|
||||
if (uniqueCharacters.containsKey(charPrefix)) {
|
||||
// this character was already used, lets make it more unique. We first need to
|
||||
// resolve the existing character if it exists
|
||||
CharSequence existingName = uniqueCharacters.get(charPrefix);
|
||||
if (existingName != null) {
|
||||
uniqueNames.put(existingName, mPeopleHelper.findNameSplit(existingName));
|
||||
uniqueCharacters.put(charPrefix, null);
|
||||
}
|
||||
uniqueNames.put(senderName, mPeopleHelper.findNameSplit(senderName));
|
||||
} else {
|
||||
uniqueNames.put(senderName, charPrefix);
|
||||
uniqueCharacters.put(charPrefix, senderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<CharSequence, String> uniqueNames = mPeopleHelper.mapUniqueNamesToPrefix(mGroups);
|
||||
|
||||
// Now that we have the correct symbols, let's look what we have cached
|
||||
ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.annotation.StyleRes;
|
||||
import android.app.Person;
|
||||
import android.content.Context;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
@@ -109,7 +110,10 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
|
||||
private boolean mIsInConversation = true;
|
||||
private ViewGroup mMessagingIconContainer;
|
||||
private int mConversationContentStart;
|
||||
private int mNonConversationMarginEnd;
|
||||
private int mNonConversationContentStart;
|
||||
private int mNonConversationPaddingStart;
|
||||
private int mConversationAvatarSize;
|
||||
private int mNonConversationAvatarSize;
|
||||
private int mNotificationTextMarginTop;
|
||||
|
||||
public MessagingGroup(@NonNull Context context) {
|
||||
@@ -141,16 +145,21 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
|
||||
mMessagingIconContainer = findViewById(R.id.message_icon_container);
|
||||
mContentContainer = findViewById(R.id.messaging_group_content_container);
|
||||
mSendingSpinnerContainer = findViewById(R.id.messaging_group_sending_progress_container);
|
||||
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
|
||||
Resources res = getResources();
|
||||
DisplayMetrics displayMetrics = res.getDisplayMetrics();
|
||||
mDisplaySize.x = displayMetrics.widthPixels;
|
||||
mDisplaySize.y = displayMetrics.heightPixels;
|
||||
mSenderTextPaddingSingleLine = getResources().getDimensionPixelSize(
|
||||
mSenderTextPaddingSingleLine = res.getDimensionPixelSize(
|
||||
R.dimen.messaging_group_singleline_sender_padding_end);
|
||||
mConversationContentStart = getResources().getDimensionPixelSize(
|
||||
R.dimen.conversation_content_start);
|
||||
mNonConversationMarginEnd = getResources().getDimensionPixelSize(
|
||||
R.dimen.messaging_layout_margin_end);
|
||||
mNotificationTextMarginTop = getResources().getDimensionPixelSize(
|
||||
mConversationContentStart = res.getDimensionPixelSize(R.dimen.conversation_content_start);
|
||||
mNonConversationContentStart = res.getDimensionPixelSize(
|
||||
R.dimen.notification_content_margin_start);
|
||||
mNonConversationPaddingStart = res.getDimensionPixelSize(
|
||||
R.dimen.messaging_layout_icon_padding_start);
|
||||
mConversationAvatarSize = res.getDimensionPixelSize(R.dimen.messaging_avatar_size);
|
||||
mNonConversationAvatarSize = res.getDimensionPixelSize(
|
||||
R.dimen.notification_icon_circle_size);
|
||||
mNotificationTextMarginTop = res.getDimensionPixelSize(
|
||||
R.dimen.notification_text_margin_top);
|
||||
}
|
||||
|
||||
@@ -696,10 +705,18 @@ public class MessagingGroup extends LinearLayout implements MessagingLinearLayou
|
||||
mIsInConversation = isInConversation;
|
||||
MarginLayoutParams layoutParams =
|
||||
(MarginLayoutParams) mMessagingIconContainer.getLayoutParams();
|
||||
layoutParams.width = mIsInConversation ? mConversationContentStart
|
||||
: ViewPager.LayoutParams.WRAP_CONTENT;
|
||||
layoutParams.setMarginEnd(mIsInConversation ? 0 : mNonConversationMarginEnd);
|
||||
layoutParams.width = mIsInConversation
|
||||
? mConversationContentStart
|
||||
: mNonConversationContentStart;
|
||||
mMessagingIconContainer.setLayoutParams(layoutParams);
|
||||
int imagePaddingStart = isInConversation ? 0 : mNonConversationPaddingStart;
|
||||
mMessagingIconContainer.setPaddingRelative(imagePaddingStart, 0, 0, 0);
|
||||
|
||||
ViewGroup.LayoutParams avatarLayoutParams = mAvatarView.getLayoutParams();
|
||||
int size = mIsInConversation ? mConversationAvatarSize : mNonConversationAvatarSize;
|
||||
avatarLayoutParams.height = size;
|
||||
avatarLayoutParams.width = size;
|
||||
mAvatarView.setLayoutParams(avatarLayoutParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.internal.widget;
|
||||
|
||||
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_AT_END;
|
||||
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_EXTERNAL;
|
||||
import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_INLINE;
|
||||
|
||||
import android.annotation.AttrRes;
|
||||
@@ -27,10 +27,6 @@ import android.app.Notification;
|
||||
import android.app.Person;
|
||||
import android.app.RemoteInputHistoryItem;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
@@ -40,21 +36,22 @@ import android.util.ArrayMap;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.RemotableViewMethod;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.PathInterpolator;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.RemoteViews;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.graphics.ColorUtils;
|
||||
import com.android.internal.util.ContrastColorUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
|
||||
@@ -65,15 +62,6 @@ public class MessagingLayout extends FrameLayout
|
||||
implements ImageMessageConsumer, IMessagingLayout {
|
||||
|
||||
private static final float COLOR_SHIFT_AMOUNT = 60;
|
||||
/**
|
||||
* Pattren for filter some ingonable characters.
|
||||
* p{Z} for any kind of whitespace or invisible separator.
|
||||
* p{C} for any kind of punctuation character.
|
||||
*/
|
||||
private static final Pattern IGNORABLE_CHAR_PATTERN
|
||||
= Pattern.compile("[\\p{C}\\p{Z}]");
|
||||
private static final Pattern SPECIAL_CHAR_PATTERN
|
||||
= Pattern.compile ("[!@#$%&*()_+=|<>?{}\\[\\]~-]");
|
||||
private static final Consumer<MessagingMessage> REMOVE_MESSAGE
|
||||
= MessagingMessage::removeMessage;
|
||||
public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
|
||||
@@ -81,26 +69,26 @@ public class MessagingLayout extends FrameLayout
|
||||
public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
|
||||
public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR
|
||||
= new MessagingPropertyAnimator();
|
||||
private final PeopleHelper mPeopleHelper = new PeopleHelper();
|
||||
private List<MessagingMessage> mMessages = new ArrayList<>();
|
||||
private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
|
||||
private MessagingLinearLayout mMessagingLinearLayout;
|
||||
private boolean mShowHistoricMessages;
|
||||
private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
|
||||
private TextView mTitleView;
|
||||
private MessagingLinearLayout mImageMessageContainer;
|
||||
private ImageView mRightIconView;
|
||||
private Rect mMessagingClipRect;
|
||||
private int mLayoutColor;
|
||||
private int mSenderTextColor;
|
||||
private int mMessageTextColor;
|
||||
private int mAvatarSize;
|
||||
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private Paint mTextPaint = new Paint();
|
||||
private CharSequence mConversationTitle;
|
||||
private Icon mAvatarReplacement;
|
||||
private boolean mIsOneToOne;
|
||||
private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
|
||||
private Person mUser;
|
||||
private CharSequence mNameReplacement;
|
||||
private boolean mDisplayImagesAtEnd;
|
||||
private boolean mIsCollapsed;
|
||||
private ImageResolver mImageResolver;
|
||||
private CharSequence mConversationTitle;
|
||||
|
||||
public MessagingLayout(@NonNull Context context) {
|
||||
super(context);
|
||||
@@ -123,17 +111,16 @@ public class MessagingLayout extends FrameLayout
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mPeopleHelper.init(getContext());
|
||||
mMessagingLinearLayout = findViewById(R.id.notification_messaging);
|
||||
mImageMessageContainer = findViewById(R.id.conversation_image_message_container);
|
||||
mRightIconView = findViewById(R.id.right_icon);
|
||||
// We still want to clip, but only on the top, since views can temporarily out of bounds
|
||||
// during transitions.
|
||||
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
|
||||
int size = Math.max(displayMetrics.widthPixels, displayMetrics.heightPixels);
|
||||
Rect rect = new Rect(0, 0, size, size);
|
||||
mMessagingLinearLayout.setClipBounds(rect);
|
||||
mTitleView = findViewById(R.id.title);
|
||||
mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
|
||||
mTextPaint.setTextAlign(Paint.Align.CENTER);
|
||||
mTextPaint.setAntiAlias(true);
|
||||
mMessagingClipRect = new Rect(0, 0, size, size);
|
||||
setMessagingClippingDisabled(false);
|
||||
}
|
||||
|
||||
@RemotableViewMethod
|
||||
@@ -153,7 +140,7 @@ public class MessagingLayout extends FrameLayout
|
||||
*/
|
||||
@RemotableViewMethod
|
||||
public void setIsCollapsed(boolean isCollapsed) {
|
||||
mDisplayImagesAtEnd = isCollapsed;
|
||||
mIsCollapsed = isCollapsed;
|
||||
}
|
||||
|
||||
@RemotableViewMethod
|
||||
@@ -168,7 +155,7 @@ public class MessagingLayout extends FrameLayout
|
||||
*/
|
||||
@RemotableViewMethod
|
||||
public void setConversationTitle(CharSequence conversationTitle) {
|
||||
// Unused
|
||||
mConversationTitle = conversationTitle;
|
||||
}
|
||||
|
||||
@RemotableViewMethod
|
||||
@@ -180,11 +167,6 @@ public class MessagingLayout extends FrameLayout
|
||||
List<Notification.MessagingStyle.Message> newHistoricMessages
|
||||
= Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
|
||||
setUser(extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON));
|
||||
mConversationTitle = null;
|
||||
TextView headerText = findViewById(R.id.header_text);
|
||||
if (headerText != null) {
|
||||
mConversationTitle = headerText.getText();
|
||||
}
|
||||
RemoteInputHistoryItem[] history = (RemoteInputHistoryItem[])
|
||||
extras.getParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS);
|
||||
addRemoteInputHistoryToMessages(newMessages, history);
|
||||
@@ -238,6 +220,41 @@ public class MessagingLayout extends FrameLayout
|
||||
|
||||
updateHistoricMessageVisibility();
|
||||
updateTitleAndNamesDisplay();
|
||||
// after groups are finalized, hide the first sender name if it's showing as the title
|
||||
mPeopleHelper.maybeHideFirstSenderName(mGroups, mIsOneToOne, mConversationTitle);
|
||||
updateImageMessages();
|
||||
}
|
||||
|
||||
private void updateImageMessages() {
|
||||
View newMessage = null;
|
||||
if (mImageMessageContainer == null) {
|
||||
return;
|
||||
}
|
||||
if (mIsCollapsed && !mGroups.isEmpty()) {
|
||||
// When collapsed, we're displaying the image message in a dedicated container
|
||||
// on the right of the layout instead of inline. Let's add the isolated image there
|
||||
MessagingGroup messagingGroup = mGroups.get(mGroups.size() - 1);
|
||||
MessagingImageMessage isolatedMessage = messagingGroup.getIsolatedMessage();
|
||||
if (isolatedMessage != null) {
|
||||
newMessage = isolatedMessage.getView();
|
||||
}
|
||||
}
|
||||
// Remove all messages that don't belong into the image layout
|
||||
View previousMessage = mImageMessageContainer.getChildAt(0);
|
||||
if (previousMessage != newMessage) {
|
||||
mImageMessageContainer.removeView(previousMessage);
|
||||
if (newMessage != null) {
|
||||
mImageMessageContainer.addView(newMessage);
|
||||
}
|
||||
}
|
||||
mImageMessageContainer.setVisibility(newMessage != null ? VISIBLE : GONE);
|
||||
|
||||
// When showing an image message, do not show the large icon. Removing the drawable
|
||||
// prevents it from being shown in the left_icon view (by the grouping util).
|
||||
if (newMessage != null && mRightIconView != null && mRightIconView.getDrawable() != null) {
|
||||
mRightIconView.setImageDrawable(null);
|
||||
mRightIconView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeGroups(ArrayList<MessagingGroup> oldGroups) {
|
||||
@@ -266,34 +283,7 @@ public class MessagingLayout extends FrameLayout
|
||||
}
|
||||
|
||||
private void updateTitleAndNamesDisplay() {
|
||||
ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
|
||||
ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>();
|
||||
for (int i = 0; i < mGroups.size(); i++) {
|
||||
MessagingGroup group = mGroups.get(i);
|
||||
CharSequence senderName = group.getSenderName();
|
||||
if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
|
||||
continue;
|
||||
}
|
||||
if (!uniqueNames.containsKey(senderName)) {
|
||||
// Only use visible characters to get uniqueNames
|
||||
String pureSenderName = IGNORABLE_CHAR_PATTERN
|
||||
.matcher(senderName).replaceAll("" /* replacement */);
|
||||
char c = pureSenderName.charAt(0);
|
||||
if (uniqueCharacters.containsKey(c)) {
|
||||
// this character was already used, lets make it more unique. We first need to
|
||||
// resolve the existing character if it exists
|
||||
CharSequence existingName = uniqueCharacters.get(c);
|
||||
if (existingName != null) {
|
||||
uniqueNames.put(existingName, findNameSplit((String) existingName));
|
||||
uniqueCharacters.put(c, null);
|
||||
}
|
||||
uniqueNames.put(senderName, findNameSplit((String) senderName));
|
||||
} else {
|
||||
uniqueNames.put(senderName, Character.toString(c));
|
||||
uniqueCharacters.put(c, pureSenderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
Map<CharSequence, String> uniqueNames = mPeopleHelper.mapUniqueNamesToPrefix(mGroups);
|
||||
|
||||
// Now that we have the correct symbols, let's look what we have cached
|
||||
ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
|
||||
@@ -337,26 +327,7 @@ public class MessagingLayout extends FrameLayout
|
||||
}
|
||||
|
||||
public Icon createAvatarSymbol(CharSequence senderName, String symbol, int layoutColor) {
|
||||
if (symbol.isEmpty() || TextUtils.isDigitsOnly(symbol) ||
|
||||
SPECIAL_CHAR_PATTERN.matcher(symbol).find()) {
|
||||
Icon avatarIcon = Icon.createWithResource(getContext(),
|
||||
com.android.internal.R.drawable.messaging_user);
|
||||
avatarIcon.setTint(findColor(senderName, layoutColor));
|
||||
return avatarIcon;
|
||||
} else {
|
||||
Bitmap bitmap = Bitmap.createBitmap(mAvatarSize, mAvatarSize, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
float radius = mAvatarSize / 2.0f;
|
||||
int color = findColor(senderName, layoutColor);
|
||||
mPaint.setColor(color);
|
||||
canvas.drawCircle(radius, radius, radius, mPaint);
|
||||
boolean needDarkText = ColorUtils.calculateLuminance(color) > 0.5f;
|
||||
mTextPaint.setColor(needDarkText ? Color.BLACK : Color.WHITE);
|
||||
mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.5f : mAvatarSize * 0.3f);
|
||||
int yPos = (int) (radius - ((mTextPaint.descent() + mTextPaint.ascent()) / 2));
|
||||
canvas.drawText(symbol, radius, yPos, mTextPaint);
|
||||
return Icon.createWithBitmap(bitmap);
|
||||
}
|
||||
return mPeopleHelper.createAvatarSymbol(senderName, symbol, layoutColor);
|
||||
}
|
||||
|
||||
private int findColor(CharSequence senderName, int layoutColor) {
|
||||
@@ -449,8 +420,8 @@ public class MessagingLayout extends FrameLayout
|
||||
newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
|
||||
mAddedGroups.add(newGroup);
|
||||
}
|
||||
newGroup.setImageDisplayLocation(mDisplayImagesAtEnd
|
||||
? IMAGE_DISPLAY_LOCATION_AT_END
|
||||
newGroup.setImageDisplayLocation(mIsCollapsed
|
||||
? IMAGE_DISPLAY_LOCATION_EXTERNAL
|
||||
: IMAGE_DISPLAY_LOCATION_INLINE);
|
||||
newGroup.setIsInConversation(false);
|
||||
newGroup.setLayoutColor(mLayoutColor);
|
||||
@@ -460,6 +431,8 @@ public class MessagingLayout extends FrameLayout
|
||||
if (sender != mUser && mNameReplacement != null) {
|
||||
nameOverride = mNameReplacement;
|
||||
}
|
||||
newGroup.setSingleLine(mIsCollapsed);
|
||||
newGroup.setShowingAvatar(!mIsCollapsed);
|
||||
newGroup.setSender(sender, nameOverride);
|
||||
newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
|
||||
mGroups.add(newGroup);
|
||||
@@ -600,12 +573,17 @@ public class MessagingLayout extends FrameLayout
|
||||
return mMessagingLinearLayout;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ViewGroup getImageMessageContainer() {
|
||||
return mImageMessageContainer;
|
||||
}
|
||||
|
||||
public ArrayList<MessagingGroup> getMessagingGroups() {
|
||||
return mGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMessagingClippingDisabled(boolean clippingDisabled) {
|
||||
// Don't do anything, this is only used for the ConversationLayout
|
||||
mMessagingLinearLayout.setClipBounds(clippingDisabled ? null : mMessagingClipRect);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT;
|
||||
|
||||
import android.annotation.ColorInt;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
@@ -28,12 +29,15 @@ import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.graphics.ColorUtils;
|
||||
import com.android.internal.util.ContrastColorUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
@@ -176,4 +180,58 @@ public class PeopleHelper {
|
||||
}
|
||||
return findNamePrefix(name, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mapping of the unique sender names in the groups to the string 1- or 2-character
|
||||
* prefix strings for the names, which are extracted as the initials, and should be used for
|
||||
* generating the avatar. Senders not requiring a generated avatar, or with an empty name are
|
||||
* omitted.
|
||||
*/
|
||||
public Map<CharSequence, String> mapUniqueNamesToPrefix(List<MessagingGroup> groups) {
|
||||
// Map of unique names to their prefix
|
||||
ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
|
||||
// Map of single-character string prefix to the only name which uses it, or null if multiple
|
||||
ArrayMap<String, CharSequence> uniqueCharacters = new ArrayMap<>();
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
MessagingGroup group = groups.get(i);
|
||||
CharSequence senderName = group.getSenderName();
|
||||
if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
|
||||
continue;
|
||||
}
|
||||
if (!uniqueNames.containsKey(senderName)) {
|
||||
String charPrefix = findNamePrefix(senderName, null);
|
||||
if (charPrefix == null) {
|
||||
continue;
|
||||
}
|
||||
if (uniqueCharacters.containsKey(charPrefix)) {
|
||||
// this character was already used, lets make it more unique. We first need to
|
||||
// resolve the existing character if it exists
|
||||
CharSequence existingName = uniqueCharacters.get(charPrefix);
|
||||
if (existingName != null) {
|
||||
uniqueNames.put(existingName, findNameSplit(existingName));
|
||||
uniqueCharacters.put(charPrefix, null);
|
||||
}
|
||||
uniqueNames.put(senderName, findNameSplit(senderName));
|
||||
} else {
|
||||
uniqueNames.put(senderName, charPrefix);
|
||||
uniqueCharacters.put(charPrefix, senderName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return uniqueNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update whether the groups can hide the sender if they are first
|
||||
* (happens only for 1:1 conversations where the given title matches the sender's name)
|
||||
*/
|
||||
public void maybeHideFirstSenderName(@NonNull List<MessagingGroup> groups,
|
||||
boolean isOneToOne, @Nullable CharSequence conversationTitle) {
|
||||
for (int i = groups.size() - 1; i >= 0; i--) {
|
||||
MessagingGroup messagingGroup = groups.get(i);
|
||||
CharSequence messageSender = messagingGroup.getSenderName();
|
||||
boolean canHide = isOneToOne && TextUtils.equals(conversationTitle, messageSender);
|
||||
messagingGroup.setCanHideSenderIfFirst(canHide);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2021 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
|
||||
-->
|
||||
<com.android.internal.widget.MessagingLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/status_bar_latest_event_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false"
|
||||
android:tag="messaging"
|
||||
>
|
||||
<include layout="@layout/notification_template_header"/>
|
||||
<com.android.internal.widget.RemeasuringLinearLayout
|
||||
android:id="@+id/notification_action_list_margin_target"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:layout_marginTop="@dimen/notification_content_margin_top"
|
||||
android:clipChildren="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.android.internal.widget.RemeasuringLinearLayout
|
||||
android:id="@+id/notification_main_column"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginEnd="@dimen/notification_content_margin_end"
|
||||
android:orientation="vertical"
|
||||
android:clipChildren="false"
|
||||
>
|
||||
<com.android.internal.widget.MessagingLinearLayout
|
||||
android:id="@+id/notification_messaging"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:spacing="@dimen/notification_messaging_spacing" />
|
||||
</com.android.internal.widget.RemeasuringLinearLayout>
|
||||
<include layout="@layout/notification_template_smart_reply_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/notification_content_margin"
|
||||
android:layout_marginStart="@dimen/notification_content_margin_start"
|
||||
android:layout_marginEnd="@dimen/notification_content_margin_end" />
|
||||
<include layout="@layout/notification_material_action_list" />
|
||||
</com.android.internal.widget.RemeasuringLinearLayout>
|
||||
<include layout="@layout/notification_template_right_icon" />
|
||||
</com.android.internal.widget.MessagingLayout>
|
||||
@@ -38,7 +38,7 @@
|
||||
<com.android.internal.widget.RemeasuringLinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-12dp"
|
||||
android:layout_marginTop="-20dp"
|
||||
android:clipChildren="false"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
@@ -22,32 +22,186 @@
|
||||
android:clipChildren="false"
|
||||
android:tag="messaging"
|
||||
>
|
||||
<include layout="@layout/notification_template_header"/>
|
||||
<com.android.internal.widget.RemeasuringLinearLayout
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
|
||||
<com.android.internal.widget.NotificationMaxHeightFrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/notification_min_height"
|
||||
android:clipChildren="false"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/left_icon"
|
||||
android:layout_width="@dimen/notification_left_icon_size"
|
||||
android:layout_height="@dimen/notification_left_icon_size"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:layout_marginStart="@dimen/notification_left_icon_start"
|
||||
android:background="@drawable/notification_large_icon_outline"
|
||||
android:clipToOutline="true"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerCrop"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<com.android.internal.widget.CachingIconView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="@dimen/notification_icon_circle_size"
|
||||
android:layout_height="@dimen/notification_icon_circle_size"
|
||||
android:layout_gravity="center_vertical|start"
|
||||
android:layout_marginStart="@dimen/notification_icon_circle_start"
|
||||
android:background="@drawable/notification_icon_circle"
|
||||
android:padding="@dimen/notification_icon_circle_padding"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/alternate_expand_target"
|
||||
android:layout_width="@dimen/notification_content_margin_start"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:importantForAccessibility="no"
|
||||
/>
|
||||
|
||||
<!--
|
||||
NOTE: to make the expansion animation of id/notification_messaging happen vertically,
|
||||
its X positioning must be the left edge of the notification, so instead of putting the
|
||||
layout_marginStart on the id/notification_headerless_view_row, we put it on
|
||||
id/notification_top_line, making the layout here just a bit different from the base.
|
||||
-->
|
||||
<LinearLayout
|
||||
android:id="@+id/notification_headerless_view_row"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:clipChildren="false"
|
||||
>
|
||||
|
||||
<!--
|
||||
NOTE: because messaging will always have 2 lines, this LinearLayout should NOT
|
||||
have the id/notification_headerless_view_column, as that is used for modifying
|
||||
vertical margins to accommodate the single-line state that base supports
|
||||
-->
|
||||
<LinearLayout
|
||||
android:layout_width="0px"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginBottom="@dimen/notification_headerless_margin_twoline"
|
||||
android:layout_marginTop="@dimen/notification_headerless_margin_twoline"
|
||||
android:clipChildren="false"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<NotificationTopLineView
|
||||
android:id="@+id/notification_top_line"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/notification_headerless_line_height"
|
||||
android:layout_marginStart="@dimen/notification_content_margin_start"
|
||||
android:clipChildren="false"
|
||||
android:theme="@style/Theme.DeviceDefault.Notification"
|
||||
>
|
||||
|
||||
<!--
|
||||
NOTE: The notification_top_line_views layout contains the app_name_text.
|
||||
In order to include the title view at the beginning, the Notification.Builder
|
||||
has logic to hide that view whenever this title view is to be visible.
|
||||
-->
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/notification_header_separating_margin"
|
||||
android:ellipsize="marquee"
|
||||
android:fadingEdge="horizontal"
|
||||
android:singleLine="true"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title"
|
||||
/>
|
||||
|
||||
<include layout="@layout/notification_top_line_views" />
|
||||
|
||||
</NotificationTopLineView>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/notification_main_column"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:clipChildren="false"
|
||||
>
|
||||
<com.android.internal.widget.MessagingLinearLayout
|
||||
android:id="@+id/notification_messaging"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipChildren="false"
|
||||
android:spacing="@dimen/notification_messaging_spacing" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Images -->
|
||||
<com.android.internal.widget.MessagingLinearLayout
|
||||
android:id="@+id/conversation_image_message_container"
|
||||
android:layout_width="@dimen/notification_right_icon_size"
|
||||
android:layout_height="@dimen/notification_right_icon_size"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
|
||||
android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
|
||||
android:layout_marginStart="@dimen/notification_right_icon_content_margin"
|
||||
android:forceHasOverlappingRendering="false"
|
||||
android:spacing="0dp"
|
||||
android:clipChildren="false"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/right_icon"
|
||||
android:layout_width="@dimen/notification_right_icon_size"
|
||||
android:layout_height="@dimen/notification_right_icon_size"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
android:layout_marginTop="@dimen/notification_right_icon_headerless_margin"
|
||||
android:layout_marginBottom="@dimen/notification_right_icon_headerless_margin"
|
||||
android:layout_marginStart="@dimen/notification_right_icon_content_margin"
|
||||
android:background="@drawable/notification_large_icon_outline"
|
||||
android:clipToOutline="true"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerCrop"
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/expand_button_touch_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:minWidth="@dimen/notification_content_margin_end"
|
||||
>
|
||||
|
||||
<include layout="@layout/notification_expand_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical|end"
|
||||
/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.internal.widget.NotificationMaxHeightFrameLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/notification_action_list_margin_target"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:layout_marginTop="@dimen/notification_content_margin_top"
|
||||
android:clipToPadding="false"
|
||||
android:layout_marginTop="-20dp"
|
||||
android:clipChildren="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.android.internal.widget.RemeasuringLinearLayout
|
||||
android:id="@+id/notification_main_column"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="top"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="@dimen/notification_content_margin_start"
|
||||
android:layout_marginEnd="@dimen/notification_content_margin_end"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
<com.android.internal.widget.MessagingLinearLayout
|
||||
android:id="@+id/notification_messaging"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:spacing="@dimen/notification_messaging_spacing" />
|
||||
</com.android.internal.widget.RemeasuringLinearLayout>
|
||||
<include layout="@layout/notification_template_smart_reply_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -55,6 +209,6 @@
|
||||
android:layout_marginStart="@dimen/notification_content_margin_start"
|
||||
android:layout_marginEnd="@dimen/notification_content_margin_end" />
|
||||
<include layout="@layout/notification_material_action_list" />
|
||||
</com.android.internal.widget.RemeasuringLinearLayout>
|
||||
<include layout="@layout/notification_template_right_icon" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.android.internal.widget.MessagingLayout>
|
||||
|
||||
@@ -803,8 +803,8 @@
|
||||
<!-- The padding of the conversation header when expanded. This is calculated from the expand button size + notification_content_margin_end -->
|
||||
<dimen name="conversation_header_expanded_padding_end">38dp</dimen>
|
||||
|
||||
<!-- margin at the end of messaging group icons when not conversations -->
|
||||
<dimen name="messaging_layout_margin_end">12dp</dimen>
|
||||
<!-- extra padding at the start of the icons when not conversations to keep them horizontally aligned with the notification icon -->
|
||||
<dimen name="messaging_layout_icon_padding_start">4dp</dimen>
|
||||
|
||||
<!-- Padding between text and sender when singleline -->
|
||||
<dimen name="messaging_group_singleline_sender_padding_end">4dp</dimen>
|
||||
|
||||
@@ -3015,6 +3015,7 @@
|
||||
|
||||
<java-symbol type="layout" name="app_anr_dialog" />
|
||||
<java-symbol type="layout" name="notification_template_material_messaging" />
|
||||
<java-symbol type="layout" name="notification_template_material_big_messaging" />
|
||||
|
||||
<java-symbol type="id" name="aerr_wait" />
|
||||
|
||||
@@ -3647,6 +3648,7 @@
|
||||
<java-symbol type="id" name="bubble_button" />
|
||||
<java-symbol type="id" name="snooze_button" />
|
||||
<java-symbol type="dimen" name="text_size_body_2_material" />
|
||||
<java-symbol type="dimen" name="notification_icon_circle_size" />
|
||||
<java-symbol type="dimen" name="messaging_avatar_size" />
|
||||
<java-symbol type="dimen" name="messaging_group_sending_progress_size" />
|
||||
<java-symbol type="dimen" name="messaging_image_rounding" />
|
||||
@@ -4063,7 +4065,7 @@
|
||||
<java-symbol type="dimen" name="conversation_badge_side_margin_group_expanded_face_pile" />
|
||||
<java-symbol type="dimen" name="conversation_content_start" />
|
||||
<java-symbol type="dimen" name="expanded_group_conversation_message_padding" />
|
||||
<java-symbol type="dimen" name="messaging_layout_margin_end" />
|
||||
<java-symbol type="dimen" name="messaging_layout_icon_padding_start" />
|
||||
<java-symbol type="dimen" name="conversation_header_expanded_padding_end" />
|
||||
<java-symbol type="dimen" name="conversation_icon_container_top_padding" />
|
||||
<java-symbol type="dimen" name="conversation_icon_container_top_padding_small_avatar" />
|
||||
|
||||
@@ -71,7 +71,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.util.ContrastColorUtil;
|
||||
import com.android.internal.widget.CachingIconView;
|
||||
import com.android.internal.widget.CallLayout;
|
||||
import com.android.internal.widget.MessagingLayout;
|
||||
import com.android.systemui.Dependency;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.animation.ActivityLaunchAnimator;
|
||||
@@ -658,10 +657,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
boolean beforeS = mEntry.targetSdk < Build.VERSION_CODES.S;
|
||||
int smallHeight;
|
||||
|
||||
View expandedView = layout.getExpandedChild();
|
||||
boolean isMediaLayout = expandedView != null
|
||||
&& expandedView.findViewById(com.android.internal.R.id.media_actions) != null;
|
||||
boolean isMessagingLayout = contractedView instanceof MessagingLayout;
|
||||
boolean isCallLayout = contractedView instanceof CallLayout;
|
||||
|
||||
if (customView && beforeS && !mIsSummaryWithChildren) {
|
||||
@@ -672,12 +667,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
|
||||
} else {
|
||||
smallHeight = mMaxSmallHeightBeforeS;
|
||||
}
|
||||
} else if (isMessagingLayout) {
|
||||
// TODO(b/173204301): MessagingStyle notifications currently look broken when we enforce
|
||||
// the standard notification height, so we have to afford them more vertical space to
|
||||
// make sure we don't crop them terribly. We actually need to revisit this and give
|
||||
// them a headerless design, then remove this hack.
|
||||
smallHeight = mMaxSmallHeightLarge;
|
||||
} else if (isCallLayout) {
|
||||
smallHeight = mMaxExpandedHeight;
|
||||
} else if (mUseIncreasedCollapsedHeight && layout == mPrivateLayout) {
|
||||
|
||||
@@ -23,12 +23,9 @@ import com.android.internal.widget.CachingIconView
|
||||
import com.android.internal.widget.ConversationLayout
|
||||
import com.android.internal.widget.MessagingLinearLayout
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.statusbar.TransformableView
|
||||
import com.android.systemui.statusbar.ViewTransformationHelper
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils
|
||||
import com.android.systemui.statusbar.notification.TransformState
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
|
||||
import com.android.systemui.statusbar.notification.row.HybridNotificationView
|
||||
import com.android.systemui.statusbar.notification.row.wrapper.NotificationMessagingTemplateViewWrapper.setCustomImageMessageTransform
|
||||
|
||||
/**
|
||||
* Wraps a notification containing a conversation template
|
||||
@@ -93,33 +90,7 @@ class NotificationConversationTemplateViewWrapper constructor(
|
||||
appName,
|
||||
conversationTitleView)
|
||||
|
||||
// Let's ignore the image message container since that is transforming as part of the
|
||||
// messages already
|
||||
mTransformationHelper.setCustomTransformation(
|
||||
object : ViewTransformationHelper.CustomTransformation() {
|
||||
override fun transformTo(
|
||||
ownState: TransformState,
|
||||
otherView: TransformableView,
|
||||
transformationAmount: Float
|
||||
): Boolean {
|
||||
if (otherView is HybridNotificationView) {
|
||||
return false
|
||||
}
|
||||
// we're hidden by default by the transformState
|
||||
ownState.ensureVisible()
|
||||
// Let's do nothing otherwise, this is already handled by the messages
|
||||
return true
|
||||
}
|
||||
|
||||
override fun transformFrom(
|
||||
ownState: TransformState,
|
||||
otherView: TransformableView,
|
||||
transformationAmount: Float
|
||||
): Boolean =
|
||||
transformTo(ownState, otherView, transformationAmount)
|
||||
},
|
||||
imageMessageContainer.id
|
||||
)
|
||||
setCustomImageMessageTransform(mTransformationHelper, imageMessageContainer)
|
||||
|
||||
addViewsTransformingToSimilar(
|
||||
conversationIconView,
|
||||
|
||||
@@ -18,12 +18,17 @@ package com.android.systemui.statusbar.notification.row.wrapper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.internal.widget.MessagingLayout;
|
||||
import com.android.internal.widget.MessagingLinearLayout;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.TransformableView;
|
||||
import com.android.systemui.statusbar.ViewTransformationHelper;
|
||||
import com.android.systemui.statusbar.notification.NotificationUtils;
|
||||
import com.android.systemui.statusbar.notification.TransformState;
|
||||
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.notification.row.HybridNotificationView;
|
||||
|
||||
/**
|
||||
* Wraps a notification containing a messaging template
|
||||
@@ -31,12 +36,17 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
|
||||
public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper {
|
||||
|
||||
private final int mMinHeightWithActions;
|
||||
private final View mTitle;
|
||||
private final View mTitleInHeader;
|
||||
private MessagingLayout mMessagingLayout;
|
||||
private MessagingLinearLayout mMessagingLinearLayout;
|
||||
private ViewGroup mImageMessageContainer;
|
||||
|
||||
protected NotificationMessagingTemplateViewWrapper(Context ctx, View view,
|
||||
ExpandableNotificationRow row) {
|
||||
super(ctx, view, row);
|
||||
mTitle = mView.findViewById(com.android.internal.R.id.title);
|
||||
mTitleInHeader = mView.findViewById(com.android.internal.R.id.header_text_secondary);
|
||||
mMessagingLayout = (MessagingLayout) view;
|
||||
mMinHeightWithActions = NotificationUtils.getFontScaledHeight(ctx,
|
||||
R.dimen.notification_messaging_actions_min_height);
|
||||
@@ -44,6 +54,7 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
|
||||
|
||||
private void resolveViews() {
|
||||
mMessagingLinearLayout = mMessagingLayout.getMessagingLinearLayout();
|
||||
mImageMessageContainer = mMessagingLayout.getImageMessageContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,8 +70,48 @@ public class NotificationMessagingTemplateViewWrapper extends NotificationTempla
|
||||
// This also clears the existing types
|
||||
super.updateTransformedTypes();
|
||||
if (mMessagingLinearLayout != null) {
|
||||
mTransformationHelper.addTransformedView(mMessagingLinearLayout.getId(),
|
||||
mMessagingLinearLayout);
|
||||
mTransformationHelper.addTransformedView(mMessagingLinearLayout);
|
||||
}
|
||||
// The title is not as important for messaging, and stays in the header when expanded,
|
||||
// but this ensures it animates cleanly between the two positions
|
||||
if (mTitle == null && mTitleInHeader != null) {
|
||||
mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TITLE,
|
||||
mTitleInHeader);
|
||||
}
|
||||
setCustomImageMessageTransform(mTransformationHelper, mImageMessageContainer);
|
||||
}
|
||||
|
||||
static void setCustomImageMessageTransform(
|
||||
ViewTransformationHelper transformationHelper, ViewGroup imageMessageContainer) {
|
||||
if (imageMessageContainer != null) {
|
||||
// Let's ignore the image message container since that is transforming as part of the
|
||||
// messages already. This is also required to prevent a clipping artifact caused by the
|
||||
// alpha layering triggering hardware rendering mode that in turn results in more
|
||||
// aggressive clipping than we want.
|
||||
transformationHelper.setCustomTransformation(
|
||||
new ViewTransformationHelper.CustomTransformation() {
|
||||
@Override
|
||||
public boolean transformTo(
|
||||
TransformState ownState,
|
||||
TransformableView otherView,
|
||||
float transformationAmount) {
|
||||
if (otherView instanceof HybridNotificationView) {
|
||||
return false;
|
||||
}
|
||||
// we're hidden by default by the transformState
|
||||
ownState.ensureVisible();
|
||||
// Let's do nothing otherwise, this is already handled by the messages
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean transformFrom(
|
||||
TransformState ownState,
|
||||
TransformableView otherView,
|
||||
float transformationAmount) {
|
||||
return transformTo(ownState, otherView, transformationAmount);
|
||||
}
|
||||
}, imageMessageContainer.getId());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
|
||||
private ProgressBar mProgressBar;
|
||||
private TextView mTitle;
|
||||
private TextView mText;
|
||||
protected View mSmartReplyContainer;
|
||||
protected View mActionsContainer;
|
||||
|
||||
private int mContentHeight;
|
||||
@@ -160,6 +161,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
|
||||
// It's still a viewstub
|
||||
mProgressBar = null;
|
||||
}
|
||||
mSmartReplyContainer = mView.findViewById(com.android.internal.R.id.smart_reply_container);
|
||||
mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
|
||||
mActions = mView.findViewById(com.android.internal.R.id.actions);
|
||||
mRemoteInputHistory = mView.findViewById(
|
||||
@@ -275,6 +277,7 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
|
||||
mProgressBar);
|
||||
}
|
||||
addViewsTransformingToSimilar(mLeftIcon);
|
||||
addTransformedViews(mSmartReplyContainer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user