1 /* 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 17 package com.android.internal.widget; 18 19 import android.app.ActivityManager; 20 import android.app.Notification; 21 import android.view.View; 22 23 import java.util.ArrayList; 24 import java.util.Objects; 25 26 /** 27 * A message of a {@link MessagingLayout}. 28 */ 29 public interface MessagingMessage extends MessagingLinearLayout.MessagingChild { 30 31 /** 32 * Prefix for supported image MIME types 33 **/ 34 String IMAGE_MIME_TYPE_PREFIX = "image/"; 35 createMessage(IMessagingLayout layout, Notification.MessagingStyle.Message m, ImageResolver resolver)36 static MessagingMessage createMessage(IMessagingLayout layout, 37 Notification.MessagingStyle.Message m, ImageResolver resolver) { 38 if (hasImage(m) && !ActivityManager.isLowRamDeviceStatic()) { 39 return MessagingImageMessage.createMessage(layout, m, resolver); 40 } else { 41 return MessagingTextMessage.createMessage(layout, m); 42 } 43 } 44 dropCache()45 static void dropCache() { 46 MessagingTextMessage.dropCache(); 47 MessagingImageMessage.dropCache(); 48 } 49 hasImage(Notification.MessagingStyle.Message m)50 static boolean hasImage(Notification.MessagingStyle.Message m) { 51 return m.getDataUri() != null 52 && m.getDataMimeType() != null 53 && m.getDataMimeType().startsWith(IMAGE_MIME_TYPE_PREFIX); 54 } 55 56 /** 57 * Set a message for this view. 58 * @return true if setting the message worked 59 */ setMessage(Notification.MessagingStyle.Message message)60 default boolean setMessage(Notification.MessagingStyle.Message message) { 61 getState().setMessage(message); 62 return true; 63 } 64 getMessage()65 default Notification.MessagingStyle.Message getMessage() { 66 return getState().getMessage(); 67 } 68 sameAs(Notification.MessagingStyle.Message message)69 default boolean sameAs(Notification.MessagingStyle.Message message) { 70 Notification.MessagingStyle.Message ownMessage = getMessage(); 71 if (!Objects.equals(message.getText(), ownMessage.getText())) { 72 return false; 73 } 74 if (!Objects.equals(message.getSender(), ownMessage.getSender())) { 75 return false; 76 } 77 boolean hasRemoteInputHistoryChanged = message.isRemoteInputHistory() 78 != ownMessage.isRemoteInputHistory(); 79 // When the remote input history has changed, we want to regard messages equal even when 80 // the timestamp changes. The main reason is that the message that the system inserts 81 // will have a different time set than the one that the app will update us with and we 82 // still want to reuse that message. 83 if (!hasRemoteInputHistoryChanged 84 && !Objects.equals(message.getTimestamp(), ownMessage.getTimestamp())) { 85 return false; 86 } 87 if (!Objects.equals(message.getDataMimeType(), ownMessage.getDataMimeType())) { 88 return false; 89 } 90 if (!Objects.equals(message.getDataUri(), ownMessage.getDataUri())) { 91 return false; 92 } 93 return true; 94 } 95 sameAs(MessagingMessage message)96 default boolean sameAs(MessagingMessage message) { 97 return sameAs(message.getMessage()); 98 } 99 removeMessage(ArrayList<MessagingLinearLayout.MessagingChild> toRecycle)100 default void removeMessage(ArrayList<MessagingLinearLayout.MessagingChild> toRecycle) { 101 getGroup().removeMessage(this, toRecycle); 102 } 103 setMessagingGroup(MessagingGroup group)104 default void setMessagingGroup(MessagingGroup group) { 105 getState().setGroup(group); 106 } 107 setIsHistoric(boolean isHistoric)108 default void setIsHistoric(boolean isHistoric) { 109 getState().setIsHistoric(isHistoric); 110 } 111 getGroup()112 default MessagingGroup getGroup() { 113 return getState().getGroup(); 114 } 115 setIsHidingAnimated(boolean isHiding)116 default void setIsHidingAnimated(boolean isHiding) { 117 getState().setIsHidingAnimated(isHiding); 118 } 119 120 @Override isHidingAnimated()121 default boolean isHidingAnimated() { 122 return getState().isHidingAnimated(); 123 } 124 125 @Override hideAnimated()126 default void hideAnimated() { 127 setIsHidingAnimated(true); 128 getGroup().performRemoveAnimation(getView(), () -> setIsHidingAnimated(false)); 129 } 130 hasOverlappingRendering()131 default boolean hasOverlappingRendering() { 132 return false; 133 } 134 recycle()135 default void recycle() { 136 getState().recycle(); 137 } 138 getView()139 default View getView() { 140 return (View) this; 141 } 142 setColor(int textColor)143 default void setColor(int textColor) {} 144 getState()145 MessagingMessageState getState(); 146 setVisibility(int visibility)147 void setVisibility(int visibility); 148 getVisibility()149 int getVisibility(); 150 } 151