1/*
2 * Copyright (C) 2010 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.gallery3d.ui;
18
19import android.graphics.Rect;
20import android.test.suitebuilder.annotation.SmallTest;
21import android.view.MotionEvent;
22
23import junit.framework.TestCase;
24
25@SmallTest
26public class GLViewTest extends TestCase {
27    @SuppressWarnings("unused")
28    private static final String TAG = "GLViewTest";
29
30    @SmallTest
31    public void testVisibility() {
32        GLViewMock a = new GLViewMock();
33        assertEquals(GLView.VISIBLE, a.getVisibility());
34        assertEquals(0, a.mOnVisibilityChangedCalled);
35        a.setVisibility(GLView.INVISIBLE);
36        assertEquals(GLView.INVISIBLE, a.getVisibility());
37        assertEquals(1, a.mOnVisibilityChangedCalled);
38        a.setVisibility(GLView.VISIBLE);
39        assertEquals(GLView.VISIBLE, a.getVisibility());
40        assertEquals(2, a.mOnVisibilityChangedCalled);
41    }
42
43    @SmallTest
44    public void testComponents() {
45        GLView view = new GLView();
46        assertEquals(0, view.getComponentCount());
47        try {
48            view.getComponent(0);
49            fail();
50        } catch (IndexOutOfBoundsException ex) {
51            // expected
52        }
53
54        GLView x = new GLView();
55        GLView y = new GLView();
56        view.addComponent(x);
57        view.addComponent(y);
58        assertEquals(2, view.getComponentCount());
59        assertSame(x, view.getComponent(0));
60        assertSame(y, view.getComponent(1));
61        view.removeComponent(x);
62        assertSame(y, view.getComponent(0));
63        try {
64            view.getComponent(1);
65            fail();
66        } catch (IndexOutOfBoundsException ex) {
67            // expected
68        }
69        try {
70            view.addComponent(y);
71            fail();
72        } catch (IllegalStateException ex) {
73            // expected
74        }
75        view.addComponent(x);
76        view.removeAllComponents();
77        assertEquals(0, view.getComponentCount());
78    }
79
80    @SmallTest
81    public void testBounds() {
82        GLView view = new GLView();
83
84        assertEquals(0, view.getWidth());
85        assertEquals(0, view.getHeight());
86
87        Rect b = view.bounds();
88        assertEquals(0, b.left);
89        assertEquals(0, b.top);
90        assertEquals(0, b.right);
91        assertEquals(0, b.bottom);
92
93        view.layout(10, 20, 30, 100);
94        assertEquals(20, view.getWidth());
95        assertEquals(80, view.getHeight());
96
97        b = view.bounds();
98        assertEquals(10, b.left);
99        assertEquals(20, b.top);
100        assertEquals(30, b.right);
101        assertEquals(100, b.bottom);
102    }
103
104    @SmallTest
105    public void testPaddings() {
106        GLView view = new GLView();
107
108        Rect p = view.getPaddings();
109        assertEquals(0, p.left);
110        assertEquals(0, p.top);
111        assertEquals(0, p.right);
112        assertEquals(0, p.bottom);
113
114        view.setPaddings(10, 20, 30, 100);
115        p = view.getPaddings();
116        assertEquals(10, p.left);
117        assertEquals(20, p.top);
118        assertEquals(30, p.right);
119        assertEquals(100, p.bottom);
120
121        p = new Rect(11, 22, 33, 104);
122        view.setPaddings(p);
123        p = view.getPaddings();
124        assertEquals(11, p.left);
125        assertEquals(22, p.top);
126        assertEquals(33, p.right);
127        assertEquals(104, p.bottom);
128    }
129
130    @SmallTest
131    public void testParent() {
132        GLView a = new GLView();
133        GLView b = new GLView();
134        assertNull(b.mParent);
135        a.addComponent(b);
136        assertSame(a, b.mParent);
137        a.removeComponent(b);
138        assertNull(b.mParent);
139    }
140
141    @SmallTest
142    public void testRoot() {
143        GLViewMock a = new GLViewMock();
144        GLViewMock b = new GLViewMock();
145        GLRoot r = new GLRootStub();
146        GLRoot r2 = new GLRootStub();
147        a.addComponent(b);
148
149        // Attach to root r
150        assertEquals(0, a.mOnAttachCalled);
151        assertEquals(0, b.mOnAttachCalled);
152        a.attachToRoot(r);
153        assertEquals(1, a.mOnAttachCalled);
154        assertEquals(1, b.mOnAttachCalled);
155        assertSame(r, a.getGLRoot());
156        assertSame(r, b.getGLRoot());
157
158        // Detach from r
159        assertEquals(0, a.mOnDetachCalled);
160        assertEquals(0, b.mOnDetachCalled);
161        a.detachFromRoot();
162        assertEquals(1, a.mOnDetachCalled);
163        assertEquals(1, b.mOnDetachCalled);
164
165        // Attach to another root r2
166        assertEquals(1, a.mOnAttachCalled);
167        assertEquals(1, b.mOnAttachCalled);
168        a.attachToRoot(r2);
169        assertEquals(2, a.mOnAttachCalled);
170        assertEquals(2, b.mOnAttachCalled);
171        assertSame(r2, a.getGLRoot());
172        assertSame(r2, b.getGLRoot());
173
174        // Detach from r2
175        assertEquals(1, a.mOnDetachCalled);
176        assertEquals(1, b.mOnDetachCalled);
177        a.detachFromRoot();
178        assertEquals(2, a.mOnDetachCalled);
179        assertEquals(2, b.mOnDetachCalled);
180    }
181
182    @SmallTest
183    public void testRoot2() {
184        GLView a = new GLViewMock();
185        GLViewMock b = new GLViewMock();
186        GLRoot r = new GLRootStub();
187
188        a.attachToRoot(r);
189
190        assertEquals(0, b.mOnAttachCalled);
191        a.addComponent(b);
192        assertEquals(1, b.mOnAttachCalled);
193
194        assertEquals(0, b.mOnDetachCalled);
195        a.removeComponent(b);
196        assertEquals(1, b.mOnDetachCalled);
197    }
198
199    @SmallTest
200    public void testInvalidate() {
201        GLView a = new GLView();
202        GLRootMock r = new GLRootMock();
203        a.attachToRoot(r);
204        assertEquals(0, r.mRequestRenderCalled);
205        a.invalidate();
206        assertEquals(1, r.mRequestRenderCalled);
207    }
208
209    @SmallTest
210    public void testRequestLayout() {
211        GLView a = new GLView();
212        GLView b = new GLView();
213        GLRootMock r = new GLRootMock();
214        a.attachToRoot(r);
215        a.addComponent(b);
216        assertEquals(0, r.mRequestLayoutContentPaneCalled);
217        b.requestLayout();
218        assertEquals(1, r.mRequestLayoutContentPaneCalled);
219    }
220
221    @SmallTest
222    public void testLayout() {
223        GLViewMock a = new GLViewMock();
224        GLViewMock b = new GLViewMock();
225        GLViewMock c = new GLViewMock();
226        GLRootMock r = new GLRootMock();
227
228        a.attachToRoot(r);
229        a.addComponent(b);
230        a.addComponent(c);
231
232        assertEquals(0, a.mOnLayoutCalled);
233        a.layout(10, 20, 60, 100);
234        assertEquals(1, a.mOnLayoutCalled);
235        assertEquals(1, b.mOnLayoutCalled);
236        assertEquals(1, c.mOnLayoutCalled);
237        assertTrue(a.mOnLayoutChangeSize);
238        assertTrue(b.mOnLayoutChangeSize);
239        assertTrue(c.mOnLayoutChangeSize);
240
241        // same size should not trigger onLayout
242        a.layout(10, 20, 60, 100);
243        assertEquals(1, a.mOnLayoutCalled);
244
245        // unless someone requested it, but only those on the path
246        // to the requester.
247        assertEquals(0, r.mRequestLayoutContentPaneCalled);
248        b.requestLayout();
249        a.layout(10, 20, 60, 100);
250        assertEquals(1, r.mRequestLayoutContentPaneCalled);
251        assertEquals(2, a.mOnLayoutCalled);
252        assertEquals(2, b.mOnLayoutCalled);
253        assertEquals(1, c.mOnLayoutCalled);
254    }
255
256    @SmallTest
257    public void testRender() {
258        GLViewMock a = new GLViewMock();
259        GLViewMock b = new GLViewMock();
260
261        a.addComponent(b);
262        GLCanvasStub canvas = new GLCanvasStub();
263        assertEquals(0, a.mRenderBackgroundCalled);
264        assertEquals(0, b.mRenderBackgroundCalled);
265        a.render(canvas);
266        assertEquals(1, a.mRenderBackgroundCalled);
267        assertEquals(1, b.mRenderBackgroundCalled);
268    }
269
270    @SmallTest
271    public void testMeasure() {
272        GLViewMock a = new GLViewMock();
273        GLViewMock b = new GLViewMock();
274        GLViewMock c = new GLViewMock();
275        GLRootMock r = new GLRootMock();
276
277        a.addComponent(b);
278        a.addComponent(c);
279        a.attachToRoot(r);
280
281        assertEquals(0, a.mOnMeasureCalled);
282        a.measure(100, 200);
283        assertEquals(1, a.mOnMeasureCalled);
284        assertEquals(1, b.mOnMeasureCalled);
285        assertEquals(100, a.mOnMeasureWidthSpec);
286        assertEquals(200, a.mOnMeasureHeightSpec);
287        assertEquals(100, b.mOnMeasureWidthSpec);
288        assertEquals(200, b.mOnMeasureHeightSpec);
289        assertEquals(100, a.getMeasuredWidth());
290        assertEquals(200, b.getMeasuredHeight());
291
292        // same spec should not trigger onMeasure
293        a.measure(100, 200);
294        assertEquals(1, a.mOnMeasureCalled);
295
296        // unless someone requested it, but only those on the path
297        // to the requester.
298        b.requestLayout();
299        a.measure(100, 200);
300        assertEquals(2, a.mOnMeasureCalled);
301        assertEquals(2, b.mOnMeasureCalled);
302        assertEquals(1, c.mOnMeasureCalled);
303    }
304
305    class MyGLView extends GLView {
306        private int mWidth;
307        int mOnTouchCalled;
308        int mOnTouchX;
309        int mOnTouchY;
310        int mOnTouchAction;
311
312        public MyGLView(int width) {
313            mWidth = width;
314        }
315
316        @Override
317        protected void onLayout(boolean changeSize, int left, int top,
318                int right, int bottom) {
319            // layout children from left to right
320            // call children's layout.
321            int x = 0;
322            for (int i = 0, n = getComponentCount(); i < n; ++i) {
323                GLView item = getComponent(i);
324                item.measure(0, 0);
325                int w = item.getMeasuredWidth();
326                int h = item.getMeasuredHeight();
327                item.layout(x, 0, x + w, h);
328                x += w;
329            }
330        }
331
332        @Override
333        protected void onMeasure(int widthSpec, int heightSpec) {
334            setMeasuredSize(mWidth, 100);
335        }
336
337        @Override
338        protected boolean onTouch(MotionEvent event) {
339            mOnTouchCalled++;
340            mOnTouchX = (int) event.getX();
341            mOnTouchY = (int) event.getY();
342            mOnTouchAction = event.getAction();
343            return true;
344        }
345    }
346
347    private MotionEvent NewMotionEvent(int action, int x, int y) {
348        return MotionEvent.obtain(0, 0, action, x, y, 0);
349    }
350
351    @SmallTest
352    public void testTouchEvent() {
353        // We construct a tree with four nodes. Only the x coordinate is used:
354        // A = [0..............................300)
355        // B = [0......100)
356        // C =             [100......200)
357        // D =             [100..150)
358
359        MyGLView a = new MyGLView(300);
360        MyGLView b = new MyGLView(100);
361        MyGLView c = new MyGLView(100);
362        MyGLView d = new MyGLView(50);
363        GLRoot r = new GLRootStub();
364
365        a.addComponent(b);
366        a.addComponent(c);
367        c.addComponent(d);
368        a.attachToRoot(r);
369        a.layout(0, 0, 300, 100);
370
371        int DOWN = MotionEvent.ACTION_DOWN;
372        int UP = MotionEvent.ACTION_UP;
373        int MOVE = MotionEvent.ACTION_MOVE;
374        int CANCEL = MotionEvent.ACTION_CANCEL;
375
376        // simple case
377        assertEquals(0, a.mOnTouchCalled);
378        a.dispatchTouchEvent(NewMotionEvent(DOWN, 250, 0));
379        assertEquals(DOWN, a.mOnTouchAction);
380        a.dispatchTouchEvent(NewMotionEvent(UP, 250, 0));
381        assertEquals(UP, a.mOnTouchAction);
382        assertEquals(2, a.mOnTouchCalled);
383
384        // pass to a child, check the location is offseted.
385        assertEquals(0, c.mOnTouchCalled);
386        a.dispatchTouchEvent(NewMotionEvent(DOWN, 175, 0));
387        a.dispatchTouchEvent(NewMotionEvent(UP, 175, 0));
388        assertEquals(75, c.mOnTouchX);
389        assertEquals(0, c.mOnTouchY);
390        assertEquals(2, c.mOnTouchCalled);
391        assertEquals(2, a.mOnTouchCalled);
392
393        // motion target cancel event
394        assertEquals(0, d.mOnTouchCalled);
395        a.dispatchTouchEvent(NewMotionEvent(DOWN, 125, 0));
396        assertEquals(1, d.mOnTouchCalled);
397        a.dispatchTouchEvent(NewMotionEvent(MOVE, 250, 0));
398        assertEquals(2, d.mOnTouchCalled);
399        a.dispatchTouchEvent(NewMotionEvent(MOVE, 50, 0));
400        assertEquals(3, d.mOnTouchCalled);
401        a.dispatchTouchEvent(NewMotionEvent(DOWN, 175, 0));
402        assertEquals(4, d.mOnTouchCalled);
403        assertEquals(CANCEL, d.mOnTouchAction);
404        assertEquals(3, c.mOnTouchCalled);
405        assertEquals(DOWN, c.mOnTouchAction);
406        a.dispatchTouchEvent(NewMotionEvent(UP, 175, 0));
407
408        // motion target is removed
409        assertEquals(4, d.mOnTouchCalled);
410        a.dispatchTouchEvent(NewMotionEvent(DOWN, 125, 0));
411        assertEquals(5, d.mOnTouchCalled);
412        a.removeComponent(c);
413        assertEquals(6, d.mOnTouchCalled);
414        assertEquals(CANCEL, d.mOnTouchAction);
415
416        // invisible component should not get events
417        assertEquals(2, a.mOnTouchCalled);
418        assertEquals(0, b.mOnTouchCalled);
419        b.setVisibility(GLView.INVISIBLE);
420        a.dispatchTouchEvent(NewMotionEvent(DOWN, 50, 0));
421        assertEquals(3, a.mOnTouchCalled);
422        assertEquals(0, b.mOnTouchCalled);
423    }
424}
425