1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.ui;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
197a5e1e771ae58241f3a2be36f23025f282032261Owen Linimport android.annotation.TargetApi;
20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context;
21bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport android.graphics.Matrix;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.PixelFormat;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.opengl.GLSurfaceView;
24df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Linimport android.os.Build;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Process;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.SystemClock;
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.util.AttributeSet;
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent;
2979cf902f4cc602774e90bc2040f0029978becb61Owen Linimport android.view.SurfaceHolder;
30edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Changimport android.view.View;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
32edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Changimport com.android.gallery3d.R;
332b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.anim.CanvasAnimation;
347a5e1e771ae58241f3a2be36f23025f282032261Owen Linimport com.android.gallery3d.common.ApiHelper;
352b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.Utils;
36a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.BasicTexture;
37a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.GLCanvas;
3850b33abe053ccab7be3d1bca2328e792507963d4George Mountimport com.android.gallery3d.glrenderer.GLES11Canvas;
3950b33abe053ccab7be3d1bca2328e792507963d4George Mountimport com.android.gallery3d.glrenderer.GLES20Canvas;
40a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.UploadedTexture;
412b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.GalleryUtils;
428fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Changimport com.android.gallery3d.util.MotionEventHelper;
432b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.Profile;
442b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
45d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Linimport java.util.ArrayDeque;
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList;
471ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Changimport java.util.concurrent.locks.Condition;
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.locks.ReentrantLock;
492b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.egl.EGLConfig;
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL10;
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL11;
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// The root component of all <code>GLView</code>s. The rendering is done in GL
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// thread while the event handling is done in the main thread.  To synchronize
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// the two threads, the entry points of this package need to synchronize on the
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// <code>GLRootView</code> instance unless it can be proved that the rendering
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// thread won't access the same thing as the method. The entry points include:
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (1) The public methods of HeadUpDisplay
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (2) The public methods of CameraHeadUpDisplay
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (3) The overridden methods in GLRootView.
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class GLRootView extends GLSurfaceView
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        implements GLSurfaceView.Renderer, GLRoot {
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "GLRootView";
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final boolean DEBUG_FPS = false;
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mFrameCount = 0;
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private long mFrameCountingStart = 0;
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final boolean DEBUG_INVALIDATE = false;
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mInvalidateColor = 0;
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final boolean DEBUG_DRAWING_STAT = false;
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
753d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private static final boolean DEBUG_PROFILE = false;
767d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang    private static final boolean DEBUG_PROFILE_SLOW_ONLY = false;
773d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int FLAG_INITIALIZED = 1;
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int FLAG_NEED_LAYOUT = 2;
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private GL11 mGL;
827b83fb8e3a8978b33a6b9bfc56d85fe2c1a9cf06Chih-Chung Chang    private GLCanvas mCanvas;
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private GLView mContentView;
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
852ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    private OrientationSource mOrientationSource;
86bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // mCompensation is the difference between the UI orientation on GLCanvas
87bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // and the framework orientation. See OrientationManager for details.
88bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private int mCompensation;
89bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // mCompensationMatrix maps the coordinates of touch events. It is kept sync
90bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // with mCompensation.
91bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private Matrix mCompensationMatrix = new Matrix();
922ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    private int mDisplayRotation;
932ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mFlags = FLAG_NEED_LAYOUT;
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private volatile boolean mRenderRequested = false;
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final ArrayList<CanvasAnimation> mAnimations =
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            new ArrayList<CanvasAnimation>();
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
100d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final ArrayDeque<OnGLIdleListener> mIdleListeners =
101d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            new ArrayDeque<OnGLIdleListener>();
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final IdleRunner mIdleRunner = new IdleRunner();
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final ReentrantLock mRenderLock = new ReentrantLock();
1061ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang    private final Condition mFreezeCondition =
1071ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang            mRenderLock.newCondition();
1081ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang    private boolean mFreeze;
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private long mLastDrawFinishTime;
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean mInDownState = false;
112edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang    private boolean mFirstDraw = true;
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public GLRootView(Context context) {
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        this(context, null);
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public GLRootView(Context context, AttributeSet attrs) {
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        super(context, attrs);
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mFlags |= FLAG_INITIALIZED;
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setBackgroundDrawable(null);
12250b33abe053ccab7be3d1bca2328e792507963d4George Mount        setEGLContextClientVersion(ApiHelper.HAS_GLES20_REQUIRED ? 2 : 1);
123ac94740cd673a016542d803c8600633c99b7427eGeorge Mount        if (ApiHelper.USE_888_PIXEL_FORMAT) {
124ac94740cd673a016542d803c8600633c99b7427eGeorge Mount            setEGLConfigChooser(8, 8, 8, 0, 0, 0);
125ac94740cd673a016542d803c8600633c99b7427eGeorge Mount        } else {
126ac94740cd673a016542d803c8600633c99b7427eGeorge Mount            setEGLConfigChooser(5, 6, 5, 0, 0, 0);
127ac94740cd673a016542d803c8600633c99b7427eGeorge Mount        }
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setRenderer(this);
1292e1771b997ab6966411b2c612562c538ae3e325dPin Ting        if (ApiHelper.USE_888_PIXEL_FORMAT) {
1302e1771b997ab6966411b2c612562c538ae3e325dPin Ting            getHolder().setFormat(PixelFormat.RGB_888);
1312e1771b997ab6966411b2c612562c538ae3e325dPin Ting        } else {
1322e1771b997ab6966411b2c612562c538ae3e325dPin Ting            getHolder().setFormat(PixelFormat.RGB_565);
1332e1771b997ab6966411b2c612562c538ae3e325dPin Ting        }
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Uncomment this to enable gl error check.
13649affdc4e274098a34e4eb2dbe4a89a750f1ba7fOwen Lin        // setDebugFlags(DEBUG_CHECK_GL_ERROR);
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void registerLaunchedAnimation(CanvasAnimation animation) {
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Register the newly launched animation so that we can set the start
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // time more precisely. (Usually, it takes much longer for first
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // rendering, so we set the animation start time as the time we
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // complete rendering)
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mAnimations.add(animation);
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void addOnGLIdleListener(OnGLIdleListener listener) {
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (mIdleListeners) {
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mIdleListeners.addLast(listener);
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mIdleRunner.enable();
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setContentPane(GLView content) {
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mContentView == content) return;
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mContentView != null) {
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mInDownState) {
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                long now = SystemClock.uptimeMillis();
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                MotionEvent cancelEvent = MotionEvent.obtain(
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mContentView.dispatchTouchEvent(cancelEvent);
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                cancelEvent.recycle();
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mInDownState = false;
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mContentView.detachFromRoot();
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            BasicTexture.yieldAllTextures();
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContentView = content;
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (content != null) {
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            content.attachToRoot(this);
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestLayoutContentPane();
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
17971c177759c7aa10082c8fdf909b701cf0047beadAngus Kong    public void requestRenderForced() {
18071c177759c7aa10082c8fdf909b701cf0047beadAngus Kong        superRequestRender();
18171c177759c7aa10082c8fdf909b701cf0047beadAngus Kong    }
18271c177759c7aa10082c8fdf909b701cf0047beadAngus Kong
18371c177759c7aa10082c8fdf909b701cf0047beadAngus Kong    @Override
184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void requestRender() {
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (DEBUG_INVALIDATE) {
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            StackTraceElement e = Thread.currentThread().getStackTrace()[4];
187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String caller = e.getFileName() + ":" + e.getLineNumber() + " ";
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.d(TAG, "invalidate: " + caller);
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mRenderRequested) return;
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderRequested = true;
192b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck        if (ApiHelper.HAS_POST_ON_ANIMATION) {
193b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck            postOnAnimation(mRequestRenderOnAnimationFrame);
194b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck        } else {
195b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck            super.requestRender();
196b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck        }
197b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck    }
198b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck
199b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck    private Runnable mRequestRenderOnAnimationFrame = new Runnable() {
200b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck        @Override
201b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck        public void run() {
202b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck            superRequestRender();
203b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck        }
204b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck    };
205b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck
206b75f5defe8ace12b8b563e713f7175863ab5713dJohn Reck    private void superRequestRender() {
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        super.requestRender();
208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void requestLayoutContentPane() {
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.lock();
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mContentView == null || (mFlags & FLAG_NEED_LAYOUT) != 0) return;
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // "View" system will invoke onLayout() for initialization(bug ?), we
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // have to ignore it since the GLThread is not ready yet.
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if ((mFlags & FLAG_INITIALIZED) == 0) return;
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFlags |= FLAG_NEED_LAYOUT;
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestRender();
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRenderLock.unlock();
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void layoutContentPane() {
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mFlags &= ~FLAG_NEED_LAYOUT;
229bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
230bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int w = getWidth();
231bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int h = getHeight();
2322ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        int displayRotation = 0;
2332ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        int compensation = 0;
2342ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang
2352ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        // Get the new orientation values
2362ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        if (mOrientationSource != null) {
2372ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang            displayRotation = mOrientationSource.getDisplayRotation();
2382ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang            compensation = mOrientationSource.getCompensation();
2392ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        } else {
2402ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang            displayRotation = 0;
2412ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang            compensation = 0;
2422ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        }
243bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
2442ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        if (mCompensation != compensation) {
2452ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang            mCompensation = compensation;
246bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            if (mCompensation % 180 != 0) {
247bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                mCompensationMatrix.setRotate(mCompensation);
248bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                // move center to origin before rotation
249bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                mCompensationMatrix.preTranslate(-w / 2, -h / 2);
250bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                // align with the new origin after rotation
251bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                mCompensationMatrix.postTranslate(h / 2, w / 2);
252bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            } else {
253bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                mCompensationMatrix.setRotate(mCompensation, w / 2, h / 2);
254bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            }
255bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
2562ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        mDisplayRotation = displayRotation;
257bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
258bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        // Do the actual layout.
259bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mCompensation % 180 != 0) {
260bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            int tmp = w;
261bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            w = h;
262bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            h = tmp;
263bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
264bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        Log.i(TAG, "layout content pane " + w + "x" + h
265bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                + " (compensation " + mCompensation + ")");
266bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mContentView != null && w != 0 && h != 0) {
267bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mContentView.layout(0, 0, w, h);
268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Uncomment this to dump the view hierarchy.
270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        //mContentView.dumpTree("");
271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onLayout(
275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean changed, int left, int top, int right, int bottom) {
276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (changed) requestLayoutContentPane();
277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    /**
280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * Called when the context is created, possibly after automatic destruction.
281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     */
282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // This is a GLSurfaceView.Renderer callback
283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onSurfaceCreated(GL10 gl1, EGLConfig config) {
285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = (GL11) gl1;
286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mGL != null) {
287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // The GL Object has changed
288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.i(TAG, "GLObject has changed from " + mGL + " to " + gl);
289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
29037c605949219b8bf54c165c34d6405f5f2989f50Owen Lin        mRenderLock.lock();
29137c605949219b8bf54c165c34d6405f5f2989f50Owen Lin        try {
29237c605949219b8bf54c165c34d6405f5f2989f50Owen Lin            mGL = gl;
29350b33abe053ccab7be3d1bca2328e792507963d4George Mount            mCanvas = ApiHelper.HAS_GLES20_REQUIRED ? new GLES20Canvas() : new GLES11Canvas(gl);
29437c605949219b8bf54c165c34d6405f5f2989f50Owen Lin            BasicTexture.invalidateAllTextures();
29537c605949219b8bf54c165c34d6405f5f2989f50Owen Lin        } finally {
29637c605949219b8bf54c165c34d6405f5f2989f50Owen Lin            mRenderLock.unlock();
29737c605949219b8bf54c165c34d6405f5f2989f50Owen Lin        }
29837c605949219b8bf54c165c34d6405f5f2989f50Owen Lin
2993d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (DEBUG_FPS || DEBUG_PROFILE) {
300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
3013d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        } else {
3023d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    /**
307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * Called when the OpenGL surface is recreated without destroying the
308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * context.
309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     */
310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // This is a GLSurfaceView.Renderer callback
311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onSurfaceChanged(GL10 gl1, int width, int height) {
313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Log.i(TAG, "onSurfaceChanged: " + width + "x" + height
314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                + ", gl10: " + gl1.toString());
315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GalleryUtils.setRenderThread();
3173d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (DEBUG_PROFILE) {
3183d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Log.d(TAG, "Start profiling");
3193d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.enable(20);  // take a sample every 20ms
3203d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = (GL11) gl1;
322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Utils.assertTrue(mGL == gl);
323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCanvas.setSize(width, height);
325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void outputFps() {
328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        long now = System.nanoTime();
329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mFrameCountingStart == 0) {
330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFrameCountingStart = now;
331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else if ((now - mFrameCountingStart) > 1000000000) {
332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.d(TAG, "fps: " + (double) mFrameCount
333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    * 1000000000 / (now - mFrameCountingStart));
334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFrameCountingStart = now;
335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFrameCount = 0;
336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ++mFrameCount;
338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onDrawFrame(GL10 gl) {
342cb05834cedb8223fc59456afcd62fa7448f2b3b8Chih-Chung Chang        AnimationTime.update();
3433d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        long t0;
3447d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang        if (DEBUG_PROFILE_SLOW_ONLY) {
3453d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.hold();
3463d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            t0 = System.nanoTime();
3473d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.lock();
3491ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang
3501ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        while (mFreeze) {
3511ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang            mFreezeCondition.awaitUninterruptibly();
3521ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        }
3531ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang
354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            onDrawFrameLocked(gl);
356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRenderLock.unlock();
358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
359d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
360edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang        // We put a black cover View in front of the SurfaceView and hide it
361edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang        // after the first draw. This prevents the SurfaceView being transparent
362edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang        // before the first draw.
363edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang        if (mFirstDraw) {
364edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang            mFirstDraw = false;
365edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang            post(new Runnable() {
366ca7d9bfb42c1d5037bcecdde30eb836755140b03The Android Open Source Project                    @Override
367edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang                    public void run() {
368edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang                        View root = getRootView();
369edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang                        View cover = root.findViewById(R.id.gl_root_cover);
370edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang                        cover.setVisibility(GONE);
371edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang                    }
372edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang                });
373edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang        }
374edada7ca2b7c70c5459cbe488c1a16cc186f2bf0Chih-Chung Chang
3757d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang        if (DEBUG_PROFILE_SLOW_ONLY) {
3763d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            long t = System.nanoTime();
3773d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            long durationInMs = (t - mLastDrawFinishTime) / 1000000;
3783d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            long durationDrawInMs = (t - t0) / 1000000;
3793d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            mLastDrawFinishTime = t;
3803d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
3813d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            if (durationInMs > 34) {  // 34ms -> we skipped at least 2 frames
3823d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                Log.v(TAG, "----- SLOW (" + durationDrawInMs + "/" +
3833d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                        durationInMs + ") -----");
3843d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                Profile.commit();
3853d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            } else {
3863d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                Profile.drop();
387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void onDrawFrameLocked(GL10 gl) {
392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (DEBUG_FPS) outputFps();
393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // release the unbound textures and deleted buffers.
395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCanvas.deleteRecycledResources();
396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // reset texture upload limit
398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        UploadedTexture.resetUploadLimit();
399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderRequested = false;
401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
402695e1aa059cbc2cb2988f6beb0fee8ff7952b229John Reck        if ((mOrientationSource != null
403695e1aa059cbc2cb2988f6beb0fee8ff7952b229John Reck                && mDisplayRotation != mOrientationSource.getDisplayRotation())
404695e1aa059cbc2cb2988f6beb0fee8ff7952b229John Reck                || (mFlags & FLAG_NEED_LAYOUT) != 0) {
405695e1aa059cbc2cb2988f6beb0fee8ff7952b229John Reck            layoutContentPane();
406695e1aa059cbc2cb2988f6beb0fee8ff7952b229John Reck        }
407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
408bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mCanvas.save(GLCanvas.SAVE_FLAG_ALL);
409bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        rotateCanvas(-mCompensation);
410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mContentView != null) {
411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin           mContentView.render(mCanvas);
4126adf13c2aeee89735df1b7c12670a026e5087161John Reck        } else {
4136adf13c2aeee89735df1b7c12670a026e5087161John Reck            // Make sure we always draw something to prevent displaying garbage
4146adf13c2aeee89735df1b7c12670a026e5087161John Reck            mCanvas.clearBuffer();
415f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
416bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mCanvas.restore();
417f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
418f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!mAnimations.isEmpty()) {
4197d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang            long now = AnimationTime.get();
420f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = 0, n = mAnimations.size(); i < n; i++) {
421f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mAnimations.get(i).setStartTime(now);
422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mAnimations.clear();
424f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
425f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
426f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (UploadedTexture.uploadLimitReached()) {
427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestRender();
428f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
429f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
430f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (mIdleListeners) {
431d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            if (!mIdleListeners.isEmpty()) mIdleRunner.enable();
432f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (DEBUG_INVALIDATE) {
435f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mCanvas.fillRect(10, 10, 5, 5, mInvalidateColor);
436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mInvalidateColor = ~mInvalidateColor;
437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (DEBUG_DRAWING_STAT) {
440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mCanvas.dumpStatisticsAndClear();
441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
442f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
443f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
444bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private void rotateCanvas(int degrees) {
445bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (degrees == 0) return;
446bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int w = getWidth();
447bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int h = getHeight();
448bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int cx = w / 2;
449bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int cy = h / 2;
450bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mCanvas.translate(cx, cy);
451bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mCanvas.rotate(degrees, 0, 0, 1);
452bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (degrees % 180 != 0) {
453bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mCanvas.translate(-cy, -cx);
454bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        } else {
455bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mCanvas.translate(-cx, -cy);
456bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
457bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
458bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
459f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
460f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public boolean dispatchTouchEvent(MotionEvent event) {
461bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (!isEnabled()) return false;
462bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
463f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int action = event.getAction();
464f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (action == MotionEvent.ACTION_CANCEL
465f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                || action == MotionEvent.ACTION_UP) {
466f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mInDownState = false;
467f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else if (!mInDownState && action != MotionEvent.ACTION_DOWN) {
468f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return false;
469f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
470bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
471bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mCompensation != 0) {
4728fedc27c552424cc5d8e72783bd53f38538190e9Ahbong Chang            event = MotionEventHelper.transformEvent(event, mCompensationMatrix);
473bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
474bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
475f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.lock();
476f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
477f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // If this has been detached from root, we don't need to handle event
478f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean handled = mContentView != null
479f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    && mContentView.dispatchTouchEvent(event);
480f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (action == MotionEvent.ACTION_DOWN && handled) {
481f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mInDownState = true;
482f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
483f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return handled;
484f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
485f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRenderLock.unlock();
486f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
487f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
488f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
489f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private class IdleRunner implements Runnable {
490f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // true if the idle runner is in the queue
491f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private boolean mActive = false;
492f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
493f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
494f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void run() {
495f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            OnGLIdleListener listener;
496f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            synchronized (mIdleListeners) {
497f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mActive = false;
498f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (mIdleListeners.isEmpty()) return;
499f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                listener = mIdleListeners.removeFirst();
500f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
501f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRenderLock.lock();
5025515801ddea6953e95b2c41a9434bb1fe489e08aOwen Lin            boolean keepInQueue;
503f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            try {
5045515801ddea6953e95b2c41a9434bb1fe489e08aOwen Lin                keepInQueue = listener.onGLIdle(mCanvas, mRenderRequested);
505f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } finally {
506f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mRenderLock.unlock();
507f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
508f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            synchronized (mIdleListeners) {
5095515801ddea6953e95b2c41a9434bb1fe489e08aOwen Lin                if (keepInQueue) mIdleListeners.addLast(listener);
5105515801ddea6953e95b2c41a9434bb1fe489e08aOwen Lin                if (!mRenderRequested && !mIdleListeners.isEmpty()) enable();
511f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
512f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
513f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
514f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void enable() {
515f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Who gets the flag can add it to the queue
516f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mActive) return;
517f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mActive = true;
518f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            queueEvent(this);
519f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
520f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
521f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
522f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
523f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void lockRenderThread() {
524f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.lock();
525f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
526f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
527f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
528f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void unlockRenderThread() {
529f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.unlock();
530f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
5313d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
5323d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    @Override
5333d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    public void onPause() {
53479cf902f4cc602774e90bc2040f0029978becb61Owen Lin        unfreeze();
5353d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        super.onPause();
5363d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (DEBUG_PROFILE) {
5373d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Log.d(TAG, "Stop profiling");
5383d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.disableAll();
5393d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.dumpToFile("/sdcard/gallery.prof");
5403d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.reset();
5413d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
5423d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
543bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
544bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    @Override
5452ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    public void setOrientationSource(OrientationSource source) {
5462ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        mOrientationSource = source;
5472ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    }
5482ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang
5492ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    @Override
5502ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    public int getDisplayRotation() {
5512ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        return mDisplayRotation;
5522ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    }
5532ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang
5542ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    @Override
5552ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    public int getCompensation() {
5562ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        return mCompensation;
5572ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    }
5582ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang
5592ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    @Override
5602ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang    public Matrix getCompensationMatrix() {
5612ef46ed28b28b355d7f3f1432c7b1196b832a859Chih-Chung Chang        return mCompensationMatrix;
562bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
5631ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang
5641ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang    @Override
5651ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang    public void freeze() {
5661ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        mRenderLock.lock();
5671ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        mFreeze = true;
5681ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        mRenderLock.unlock();
5691ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang    }
5701ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang
5711ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang    @Override
5721ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang    public void unfreeze() {
5731ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        mRenderLock.lock();
5741ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        mFreeze = false;
5751ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        mFreezeCondition.signalAll();
5761ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang        mRenderLock.unlock();
5771ade1266d8e13830e3b07c1ebd8c95f4e859e129Chih-Chung Chang    }
57879cf902f4cc602774e90bc2040f0029978becb61Owen Lin
5790b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang    @Override
580df4763cf8752fb1babc7244fc2be33ed87d3b072Owen Lin    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
5810b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang    public void setLightsOutMode(boolean enabled) {
582b0774a3bfb24d8515fc3ddf152fabf82f0ff67e5Yuli Huang        if (!ApiHelper.HAS_SET_SYSTEM_UI_VISIBILITY) return;
583b0774a3bfb24d8515fc3ddf152fabf82f0ff67e5Yuli Huang
5847a5e1e771ae58241f3a2be36f23025f282032261Owen Lin        int flags = 0;
5857a5e1e771ae58241f3a2be36f23025f282032261Owen Lin        if (enabled) {
586ca7d9bfb42c1d5037bcecdde30eb836755140b03The Android Open Source Project            flags = STATUS_BAR_HIDDEN;
5877a5e1e771ae58241f3a2be36f23025f282032261Owen Lin            if (ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE) {
5887a5e1e771ae58241f3a2be36f23025f282032261Owen Lin                flags |= (SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_STABLE);
5897a5e1e771ae58241f3a2be36f23025f282032261Owen Lin            }
5907a5e1e771ae58241f3a2be36f23025f282032261Owen Lin        }
5910b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang        setSystemUiVisibility(flags);
5920b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang    }
5930b2486cff0c1b951c54325596256b986307f7f3aChih-Chung Chang
59479cf902f4cc602774e90bc2040f0029978becb61Owen Lin    // We need to unfreeze in the following methods and in onPause().
59579cf902f4cc602774e90bc2040f0029978becb61Owen Lin    // These methods will wait on GLThread. If we have freezed the GLRootView,
59679cf902f4cc602774e90bc2040f0029978becb61Owen Lin    // the GLThread will wait on main thread to call unfreeze and cause dead
59779cf902f4cc602774e90bc2040f0029978becb61Owen Lin    // lock.
59879cf902f4cc602774e90bc2040f0029978becb61Owen Lin    @Override
59979cf902f4cc602774e90bc2040f0029978becb61Owen Lin    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
60079cf902f4cc602774e90bc2040f0029978becb61Owen Lin        unfreeze();
60179cf902f4cc602774e90bc2040f0029978becb61Owen Lin        super.surfaceChanged(holder, format, w, h);
60279cf902f4cc602774e90bc2040f0029978becb61Owen Lin    }
60379cf902f4cc602774e90bc2040f0029978becb61Owen Lin
60479cf902f4cc602774e90bc2040f0029978becb61Owen Lin    @Override
60579cf902f4cc602774e90bc2040f0029978becb61Owen Lin    public void surfaceCreated(SurfaceHolder holder) {
60679cf902f4cc602774e90bc2040f0029978becb61Owen Lin        unfreeze();
60779cf902f4cc602774e90bc2040f0029978becb61Owen Lin        super.surfaceCreated(holder);
60879cf902f4cc602774e90bc2040f0029978becb61Owen Lin    }
60979cf902f4cc602774e90bc2040f0029978becb61Owen Lin
61079cf902f4cc602774e90bc2040f0029978becb61Owen Lin    @Override
61179cf902f4cc602774e90bc2040f0029978becb61Owen Lin    public void surfaceDestroyed(SurfaceHolder holder) {
61279cf902f4cc602774e90bc2040f0029978becb61Owen Lin        unfreeze();
61379cf902f4cc602774e90bc2040f0029978becb61Owen Lin        super.surfaceDestroyed(holder);
61479cf902f4cc602774e90bc2040f0029978becb61Owen Lin    }
61579cf902f4cc602774e90bc2040f0029978becb61Owen Lin
61679cf902f4cc602774e90bc2040f0029978becb61Owen Lin    @Override
61779cf902f4cc602774e90bc2040f0029978becb61Owen Lin    protected void onDetachedFromWindow() {
61879cf902f4cc602774e90bc2040f0029978becb61Owen Lin        unfreeze();
61979cf902f4cc602774e90bc2040f0029978becb61Owen Lin        super.onDetachedFromWindow();
62079cf902f4cc602774e90bc2040f0029978becb61Owen Lin    }
62179cf902f4cc602774e90bc2040f0029978becb61Owen Lin
62279cf902f4cc602774e90bc2040f0029978becb61Owen Lin    @Override
62379cf902f4cc602774e90bc2040f0029978becb61Owen Lin    protected void finalize() throws Throwable {
62479cf902f4cc602774e90bc2040f0029978becb61Owen Lin        try {
62579cf902f4cc602774e90bc2040f0029978becb61Owen Lin            unfreeze();
62679cf902f4cc602774e90bc2040f0029978becb61Owen Lin        } finally {
62779cf902f4cc602774e90bc2040f0029978becb61Owen Lin            super.finalize();
62879cf902f4cc602774e90bc2040f0029978becb61Owen Lin        }
62979cf902f4cc602774e90bc2040f0029978becb61Owen Lin    }
630f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
631