1 /*
2  * Copyright (C) 2016 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.systemui.statusbar.notification;
18 
19 import android.text.Layout;
20 import android.text.Spanned;
21 import android.text.TextUtils;
22 import android.util.Pools;
23 import android.view.View;
24 import android.widget.TextView;
25 
26 /**
27  * A transform state of a mText view.
28 */
29 public class TextViewTransformState extends TransformState {
30 
31     private static Pools.SimplePool<TextViewTransformState> sInstancePool
32             = new Pools.SimplePool<>(40);
33     private TextView mText;
34 
35     @Override
initFrom(View view, TransformInfo transformInfo)36     public void initFrom(View view, TransformInfo transformInfo) {
37         super.initFrom(view, transformInfo);
38         mText = (TextView) view;
39     }
40 
41     @Override
sameAs(TransformState otherState)42     protected boolean sameAs(TransformState otherState) {
43         if (super.sameAs(otherState)) {
44             return true;
45         }
46         if (otherState instanceof TextViewTransformState) {
47             TextViewTransformState otherTvs = (TextViewTransformState) otherState;
48             if(TextUtils.equals(otherTvs.mText.getText(), mText.getText())) {
49                 int ownEllipsized = getEllipsisCount();
50                 int otherEllipsized = otherTvs.getEllipsisCount();
51                 return ownEllipsized == otherEllipsized
52                         && mText.getLineCount() == otherTvs.mText.getLineCount()
53                         && hasSameSpans(otherTvs);
54             }
55         }
56         return false;
57     }
58 
hasSameSpans(TextViewTransformState otherTvs)59     private boolean hasSameSpans(TextViewTransformState otherTvs) {
60         boolean hasSpans = mText instanceof Spanned;
61         boolean otherHasSpans = otherTvs.mText instanceof Spanned;
62         if (hasSpans != otherHasSpans) {
63             return false;
64         } else if (!hasSpans) {
65             return true;
66         }
67         // Actually both have spans, let's try to compare them
68         Spanned ownSpanned = (Spanned) mText;
69         Object[] spans = ownSpanned.getSpans(0, ownSpanned.length(), Object.class);
70         Spanned otherSpanned = (Spanned) otherTvs.mText;
71         Object[] otherSpans = otherSpanned.getSpans(0, otherSpanned.length(), Object.class);
72         if (spans.length != otherSpans.length) {
73             return false;
74         }
75         for (int i = 0; i < spans.length; i++) {
76             Object span = spans[i];
77             Object otherSpan = otherSpans[i];
78             if (!span.getClass().equals(otherSpan.getClass())) {
79                 return false;
80             }
81             if (ownSpanned.getSpanStart(span) != otherSpanned.getSpanStart(otherSpan)
82                     || ownSpanned.getSpanEnd(span) != otherSpanned.getSpanEnd(otherSpan)) {
83                 return false;
84             }
85         }
86         return true;
87     }
88 
89     @Override
transformScale(TransformState otherState)90     protected boolean transformScale(TransformState otherState) {
91         if (!(otherState instanceof TextViewTransformState)) {
92             return false;
93         }
94         TextViewTransformState otherTvs = (TextViewTransformState) otherState;
95         if (!TextUtils.equals(mText.getText(), otherTvs.mText.getText())) {
96             return false;
97         }
98         int lineCount = mText.getLineCount();
99         return lineCount == 1 && lineCount == otherTvs.mText.getLineCount()
100                 && getEllipsisCount() == otherTvs.getEllipsisCount()
101                 && getViewHeight() != otherTvs.getViewHeight();
102     }
103 
104     @Override
getViewWidth()105     protected int getViewWidth() {
106         Layout l = mText.getLayout();
107         if (l != null) {
108             return (int) l.getLineWidth(0);
109         }
110         return super.getViewWidth();
111     }
112 
113     @Override
getViewHeight()114     protected int getViewHeight() {
115         return mText.getLineHeight();
116     }
117 
getInnerHeight(TextView text)118     private int getInnerHeight(TextView text) {
119         return text.getHeight() - text.getPaddingTop() - text.getPaddingBottom();
120     }
121 
getEllipsisCount()122     private int getEllipsisCount() {
123         Layout l = mText.getLayout();
124         if (l != null) {
125             int lines = l.getLineCount();
126             if (lines > 0) {
127                 // we only care about the first line
128                 return l.getEllipsisCount(0);
129             }
130         }
131         return 0;
132     }
133 
obtain()134     public static TextViewTransformState obtain() {
135         TextViewTransformState instance = sInstancePool.acquire();
136         if (instance != null) {
137             return instance;
138         }
139         return new TextViewTransformState();
140     }
141 
142     @Override
recycle()143     public void recycle() {
144         super.recycle();
145         sInstancePool.release(this);
146     }
147 
148     @Override
reset()149     protected void reset() {
150         super.reset();
151         mText = null;
152     }
153 }
154