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.internal.widget;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertFalse;
21 import static org.junit.Assert.assertTrue;
22 
23 import android.content.Context;
24 import android.view.LayoutInflater;
25 import android.view.View.MeasureSpec;
26 
27 import androidx.test.InstrumentationRegistry;
28 import androidx.test.filters.SmallTest;
29 
30 import com.android.frameworks.coretests.R;
31 
32 import org.junit.Before;
33 import org.junit.Test;
34 
35 import java.lang.reflect.Field;
36 
37 @SmallTest
38 public class MessagingLinearLayoutTest {
39 
40     public static final int WIDTH_SPEC = MeasureSpec.makeMeasureSpec(500, MeasureSpec.EXACTLY);
41     public static final int HEIGHT_SPEC = MeasureSpec.makeMeasureSpec(400, MeasureSpec.AT_MOST);
42     private Context mContext;
43     private MessagingLinearLayout mView;
44 
45     @Before
setup()46     public void setup() {
47         mContext = InstrumentationRegistry.getTargetContext();
48         // spacing: 5px
49         mView = (MessagingLinearLayout) LayoutInflater.from(mContext).inflate(
50                 R.layout.messaging_linear_layout_test, null);
51     }
52 
53     @Test
testSingleChild()54     public void testSingleChild() {
55         FakeImageFloatingTextView child = fakeChild(3);
56 
57         mView.addView(child);
58 
59         mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
60         mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
61 
62         assertFalse(child.isHidden());
63         assertEquals(150, mView.getMeasuredHeight());
64     }
65 
66     @Test
testLargeSmall()67     public void testLargeSmall() {
68         FakeImageFloatingTextView child1 = fakeChild(3);
69         FakeImageFloatingTextView child2 = fakeChild(1);
70 
71         mView.addView(child1);
72         mView.addView(child2);
73 
74         mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
75         mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
76 
77         assertFalse("child1 should not be hidden", child1.isHidden());
78         assertFalse("child2 should not be hidden", child2.isHidden());
79         assertEquals(205, mView.getMeasuredHeight());
80     }
81 
82     @Test
testSmallSmall()83     public void testSmallSmall() {
84         FakeImageFloatingTextView child1 = fakeChild(1);
85         FakeImageFloatingTextView child2 = fakeChild(1);
86 
87         mView.addView(child1);
88         mView.addView(child2);
89 
90         mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
91         mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
92 
93         assertFalse("child1 should not be hidden", child1.isHidden());
94         assertFalse("child2 should not be hidden", child2.isHidden());
95         assertEquals(105, mView.getMeasuredHeight());
96     }
97 
98     @Test
testLargeLarge()99     public void testLargeLarge() {
100         FakeImageFloatingTextView child1 = fakeChild(7);
101         FakeImageFloatingTextView child2 = fakeChild(7);
102 
103         mView.addView(child1);
104         mView.addView(child2);
105 
106         mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
107         mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
108 
109         assertTrue("child1 should be hidden", child1.isHidden());
110         assertFalse("child2 should not be hidden", child2.isHidden());
111         assertEquals(350, mView.getMeasuredHeight());
112     }
113 
114     @Test
testLargeSmall_largeWrapsWith3indentbutNotFullHeight_andHitsMax()115     public void testLargeSmall_largeWrapsWith3indentbutNotFullHeight_andHitsMax() {
116         FakeImageFloatingTextView child1 = fakeChild(7);
117         FakeImageFloatingTextView child2 = fakeChild(1);
118 
119         mView.addView(child1);
120         mView.addView(child2);
121 
122         mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
123         mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
124 
125         assertFalse("child1 should not be hidden", child1.isHidden());
126         assertFalse("child2 should not be hidden", child2.isHidden());
127         assertEquals(355, mView.getMeasuredHeight());;
128     }
129 
130     private class FakeImageFloatingTextView extends MessagingTextMessage {
131 
132         public static final int LINE_HEIGHT = 50;
133         private final int mNumLines;
134 
FakeImageFloatingTextView(Context context, int linesForIndent)135         public FakeImageFloatingTextView(Context context,
136                 int linesForIndent) {
137             super(context, null, 0, 0);
138             mNumLines = linesForIndent;
139         }
140 
141         @Override
getLayoutHeight()142         public int getLayoutHeight() {
143             return Math.max(LINE_HEIGHT, getMeasuredHeight());
144         }
145 
146         @Override
onMeasure(int widthMeasureSpec, int heightMeasureSpec)147         protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
148             setMeasuredDimension(
149                     getDefaultSize(500, widthMeasureSpec),
150                     clampToMultiplesOfLineHeight(resolveSize(getDesiredHeight(),
151                             heightMeasureSpec)));
152         }
153 
getMeasuredType()154         public int getMeasuredType() {
155             boolean measuredTooSmall = getMeasuredHeight()
156                     < getLayoutHeight() + getPaddingTop() + getPaddingBottom();
157             if (measuredTooSmall) {
158                 return MEASURED_TOO_SMALL;
159             } else {
160                 if (getMeasuredHeight() == getDesiredHeight()) {
161                     return MEASURED_NORMAL;
162                 } else {
163                     return MEASURED_SHORTENED;
164                 }
165             }
166         }
167 
168         private int clampToMultiplesOfLineHeight(int size) {
169             if (size <= LINE_HEIGHT) {
170                 return size;
171             }
172             return (size / LINE_HEIGHT) * LINE_HEIGHT;
173         }
174 
175         @Override
176         public int getLineCount() {
177             return mNumLines;
178         }
179 
180         public int getDesiredHeight() {
181             return LINE_HEIGHT * getLineCount();
182         }
183 
184         @Override
185         protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
186             // swallow
187         }
188 
189         public boolean isHidden() {
190             MessagingLinearLayout.LayoutParams lp =
191                     (MessagingLinearLayout.LayoutParams) getLayoutParams();
192             try {
193                 Field hide = MessagingLinearLayout.LayoutParams.class.getDeclaredField("hide");
194                 hide.setAccessible(true);
195                 return hide.getBoolean(lp);
196             } catch (ReflectiveOperationException e) {
197                 throw new RuntimeException(e);
198             }
199         }
200     }
201 
202     private FakeImageFloatingTextView fakeChild(int numLines) {
203         return new FakeImageFloatingTextView(mContext, numLines);
204     }
205 }
206