1 /* 2 * Copyright (C) 2018 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.annotation.AttrRes; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.StyleRes; 23 import android.app.Notification; 24 import android.content.Context; 25 import android.text.Layout; 26 import android.text.PrecomputedText; 27 import android.util.AttributeSet; 28 import android.util.Log; 29 import android.view.LayoutInflater; 30 import android.widget.RemoteViews; 31 32 import com.android.internal.R; 33 34 /** 35 * A message of a {@link MessagingLayout}. 36 */ 37 @RemoteViews.RemoteView 38 public class MessagingTextMessage extends ImageFloatingTextView implements MessagingMessage { 39 40 private static final String TAG = "MessagingTextMessage"; 41 private static final MessagingPool<MessagingTextMessage> sInstancePool = 42 new MessagingPool<>(20); 43 private final MessagingMessageState mState = new MessagingMessageState(this); 44 45 private PrecomputedText mPrecomputedText = null; 46 MessagingTextMessage(@onNull Context context)47 public MessagingTextMessage(@NonNull Context context) { 48 super(context); 49 } 50 MessagingTextMessage(@onNull Context context, @Nullable AttributeSet attrs)51 public MessagingTextMessage(@NonNull Context context, @Nullable AttributeSet attrs) { 52 super(context, attrs); 53 } 54 MessagingTextMessage(@onNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr)55 public MessagingTextMessage(@NonNull Context context, @Nullable AttributeSet attrs, 56 @AttrRes int defStyleAttr) { 57 super(context, attrs, defStyleAttr); 58 } 59 MessagingTextMessage(@onNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes)60 public MessagingTextMessage(@NonNull Context context, @Nullable AttributeSet attrs, 61 @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { 62 super(context, attrs, defStyleAttr, defStyleRes); 63 } 64 65 @Override getState()66 public MessagingMessageState getState() { 67 return mState; 68 } 69 70 @Override setMessage(Notification.MessagingStyle.Message message, boolean usePrecomputedText)71 public boolean setMessage(Notification.MessagingStyle.Message message, 72 boolean usePrecomputedText) { 73 MessagingMessage.super.setMessage(message, usePrecomputedText); 74 if (usePrecomputedText) { 75 mPrecomputedText = PrecomputedText.create(message.getText(), getTextMetricsParams()); 76 } else { 77 setText(message.getText()); 78 mPrecomputedText = null; 79 } 80 81 return true; 82 } 83 createMessage(IMessagingLayout layout, Notification.MessagingStyle.Message m, boolean usePrecomputedText)84 static MessagingMessage createMessage(IMessagingLayout layout, 85 Notification.MessagingStyle.Message m, boolean usePrecomputedText) { 86 MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout(); 87 MessagingTextMessage createdMessage = sInstancePool.acquire(); 88 if (createdMessage == null) { 89 createdMessage = (MessagingTextMessage) LayoutInflater.from( 90 layout.getContext()).inflate( 91 R.layout.notification_template_messaging_text_message, 92 messagingLinearLayout, 93 false); 94 createdMessage.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR); 95 } 96 createdMessage.setMessage(m, usePrecomputedText); 97 return createdMessage; 98 } 99 recycle()100 public void recycle() { 101 MessagingMessage.super.recycle(); 102 sInstancePool.release(this); 103 } 104 dropCache()105 public static void dropCache() { 106 sInstancePool.clear(); 107 } 108 109 @Override getMeasuredType()110 public int getMeasuredType() { 111 boolean measuredTooSmall = getMeasuredHeight() 112 < getLayoutHeight() + getPaddingTop() + getPaddingBottom(); 113 if (measuredTooSmall && getLineCount() <= 1) { 114 return MEASURED_TOO_SMALL; 115 } else { 116 Layout layout = getLayout(); 117 if (layout == null) { 118 return MEASURED_TOO_SMALL; 119 } 120 if (layout.getEllipsisCount(layout.getLineCount() - 1) > 0) { 121 return MEASURED_SHORTENED; 122 } else { 123 return MEASURED_NORMAL; 124 } 125 } 126 } 127 128 @Override 129 public void setMaxDisplayedLines(int lines) { 130 setMaxLines(lines); 131 } 132 133 @Override 134 public int getConsumedLines() { 135 return getLineCount(); 136 } 137 138 public int getLayoutHeight() { 139 Layout layout = getLayout(); 140 if (layout == null) { 141 return 0; 142 } 143 return layout.getHeight(); 144 } 145 146 @Override 147 public void setColor(int color) { 148 setTextColor(color); 149 } 150 151 @Override 152 public void finalizeInflate() { 153 try { 154 setText(mPrecomputedText != null ? mPrecomputedText 155 : getState().getMessage().getText()); 156 } catch (IllegalArgumentException exception) { 157 Log.wtf( 158 /* tag = */ TAG, 159 /* msg = */ "PrecomputedText setText failed for TextView:" + this, 160 /* tr = */ exception 161 ); 162 mPrecomputedText = null; 163 setText(getState().getMessage().getText()); 164 } 165 } 166 } 167