blob: c9a916187d338e0033e322f592a41f54d2869693 [file] [log] [blame]
Selim Cinek88188f22017-09-19 16:46:56 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License
15 */
16
17package com.android.internal.widget;
18
19import android.annotation.AttrRes;
20import android.annotation.NonNull;
21import android.annotation.Nullable;
22import android.annotation.StyleRes;
Selim Cinek9acd6732018-03-23 16:39:02 -070023import android.app.Person;
Selim Cinek88188f22017-09-19 16:46:56 -070024import android.content.Context;
Kenny Guya0f6de82018-04-06 16:20:16 +010025import android.content.res.ColorStateList;
26import android.graphics.Color;
Selim Cinek7199ed92018-01-26 13:36:43 -080027import android.graphics.Point;
28import android.graphics.Rect;
Selim Cinek88188f22017-09-19 16:46:56 -070029import android.graphics.drawable.Icon;
Selim Cinek1d6b50e2017-10-27 16:10:57 -070030import android.text.TextUtils;
Selim Cinek88188f22017-09-19 16:46:56 -070031import android.util.AttributeSet;
Selim Cinek7199ed92018-01-26 13:36:43 -080032import android.util.DisplayMetrics;
Selim Cinek88188f22017-09-19 16:46:56 -070033import android.util.Pools;
Kenny Guya0f6de82018-04-06 16:20:16 +010034import android.util.TypedValue;
Selim Cinek88188f22017-09-19 16:46:56 -070035import android.view.LayoutInflater;
36import android.view.View;
37import android.view.ViewGroup;
38import android.view.ViewParent;
Selim Cinekd3809992017-10-27 16:09:20 -070039import android.view.ViewTreeObserver;
Selim Cinek88188f22017-09-19 16:46:56 -070040import android.widget.ImageView;
41import android.widget.LinearLayout;
Kenny Guya0f6de82018-04-06 16:20:16 +010042import android.widget.ProgressBar;
Selim Cinek88188f22017-09-19 16:46:56 -070043import android.widget.RemoteViews;
44
45import com.android.internal.R;
Selim Cinek88188f22017-09-19 16:46:56 -070046
Selim Cinekd3809992017-10-27 16:09:20 -070047import java.util.ArrayList;
Selim Cinek88188f22017-09-19 16:46:56 -070048import java.util.List;
49
50/**
51 * A message of a {@link MessagingLayout}.
52 */
53@RemoteViews.RemoteView
54public class MessagingGroup extends LinearLayout implements MessagingLinearLayout.MessagingChild {
Selim Cinek88188f22017-09-19 16:46:56 -070055 private static Pools.SimplePool<MessagingGroup> sInstancePool
56 = new Pools.SynchronizedPool<>(10);
57 private MessagingLinearLayout mMessageContainer;
58 private ImageFloatingTextView mSenderName;
59 private ImageView mAvatarView;
60 private String mAvatarSymbol = "";
61 private int mLayoutColor;
62 private CharSequence mAvatarName = "";
63 private Icon mAvatarIcon;
Selim Cinek88188f22017-09-19 16:46:56 -070064 private int mTextColor;
Kenny Guya0f6de82018-04-06 16:20:16 +010065 private int mSendingTextColor;
Selim Cinek1d6b50e2017-10-27 16:10:57 -070066 private List<MessagingMessage> mMessages;
Selim Cinekd3809992017-10-27 16:09:20 -070067 private ArrayList<MessagingMessage> mAddedMessages = new ArrayList<>();
68 private boolean mFirstLayout;
69 private boolean mIsHidingAnimated;
Selim Cinekafeed292017-12-12 17:32:44 -080070 private boolean mNeedsGeneratedAvatar;
Selim Cinek9acd6732018-03-23 16:39:02 -070071 private Person mSender;
Selim Cinek85d0e6e2018-03-23 18:08:32 -070072 private boolean mImagesAtEnd;
Selim Cinek7199ed92018-01-26 13:36:43 -080073 private ViewGroup mImageContainer;
74 private MessagingImageMessage mIsolatedMessage;
75 private boolean mTransformingImages;
76 private Point mDisplaySize = new Point();
Kenny Guya0f6de82018-04-06 16:20:16 +010077 private ProgressBar mSendingSpinner;
78 private View mSendingSpinnerContainer;
Selim Cinek88188f22017-09-19 16:46:56 -070079
80 public MessagingGroup(@NonNull Context context) {
81 super(context);
82 }
83
84 public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
85 super(context, attrs);
86 }
87
88 public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs,
89 @AttrRes int defStyleAttr) {
90 super(context, attrs, defStyleAttr);
91 }
92
93 public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs,
94 @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
95 super(context, attrs, defStyleAttr, defStyleRes);
96 }
97
98 @Override
99 protected void onFinishInflate() {
100 super.onFinishInflate();
101 mMessageContainer = findViewById(R.id.group_message_container);
102 mSenderName = findViewById(R.id.message_name);
103 mAvatarView = findViewById(R.id.message_icon);
Selim Cinek7199ed92018-01-26 13:36:43 -0800104 mImageContainer = findViewById(R.id.messaging_group_icon_container);
Kenny Guya0f6de82018-04-06 16:20:16 +0100105 mSendingSpinner = findViewById(R.id.messaging_group_sending_progress);
106 mSendingSpinnerContainer = findViewById(R.id.messaging_group_sending_progress_container);
Selim Cinek7199ed92018-01-26 13:36:43 -0800107 DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
108 mDisplaySize.x = displayMetrics.widthPixels;
109 mDisplaySize.y = displayMetrics.heightPixels;
110 }
111
112 public void updateClipRect() {
113 // We want to clip to the senderName if it's available, otherwise our images will come
114 // from a weird position
115 Rect clipRect;
116 if (mSenderName.getVisibility() != View.GONE && !mTransformingImages) {
117 ViewGroup parent = (ViewGroup) mSenderName.getParent();
118 int top = getDistanceFromParent(mSenderName, parent) - getDistanceFromParent(
119 mMessageContainer, parent) + mSenderName.getHeight();
Selim Cinek1110fd72018-05-01 10:53:26 -0700120 int size = Math.max(mDisplaySize.x, mDisplaySize.y);
121 clipRect = new Rect(0, top, size, size);
Selim Cinek7199ed92018-01-26 13:36:43 -0800122 } else {
123 clipRect = null;
124 }
125 mMessageContainer.setClipBounds(clipRect);
126 }
127
128 private int getDistanceFromParent(View searchedView, ViewGroup parent) {
129 int position = 0;
130 View view = searchedView;
131 while(view != parent) {
132 position += view.getTop() + view.getTranslationY();
133 view = (View) view.getParent();
134 }
135 return position;
Selim Cinek88188f22017-09-19 16:46:56 -0700136 }
137
Selim Cinek9acd6732018-03-23 16:39:02 -0700138 public void setSender(Person sender, CharSequence nameOverride) {
Selim Cinek1397ea32018-01-16 17:34:52 -0800139 mSender = sender;
Selim Cinek2dd3e722018-01-19 11:06:06 -0800140 if (nameOverride == null) {
141 nameOverride = sender.getName();
142 }
143 mSenderName.setText(nameOverride);
Selim Cinekafeed292017-12-12 17:32:44 -0800144 mNeedsGeneratedAvatar = sender.getIcon() == null;
145 if (!mNeedsGeneratedAvatar) {
146 setAvatar(sender.getIcon());
Selim Cinek88188f22017-09-19 16:46:56 -0700147 }
Selim Cinekafeed292017-12-12 17:32:44 -0800148 mAvatarView.setVisibility(VISIBLE);
Selim Cinek0f6a0d02018-05-04 16:22:05 -0700149 mSenderName.setVisibility(TextUtils.isEmpty(nameOverride) ? GONE : VISIBLE);
Kenny Guya0f6de82018-04-06 16:20:16 +0100150 }
151
152 public void setSending(boolean sending) {
153 int visibility = sending ? View.VISIBLE : View.GONE;
154 if (mSendingSpinnerContainer.getVisibility() != visibility) {
155 mSendingSpinnerContainer.setVisibility(visibility);
156 updateMessageColor();
157 }
Selim Cinek88188f22017-09-19 16:46:56 -0700158 }
159
Kenny Guya0f6de82018-04-06 16:20:16 +0100160 private int calculateSendingTextColor() {
161 TypedValue alphaValue = new TypedValue();
162 mContext.getResources().getValue(
163 R.dimen.notification_secondary_text_disabled_alpha, alphaValue, true);
164 float alpha = alphaValue.getFloat();
165 return Color.valueOf(
166 Color.red(mTextColor),
167 Color.green(mTextColor),
168 Color.blue(mTextColor),
169 alpha).toArgb();
170 }
171
Selim Cinek88188f22017-09-19 16:46:56 -0700172 public void setAvatar(Icon icon) {
173 mAvatarIcon = icon;
174 mAvatarView.setImageIcon(icon);
175 mAvatarSymbol = "";
Selim Cinek88188f22017-09-19 16:46:56 -0700176 mAvatarName = "";
177 }
178
179 static MessagingGroup createGroup(MessagingLinearLayout layout) {;
180 MessagingGroup createdGroup = sInstancePool.acquire();
181 if (createdGroup == null) {
182 createdGroup = (MessagingGroup) LayoutInflater.from(layout.getContext()).inflate(
183 R.layout.notification_template_messaging_group, layout,
184 false);
Selim Cinekd3809992017-10-27 16:09:20 -0700185 createdGroup.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
Selim Cinek88188f22017-09-19 16:46:56 -0700186 }
187 layout.addView(createdGroup);
188 return createdGroup;
189 }
190
191 public void removeMessage(MessagingMessage messagingMessage) {
Selim Cinekf68af9b2018-05-24 16:37:22 -0700192 View view = messagingMessage.getView();
193 boolean wasShown = view.isShown();
194 ViewGroup messageParent = (ViewGroup) view.getParent();
195 if (messageParent == null) {
196 return;
197 }
198 messageParent.removeView(view);
Selim Cinekd3809992017-10-27 16:09:20 -0700199 Runnable recycleRunnable = () -> {
Selim Cinekf68af9b2018-05-24 16:37:22 -0700200 messageParent.removeTransientView(view);
Selim Cinekd3809992017-10-27 16:09:20 -0700201 messagingMessage.recycle();
Selim Cinekd3809992017-10-27 16:09:20 -0700202 };
Selim Cinekf68af9b2018-05-24 16:37:22 -0700203 if (wasShown && !MessagingLinearLayout.isGone(view)) {
204 messageParent.addTransientView(view, 0);
205 performRemoveAnimation(view, recycleRunnable);
Selim Cinekd3809992017-10-27 16:09:20 -0700206 } else {
207 recycleRunnable.run();
Selim Cinek88188f22017-09-19 16:46:56 -0700208 }
Selim Cinekd3809992017-10-27 16:09:20 -0700209 }
210
Selim Cinekf68af9b2018-05-24 16:37:22 -0700211 public void recycle() {
Selim Cinek7199ed92018-01-26 13:36:43 -0800212 if (mIsolatedMessage != null) {
Selim Cinekf68af9b2018-05-24 16:37:22 -0700213 mImageContainer.removeView(mIsolatedMessage);
Selim Cinek7199ed92018-01-26 13:36:43 -0800214 }
Selim Cinekf68af9b2018-05-24 16:37:22 -0700215 for (int i = 0; i < mMessages.size(); i++) {
216 MessagingMessage message = mMessages.get(i);
217 mMessageContainer.removeView(message.getView());
218 message.recycle();
Selim Cinekd3809992017-10-27 16:09:20 -0700219 }
Selim Cinekf68af9b2018-05-24 16:37:22 -0700220 setAvatar(null);
221 mAvatarView.setAlpha(1.0f);
222 mAvatarView.setTranslationY(0.0f);
223 mSenderName.setAlpha(1.0f);
224 mSenderName.setTranslationY(0.0f);
225 setAlpha(1.0f);
226 mIsolatedMessage = null;
227 mMessages = null;
228 mAddedMessages.clear();
229 mFirstLayout = true;
230 MessagingPropertyAnimator.recycle(this);
231 sInstancePool.release(MessagingGroup.this);
232 }
233
234 public void removeGroupAnimated(Runnable endAction) {
235 performRemoveAnimation(this, () -> {
236 setAlpha(1.0f);
237 MessagingPropertyAnimator.setToLaidOutPosition(this);
238 if (endAction != null) {
239 endAction.run();
240 }
241 });
Selim Cinekd3809992017-10-27 16:09:20 -0700242 }
243
Selim Cinek7199ed92018-01-26 13:36:43 -0800244 public void performRemoveAnimation(View message, Runnable endAction) {
Selim Cinekf68af9b2018-05-24 16:37:22 -0700245 performRemoveAnimation(message, -message.getHeight(), endAction);
246 }
247
248 private void performRemoveAnimation(View view, int disappearTranslation, Runnable endAction) {
249 MessagingPropertyAnimator.startLocalTranslationTo(view, disappearTranslation,
250 MessagingLayout.FAST_OUT_LINEAR_IN);
251 MessagingPropertyAnimator.fadeOut(view, endAction);
Selim Cinek88188f22017-09-19 16:46:56 -0700252 }
253
254 public CharSequence getSenderName() {
255 return mSenderName.getText();
256 }
257
Selim Cinek88188f22017-09-19 16:46:56 -0700258 public static void dropCache() {
259 sInstancePool = new Pools.SynchronizedPool<>(10);
260 }
261
262 @Override
263 public int getMeasuredType() {
Selim Cinek02fde732018-05-22 16:30:56 -0700264 if (mIsolatedMessage != null) {
265 // We only want to show one group if we have an inline image, so let's return shortened
266 // to avoid displaying the other ones.
267 return MEASURED_SHORTENED;
268 }
Selim Cinek88188f22017-09-19 16:46:56 -0700269 boolean hasNormal = false;
270 for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
271 View child = mMessageContainer.getChildAt(i);
Selim Cinek55726572018-05-02 17:22:20 -0700272 if (child.getVisibility() == GONE) {
273 continue;
274 }
Selim Cinek88188f22017-09-19 16:46:56 -0700275 if (child instanceof MessagingLinearLayout.MessagingChild) {
276 int type = ((MessagingLinearLayout.MessagingChild) child).getMeasuredType();
Selim Cinek55726572018-05-02 17:22:20 -0700277 boolean tooSmall = type == MEASURED_TOO_SMALL;
278 final MessagingLinearLayout.LayoutParams lp =
279 (MessagingLinearLayout.LayoutParams) child.getLayoutParams();
280 tooSmall |= lp.hide;
281 if (tooSmall) {
Selim Cinek88188f22017-09-19 16:46:56 -0700282 if (hasNormal) {
283 return MEASURED_SHORTENED;
284 } else {
285 return MEASURED_TOO_SMALL;
286 }
287 } else if (type == MEASURED_SHORTENED) {
288 return MEASURED_SHORTENED;
289 } else {
290 hasNormal = true;
291 }
292 }
293 }
294 return MEASURED_NORMAL;
295 }
296
297 @Override
298 public int getConsumedLines() {
299 int result = 0;
300 for (int i = 0; i < mMessageContainer.getChildCount(); i++) {
301 View child = mMessageContainer.getChildAt(i);
302 if (child instanceof MessagingLinearLayout.MessagingChild) {
303 result += ((MessagingLinearLayout.MessagingChild) child).getConsumedLines();
304 }
305 }
Selim Cinek7199ed92018-01-26 13:36:43 -0800306 result = mIsolatedMessage != null ? Math.max(result, 1) : result;
Selim Cineke62255c2017-09-28 18:23:23 -0700307 // A group is usually taking up quite some space with the padding and the name, let's add 1
308 return result + 1;
309 }
310
311 @Override
312 public void setMaxDisplayedLines(int lines) {
313 mMessageContainer.setMaxDisplayedLines(lines);
Selim Cinek88188f22017-09-19 16:46:56 -0700314 }
315
Selim Cinekd3809992017-10-27 16:09:20 -0700316 @Override
317 public void hideAnimated() {
318 setIsHidingAnimated(true);
319 removeGroupAnimated(() -> setIsHidingAnimated(false));
320 }
321
322 @Override
323 public boolean isHidingAnimated() {
324 return mIsHidingAnimated;
325 }
326
327 private void setIsHidingAnimated(boolean isHiding) {
328 ViewParent parent = getParent();
329 mIsHidingAnimated = isHiding;
330 invalidate();
331 if (parent instanceof ViewGroup) {
332 ((ViewGroup) parent).invalidate();
333 }
334 }
335
Selim Cinekf68af9b2018-05-24 16:37:22 -0700336 @Override
337 public boolean hasOverlappingRendering() {
338 return false;
339 }
340
Selim Cinek88188f22017-09-19 16:46:56 -0700341 public Icon getAvatarSymbolIfMatching(CharSequence avatarName, String avatarSymbol,
342 int layoutColor) {
343 if (mAvatarName.equals(avatarName) && mAvatarSymbol.equals(avatarSymbol)
344 && layoutColor == mLayoutColor) {
345 return mAvatarIcon;
346 }
347 return null;
348 }
349
350 public void setCreatedAvatar(Icon cachedIcon, CharSequence avatarName, String avatarSymbol,
351 int layoutColor) {
352 if (!mAvatarName.equals(avatarName) || !mAvatarSymbol.equals(avatarSymbol)
353 || layoutColor != mLayoutColor) {
354 setAvatar(cachedIcon);
355 mAvatarSymbol = avatarSymbol;
Kenny Guya0f6de82018-04-06 16:20:16 +0100356 setLayoutColor(layoutColor);
Selim Cinek88188f22017-09-19 16:46:56 -0700357 mAvatarName = avatarName;
358 }
359 }
360
Kenny Guy14d035c2018-05-02 19:10:36 +0100361 public void setTextColors(int senderTextColor, int messageTextColor) {
362 mTextColor = messageTextColor;
363 mSendingTextColor = calculateSendingTextColor();
364 updateMessageColor();
365 mSenderName.setTextColor(senderTextColor);
366 }
367
Selim Cinek88188f22017-09-19 16:46:56 -0700368 public void setLayoutColor(int layoutColor) {
Kenny Guya0f6de82018-04-06 16:20:16 +0100369 if (layoutColor != mLayoutColor){
370 mLayoutColor = layoutColor;
371 mSendingSpinner.setIndeterminateTintList(ColorStateList.valueOf(mLayoutColor));
372 }
373 }
374
375 private void updateMessageColor() {
376 if (mMessages != null) {
377 int color = mSendingSpinnerContainer.getVisibility() == View.VISIBLE
378 ? mSendingTextColor : mTextColor;
379 for (MessagingMessage message : mMessages) {
380 message.setColor(message.getMessage().isRemoteInputHistory() ? color : mTextColor);
381 }
382 }
Selim Cinek88188f22017-09-19 16:46:56 -0700383 }
384
385 public void setMessages(List<MessagingMessage> group) {
386 // Let's now make sure all children are added and in the correct order
Selim Cinek7199ed92018-01-26 13:36:43 -0800387 int textMessageIndex = 0;
388 MessagingImageMessage isolatedMessage = null;
Selim Cinek88188f22017-09-19 16:46:56 -0700389 for (int messageIndex = 0; messageIndex < group.size(); messageIndex++) {
390 MessagingMessage message = group.get(messageIndex);
391 if (message.getGroup() != this) {
392 message.setMessagingGroup(this);
Selim Cinekd3809992017-10-27 16:09:20 -0700393 mAddedMessages.add(message);
Selim Cinek88188f22017-09-19 16:46:56 -0700394 }
Selim Cinek7199ed92018-01-26 13:36:43 -0800395 boolean isImage = message instanceof MessagingImageMessage;
Selim Cinek85d0e6e2018-03-23 18:08:32 -0700396 if (mImagesAtEnd && isImage) {
Selim Cinek7199ed92018-01-26 13:36:43 -0800397 isolatedMessage = (MessagingImageMessage) message;
398 } else {
399 if (removeFromParentIfDifferent(message, mMessageContainer)) {
400 ViewGroup.LayoutParams layoutParams = message.getView().getLayoutParams();
401 if (layoutParams != null
402 && !(layoutParams instanceof MessagingLinearLayout.LayoutParams)) {
403 message.getView().setLayoutParams(
404 mMessageContainer.generateDefaultLayoutParams());
405 }
406 mMessageContainer.addView(message.getView(), textMessageIndex);
407 }
408 if (isImage) {
409 ((MessagingImageMessage) message).setIsolated(false);
410 }
411 // Let's sort them properly
412 if (textMessageIndex != mMessageContainer.indexOfChild(message.getView())) {
413 mMessageContainer.removeView(message.getView());
414 mMessageContainer.addView(message.getView(), textMessageIndex);
415 }
416 textMessageIndex++;
Selim Cinek88188f22017-09-19 16:46:56 -0700417 }
Selim Cinek88188f22017-09-19 16:46:56 -0700418 }
Selim Cinek7199ed92018-01-26 13:36:43 -0800419 if (isolatedMessage != null) {
420 if (removeFromParentIfDifferent(isolatedMessage, mImageContainer)) {
421 mImageContainer.removeAllViews();
422 mImageContainer.addView(isolatedMessage.getView());
423 }
424 isolatedMessage.setIsolated(true);
425 } else if (mIsolatedMessage != null) {
426 mImageContainer.removeAllViews();
427 }
428 mIsolatedMessage = isolatedMessage;
Selim Cinek1c72fa02018-04-23 18:00:54 +0800429 updateImageContainerVisibility();
Selim Cinek1d6b50e2017-10-27 16:10:57 -0700430 mMessages = group;
Kenny Guya0f6de82018-04-06 16:20:16 +0100431 updateMessageColor();
Selim Cinek88188f22017-09-19 16:46:56 -0700432 }
Selim Cinekd3809992017-10-27 16:09:20 -0700433
Selim Cinek1c72fa02018-04-23 18:00:54 +0800434 private void updateImageContainerVisibility() {
435 mImageContainer.setVisibility(mIsolatedMessage != null && mImagesAtEnd
436 ? View.VISIBLE : View.GONE);
437 }
438
Selim Cinek7199ed92018-01-26 13:36:43 -0800439 /**
440 * Remove the message from the parent if the parent isn't the one provided
441 * @return whether the message was removed
442 */
443 private boolean removeFromParentIfDifferent(MessagingMessage message, ViewGroup newParent) {
444 ViewParent parent = message.getView().getParent();
445 if (parent != newParent) {
446 if (parent instanceof ViewGroup) {
447 ((ViewGroup) parent).removeView(message.getView());
448 }
449 return true;
450 }
451 return false;
452 }
453
Selim Cinekd3809992017-10-27 16:09:20 -0700454 @Override
455 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
456 super.onLayout(changed, left, top, right, bottom);
457 if (!mAddedMessages.isEmpty()) {
Selim Cinekf68af9b2018-05-24 16:37:22 -0700458 final boolean firstLayout = mFirstLayout;
Selim Cinekd3809992017-10-27 16:09:20 -0700459 getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
460 @Override
461 public boolean onPreDraw() {
462 for (MessagingMessage message : mAddedMessages) {
Selim Cinek7199ed92018-01-26 13:36:43 -0800463 if (!message.getView().isShown()) {
Selim Cinekd3809992017-10-27 16:09:20 -0700464 continue;
465 }
Selim Cinek7199ed92018-01-26 13:36:43 -0800466 MessagingPropertyAnimator.fadeIn(message.getView());
Selim Cinekf68af9b2018-05-24 16:37:22 -0700467 if (!firstLayout) {
Selim Cinek7199ed92018-01-26 13:36:43 -0800468 MessagingPropertyAnimator.startLocalTranslationFrom(message.getView(),
469 message.getView().getHeight(),
470 MessagingLayout.LINEAR_OUT_SLOW_IN);
Selim Cinekd3809992017-10-27 16:09:20 -0700471 }
472 }
473 mAddedMessages.clear();
474 getViewTreeObserver().removeOnPreDrawListener(this);
475 return true;
476 }
477 });
478 }
479 mFirstLayout = false;
Selim Cinek7199ed92018-01-26 13:36:43 -0800480 updateClipRect();
Selim Cinekd3809992017-10-27 16:09:20 -0700481 }
482
Selim Cinek1d6b50e2017-10-27 16:10:57 -0700483 /**
484 * Calculates the group compatibility between this and another group.
485 *
486 * @param otherGroup the other group to compare it with
487 *
488 * @return 0 if the groups are totally incompatible or 1 + the number of matching messages if
489 * they match.
490 */
491 public int calculateGroupCompatibility(MessagingGroup otherGroup) {
492 if (TextUtils.equals(getSenderName(),otherGroup.getSenderName())) {
493 int result = 1;
494 for (int i = 0; i < mMessages.size() && i < otherGroup.mMessages.size(); i++) {
495 MessagingMessage ownMessage = mMessages.get(mMessages.size() - 1 - i);
496 MessagingMessage otherMessage = otherGroup.mMessages.get(
497 otherGroup.mMessages.size() - 1 - i);
498 if (!ownMessage.sameAs(otherMessage)) {
499 return result;
500 }
501 result++;
502 }
503 return result;
504 }
505 return 0;
506 }
507
Selim Cinek1397ea32018-01-16 17:34:52 -0800508 public View getSenderView() {
Selim Cinekd3809992017-10-27 16:09:20 -0700509 return mSenderName;
510 }
511
512 public View getAvatar() {
513 return mAvatarView;
514 }
Selim Cinek1d6b50e2017-10-27 16:10:57 -0700515
516 public MessagingLinearLayout getMessageContainer() {
517 return mMessageContainer;
518 }
Selim Cinekafeed292017-12-12 17:32:44 -0800519
Selim Cinek7199ed92018-01-26 13:36:43 -0800520 public MessagingImageMessage getIsolatedMessage() {
521 return mIsolatedMessage;
522 }
523
Selim Cinekafeed292017-12-12 17:32:44 -0800524 public boolean needsGeneratedAvatar() {
525 return mNeedsGeneratedAvatar;
526 }
Selim Cinek1397ea32018-01-16 17:34:52 -0800527
Selim Cinek9acd6732018-03-23 16:39:02 -0700528 public Person getSender() {
Selim Cinek1397ea32018-01-16 17:34:52 -0800529 return mSender;
530 }
Selim Cinek7199ed92018-01-26 13:36:43 -0800531
532 public void setTransformingImages(boolean transformingImages) {
533 mTransformingImages = transformingImages;
534 }
535
Selim Cinek85d0e6e2018-03-23 18:08:32 -0700536 public void setDisplayImagesAtEnd(boolean atEnd) {
537 if (mImagesAtEnd != atEnd) {
538 mImagesAtEnd = atEnd;
Selim Cinek1c72fa02018-04-23 18:00:54 +0800539 updateImageContainerVisibility();
Selim Cinek7199ed92018-01-26 13:36:43 -0800540 }
541 }
542
543 public List<MessagingMessage> getMessages() {
544 return mMessages;
545 }
Selim Cinek88188f22017-09-19 16:46:56 -0700546}