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
17package com.android.internal.widget;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertTrue;
22
23import android.content.Context;
24import android.support.test.InstrumentationRegistry;
25import android.support.test.filters.SmallTest;
26import android.text.Layout;
27import android.view.LayoutInflater;
28import android.view.View.MeasureSpec;
29
30import com.android.frameworks.coretests.R;
31
32import org.junit.Before;
33import org.junit.Test;
34
35import java.lang.reflect.Field;
36
37@SmallTest
38public 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
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
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
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
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
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
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
135        public FakeImageFloatingTextView(Context context,
136                int linesForIndent) {
137            super(context, null, 0, 0);
138            mNumLines = linesForIndent;
139        }
140
141        @Override
142        public int getLayoutHeight() {
143            return Math.max(LINE_HEIGHT, getMeasuredHeight());
144        }
145
146        @Override
147        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
148            setMeasuredDimension(
149                    getDefaultSize(500, widthMeasureSpec),
150                    clampToMultiplesOfLineHeight(resolveSize(getDesiredHeight(),
151                            heightMeasureSpec)));
152        }
153
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