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