• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.camera.ui;
18 
19 import android.graphics.Matrix;
20 import android.graphics.Rect;
21 import android.os.SystemClock;
22 import android.view.MotionEvent;
23 import android.view.animation.Animation;
24 import android.view.animation.Transformation;
25 
26 import java.util.ArrayList;
27 
28 import javax.microedition.khronos.opengles.GL11;
29 
30 public class GLView {
31     @SuppressWarnings("unused")
32     private static final String TAG = "GLView";
33 
34     public static final int VISIBLE = 0;
35     public static final int INVISIBLE = 1;
36 
37     public static final int FLAG_INVISIBLE = 1;
38     public static final int FLAG_SET_MEASURED_SIZE = 2;
39     public static final int FLAG_LAYOUT_REQUESTED = 4;
40 
41     protected final Rect mBounds = new Rect();
42     protected final Rect mPaddings = new Rect();
43 
44     private GLRootView mRootView;
45     private GLView mParent;
46     private ArrayList<GLView> mComponents;
47     private GLView mMotionTarget;
48 
49     private OnTouchListener mOnTouchListener;
50     private Animation mAnimation;
51 
52     protected int mViewFlags = 0;
53 
54     protected int mMeasuredWidth = 0;
55     protected int mMeasuredHeight = 0;
56 
57     private int mLastWidthSpec = -1;
58     private int mLastHeightSpec = -1;
59 
60     protected int mScrollY = 0;
61     protected int mScrollX = 0;
62     protected int mScrollHeight = 0;
63     protected int mScrollWidth = 0;
64 
startAnimation(Animation animation)65     public void startAnimation(Animation animation) {
66         GLRootView root = getGLRootView();
67         if (root == null) throw new IllegalStateException();
68 
69         mAnimation = animation;
70         animation.initialize(getWidth(),
71                 getHeight(), mParent.getWidth(), mParent.getHeight());
72         mAnimation.start();
73         root.registerLaunchedAnimation(animation);
74         invalidate();
75     }
76 
setVisibility(int visibility)77     public void setVisibility(int visibility) {
78         if (visibility == getVisibility()) return;
79         if (visibility == VISIBLE) {
80             mViewFlags &= ~FLAG_INVISIBLE;
81         } else {
82             mViewFlags |= FLAG_INVISIBLE;
83         }
84         onVisibilityChanged(visibility);
85         invalidate();
86     }
87 
getVisibility()88     public int getVisibility() {
89         return (mViewFlags & FLAG_INVISIBLE) == 0 ? VISIBLE : INVISIBLE;
90     }
91 
92     public static interface OnTouchListener {
onTouch(GLView view, MotionEvent event)93         public boolean onTouch(GLView view, MotionEvent event);
94     }
95 
setBounds(int left, int top, int right, int bottom)96     private boolean setBounds(int left, int top, int right, int bottom) {
97         boolean sizeChanged = (right - left) != (mBounds.right - mBounds.left)
98                 || (bottom - top) != (mBounds.bottom - mBounds.top);
99         mBounds.set(left, top, right, bottom);
100         return sizeChanged;
101     }
102 
onAddToParent(GLView parent)103     protected void onAddToParent(GLView parent) {
104         // TODO: enable the check
105         // if (mParent != null) throw new IllegalStateException();
106         mParent = parent;
107         if (parent != null && parent.mRootView != null) {
108             onAttachToRoot(parent.mRootView);
109         }
110     }
111 
onRemoveFromParent(GLView parent)112     protected void onRemoveFromParent(GLView parent) {
113         if (parent != null && parent.mMotionTarget == this) {
114             long now = SystemClock.uptimeMillis();
115             dispatchTouchEvent(MotionEvent.obtain(
116                     now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0));
117             parent.mMotionTarget = null;
118         }
119         onDetachFromRoot();
120         mParent = null;
121     }
122 
clearComponents()123     public void clearComponents() {
124         mComponents = null;
125     }
126 
getComponentCount()127     public int getComponentCount() {
128         return mComponents == null ? 0 : mComponents.size();
129     }
130 
getComponent(int index)131     public GLView getComponent(int index) {
132         if (mComponents == null) {
133             throw new ArrayIndexOutOfBoundsException(index);
134         }
135         return mComponents.get(index);
136     }
137 
addComponent(GLView component)138     public void addComponent(GLView component) {
139         if (mComponents == null) {
140             mComponents = new ArrayList<GLView>();
141         }
142         mComponents.add(component);
143         component.onAddToParent(this);
144     }
145 
removeComponent(GLView component)146     public boolean removeComponent(GLView component) {
147         if (mComponents == null) return false;
148         if (mComponents.remove(component)) {
149             component.onRemoveFromParent(this);
150             return true;
151         }
152         return false;
153     }
154 
bounds()155     public Rect bounds() {
156         return mBounds;
157     }
158 
getWidth()159     public int getWidth() {
160         return mBounds.right - mBounds.left;
161     }
162 
getHeight()163     public int getHeight() {
164         return mBounds.bottom - mBounds.top;
165     }
166 
getGLRootView()167     public GLRootView getGLRootView() {
168         return mRootView;
169     }
170 
setOnTouchListener(OnTouchListener listener)171     public void setOnTouchListener(OnTouchListener listener) {
172         mOnTouchListener = listener;
173     }
174 
invalidate()175     public void invalidate() {
176         GLRootView root = getGLRootView();
177         if (root != null) root.requestRender();
178     }
179 
requestLayout()180     public void requestLayout() {
181         mViewFlags |= FLAG_LAYOUT_REQUESTED;
182         if (mParent != null) {
183             mParent.requestLayout();
184         } else {
185             // Is this a content pane ?
186             GLRootView root = getGLRootView();
187             if (root != null) root.requestLayoutContentPane();
188         }
189     }
190 
render(GLRootView view, GL11 gl)191     protected void render(GLRootView view, GL11 gl) {
192         renderBackground(view, gl);
193         for (int i = 0, n = getComponentCount(); i < n; ++i) {
194             GLView component = getComponent(i);
195             if (component.getVisibility() != GLView.VISIBLE
196                     && component.mAnimation == null) continue;
197             renderChild(view, gl, component);
198         }
199     }
200 
renderBackground(GLRootView view, GL11 gl)201     protected void renderBackground(GLRootView view, GL11 gl) {
202     }
203 
renderChild(GLRootView root, GL11 gl, GLView component)204     protected void renderChild(GLRootView root, GL11 gl, GLView component) {
205         int xoffset = component.mBounds.left - mScrollX;
206         int yoffset = component.mBounds.top - mScrollY;
207 
208         Transformation transform = root.getTransformation();
209         Matrix matrix = transform.getMatrix();
210         matrix.preTranslate(xoffset, yoffset);
211 
212         Animation anim = component.mAnimation;
213         if (anim != null) {
214             long now = root.currentAnimationTimeMillis();
215             Transformation temp = root.obtainTransformation();
216             if (!anim.getTransformation(now, temp)) {
217                 component.mAnimation = null;
218             }
219             invalidate();
220             root.pushTransform();
221             transform.compose(temp);
222             root.freeTransformation(temp);
223         }
224         component.render(root, gl);
225         if (anim != null) root.popTransform();
226         matrix.preTranslate(-xoffset, -yoffset);
227     }
228 
onTouch(MotionEvent event)229     protected boolean onTouch(MotionEvent event) {
230         if (mOnTouchListener != null) {
231             return mOnTouchListener.onTouch(this, event);
232         }
233         return false;
234     }
235 
dispatchTouchEvent(MotionEvent event, int x, int y, GLView component, boolean checkBounds)236     private boolean dispatchTouchEvent(MotionEvent event,
237             int x, int y, GLView component, boolean checkBounds) {
238         Rect rect = component.mBounds;
239         int left = rect.left;
240         int top = rect.top;
241         if (!checkBounds || rect.contains(x, y)) {
242             event.offsetLocation(-left, -top);
243             if (component.dispatchTouchEvent(event)) {
244                 event.offsetLocation(left, top);
245                 return true;
246             }
247             event.offsetLocation(left, top);
248         }
249         return false;
250     }
251 
dispatchTouchEvent(MotionEvent event)252     protected boolean dispatchTouchEvent(MotionEvent event) {
253         int x = (int) event.getX();
254         int y = (int) event.getY();
255         int action = event.getAction();
256         if (mMotionTarget != null) {
257             if (action == MotionEvent.ACTION_DOWN) {
258                 MotionEvent cancel = MotionEvent.obtain(event);
259                 cancel.setAction(MotionEvent.ACTION_CANCEL);
260                 mMotionTarget = null;
261             } else {
262                 dispatchTouchEvent(event, x, y, mMotionTarget, false);
263                 if (action == MotionEvent.ACTION_CANCEL
264                         || action == MotionEvent.ACTION_UP) {
265                     mMotionTarget = null;
266                 }
267                 return true;
268             }
269         }
270         if (action == MotionEvent.ACTION_DOWN) {
271             for (int i = 0, n = getComponentCount(); i < n; ++i) {
272                 GLView component = getComponent(i);
273                 if (component.getVisibility() != GLView.VISIBLE) continue;
274                 if (dispatchTouchEvent(event, x, y, component, true)) {
275                     mMotionTarget = component;
276                     return true;
277                 }
278             }
279         }
280         return onTouch(event);
281     }
282 
getPaddings()283     public Rect getPaddings() {
284         return mPaddings;
285     }
286 
setPaddings(Rect paddings)287     public void setPaddings(Rect paddings) {
288         mPaddings.set(paddings);
289     }
290 
setPaddings(int left, int top, int right, int bottom)291     public void setPaddings(int left, int top, int right, int bottom) {
292         mPaddings.set(left, top, right, bottom);
293     }
294 
layout(int left, int top, int right, int bottom)295     public void layout(int left, int top, int right, int bottom) {
296         boolean sizeChanged = setBounds(left, top, right, bottom);
297         if (sizeChanged) {
298             mViewFlags &= ~FLAG_LAYOUT_REQUESTED;
299             onLayout(true, left, top, right, bottom);
300         } else if ((mViewFlags & FLAG_LAYOUT_REQUESTED)!= 0) {
301             mViewFlags &= ~FLAG_LAYOUT_REQUESTED;
302             onLayout(false, left, top, right, bottom);
303         }
304     }
305 
measure(int widthSpec, int heightSpec)306     public void measure(int widthSpec, int heightSpec) {
307         if (widthSpec == mLastWidthSpec && heightSpec == mLastHeightSpec
308                 && (mViewFlags & FLAG_LAYOUT_REQUESTED) == 0) {
309             return;
310         }
311 
312         mLastWidthSpec = widthSpec;
313         mLastHeightSpec = heightSpec;
314 
315         mViewFlags &= ~FLAG_SET_MEASURED_SIZE;
316         onMeasure(widthSpec, heightSpec);
317         if ((mViewFlags & FLAG_SET_MEASURED_SIZE) == 0) {
318             throw new IllegalStateException(getClass().getName()
319                     + " should call setMeasuredSize() in onMeasure()");
320         }
321     }
322 
onMeasure(int widthSpec, int heightSpec)323     protected void onMeasure(int widthSpec, int heightSpec) {
324     }
325 
setMeasuredSize(int width, int height)326     protected void setMeasuredSize(int width, int height) {
327         mViewFlags |= FLAG_SET_MEASURED_SIZE;
328         mMeasuredWidth = width;
329         mMeasuredHeight = height;
330     }
331 
getMeasuredWidth()332     public int getMeasuredWidth() {
333         return mMeasuredWidth;
334     }
335 
getMeasuredHeight()336     public int getMeasuredHeight() {
337         return mMeasuredHeight;
338     }
339 
onLayout( boolean changeSize, int left, int top, int right, int bottom)340     protected void onLayout(
341             boolean changeSize, int left, int top, int right, int bottom) {
342     }
343 
344     /**
345      * Gets the bounds of the given descendant that relative to this view.
346      */
getBoundsOf(GLView descendant, Rect out)347     public boolean getBoundsOf(GLView descendant, Rect out) {
348         int xoffset = 0;
349         int yoffset = 0;
350         GLView view = descendant;
351         while (view != this) {
352             if (view == null) return false;
353             Rect bounds = view.mBounds;
354             xoffset += bounds.left;
355             yoffset += bounds.top;
356             view = view.mParent;
357         }
358         out.set(xoffset, yoffset, xoffset + descendant.getWidth(),
359                 yoffset + descendant.getHeight());
360         return true;
361     }
362 
onVisibilityChanged(int visibility)363     protected void onVisibilityChanged(int visibility) {
364         for (int i = 0, n = getComponentCount(); i < n; ++i) {
365             GLView child = getComponent(i);
366             if (child.getVisibility() == GLView.VISIBLE) {
367                 child.onVisibilityChanged(visibility);
368             }
369         }
370     }
371 
onAttachToRoot(GLRootView root)372     protected void onAttachToRoot(GLRootView root) {
373         mRootView = root;
374         for (int i = 0, n = getComponentCount(); i < n; ++i) {
375             getComponent(i).onAttachToRoot(root);
376         }
377     }
378 
onDetachFromRoot()379     protected void onDetachFromRoot() {
380         for (int i = 0, n = getComponentCount(); i < n; ++i) {
381             getComponent(i).onDetachFromRoot();
382         }
383         mRootView = null;
384     }
385 }
386