GLRootView.java revision bd141b5a51c96f6fcaddfa547f0928ce69cf0755
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
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.Context;
20bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Changimport android.graphics.Matrix;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.PixelFormat;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Rect;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.opengl.GLSurfaceView;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Process;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.SystemClock;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.util.AttributeSet;
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.view.MotionEvent;
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
292b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.anim.CanvasAnimation;
302b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.Utils;
312b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.GalleryUtils;
322b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.Profile;
332b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
34d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Linimport java.util.ArrayDeque;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList;
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.locks.ReentrantLock;
372b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.egl.EGLConfig;
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL10;
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport javax.microedition.khronos.opengles.GL11;
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// The root component of all <code>GLView</code>s. The rendering is done in GL
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// thread while the event handling is done in the main thread.  To synchronize
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// the two threads, the entry points of this package need to synchronize on the
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// <code>GLRootView</code> instance unless it can be proved that the rendering
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// thread won't access the same thing as the method. The entry points include:
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (1) The public methods of HeadUpDisplay
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (2) The public methods of CameraHeadUpDisplay
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// (3) The overridden methods in GLRootView.
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class GLRootView extends GLSurfaceView
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        implements GLSurfaceView.Renderer, GLRoot {
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "GLRootView";
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final boolean DEBUG_FPS = false;
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mFrameCount = 0;
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private long mFrameCountingStart = 0;
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final boolean DEBUG_INVALIDATE = false;
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mInvalidateColor = 0;
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final boolean DEBUG_DRAWING_STAT = false;
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
633d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private static final boolean DEBUG_PROFILE = false;
647d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang    private static final boolean DEBUG_PROFILE_SLOW_ONLY = false;
653d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int FLAG_INITIALIZED = 1;
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int FLAG_NEED_LAYOUT = 2;
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private GL11 mGL;
707b83fb8e3a8978b33a6b9bfc56d85fe2c1a9cf06Chih-Chung Chang    private GLCanvas mCanvas;
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private GLView mContentView;
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
73bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // mCompensation is the difference between the UI orientation on GLCanvas
74bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // and the framework orientation. See OrientationManager for details.
75bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private int mCompensation;
76bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // mCompensationMatrix maps the coordinates of touch events. It is kept sync
77bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // with mCompensation.
78bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private Matrix mCompensationMatrix = new Matrix();
79bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    // The value which will become mCompensation in next layout.
80bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private int mPendingCompensation;
81bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mFlags = FLAG_NEED_LAYOUT;
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private volatile boolean mRenderRequested = false;
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final GalleryEGLConfigChooser mEglConfigChooser =
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            new GalleryEGLConfigChooser();
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final ArrayList<CanvasAnimation> mAnimations =
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            new ArrayList<CanvasAnimation>();
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
91d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final ArrayDeque<OnGLIdleListener> mIdleListeners =
92d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            new ArrayDeque<OnGLIdleListener>();
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final IdleRunner mIdleRunner = new IdleRunner();
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final ReentrantLock mRenderLock = new ReentrantLock();
97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private long mLastDrawFinishTime;
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean mInDownState = false;
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public GLRootView(Context context) {
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        this(context, null);
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public GLRootView(Context context, AttributeSet attrs) {
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        super(context, attrs);
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mFlags |= FLAG_INITIALIZED;
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setBackgroundDrawable(null);
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setEGLConfigChooser(mEglConfigChooser);
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setRenderer(this);
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        getHolder().setFormat(PixelFormat.RGB_565);
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Uncomment this to enable gl error check.
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        //setDebugFlags(DEBUG_CHECK_GL_ERROR);
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void registerLaunchedAnimation(CanvasAnimation animation) {
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Register the newly launched animation so that we can set the start
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // time more precisely. (Usually, it takes much longer for first
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // rendering, so we set the animation start time as the time we
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // complete rendering)
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mAnimations.add(animation);
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void addOnGLIdleListener(OnGLIdleListener listener) {
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (mIdleListeners) {
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mIdleListeners.addLast(listener);
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mIdleRunner.enable();
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setContentPane(GLView content) {
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mContentView == content) return;
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mContentView != null) {
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mInDownState) {
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                long now = SystemClock.uptimeMillis();
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                MotionEvent cancelEvent = MotionEvent.obtain(
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mContentView.dispatchTouchEvent(cancelEvent);
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                cancelEvent.recycle();
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mInDownState = false;
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mContentView.detachFromRoot();
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            BasicTexture.yieldAllTextures();
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContentView = content;
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (content != null) {
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            content.attachToRoot(this);
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestLayoutContentPane();
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void requestRender() {
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (DEBUG_INVALIDATE) {
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            StackTraceElement e = Thread.currentThread().getStackTrace()[4];
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String caller = e.getFileName() + ":" + e.getLineNumber() + " ";
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.d(TAG, "invalidate: " + caller);
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mRenderRequested) return;
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderRequested = true;
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        super.requestRender();
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void requestLayoutContentPane() {
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.lock();
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mContentView == null || (mFlags & FLAG_NEED_LAYOUT) != 0) return;
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // "View" system will invoke onLayout() for initialization(bug ?), we
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // have to ignore it since the GLThread is not ready yet.
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if ((mFlags & FLAG_INITIALIZED) == 0) return;
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFlags |= FLAG_NEED_LAYOUT;
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestRender();
180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRenderLock.unlock();
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void layoutContentPane() {
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mFlags &= ~FLAG_NEED_LAYOUT;
187bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
188bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int w = getWidth();
189bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int h = getHeight();
190bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
191bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        // Before doing layout, if there is a compensation change pending, update
192bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        // mCompensation and mCompensationMatrix.
193bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mCompensation != mPendingCompensation) {
194bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mCompensation = mPendingCompensation;
195bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            if (mCompensation % 180 != 0) {
196bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                mCompensationMatrix.setRotate(mCompensation);
197bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                // move center to origin before rotation
198bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                mCompensationMatrix.preTranslate(-w / 2, -h / 2);
199bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                // align with the new origin after rotation
200bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                mCompensationMatrix.postTranslate(h / 2, w / 2);
201bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            } else {
202bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                mCompensationMatrix.setRotate(mCompensation, w / 2, h / 2);
203bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            }
204bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
205bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
206bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        // Tell the views about current display rotation and compensation value.
207bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mContentView != null) {
208bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            // This is a hack: note the 0 should be the display rotation, but we
209bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            // don't know the display rotation here. The PhotoPage will inject
210bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            // the correct value in its mRootPane.orient() method.
211bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mContentView.orient(0, mCompensation);
212bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
213bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
214bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        // Do the actual layout.
215bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mCompensation % 180 != 0) {
216bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            int tmp = w;
217bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            w = h;
218bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            h = tmp;
219bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
220bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        Log.i(TAG, "layout content pane " + w + "x" + h
221bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang                + " (compensation " + mCompensation + ")");
222bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mContentView != null && w != 0 && h != 0) {
223bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mContentView.layout(0, 0, w, h);
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // Uncomment this to dump the view hierarchy.
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        //mContentView.dumpTree("");
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    protected void onLayout(
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean changed, int left, int top, int right, int bottom) {
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (changed) requestLayoutContentPane();
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    /**
236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * Called when the context is created, possibly after automatic destruction.
237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     */
238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // This is a GLSurfaceView.Renderer callback
239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onSurfaceCreated(GL10 gl1, EGLConfig config) {
241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = (GL11) gl1;
242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mGL != null) {
243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // The GL Object has changed
244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.i(TAG, "GLObject has changed from " + mGL + " to " + gl);
245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mGL = gl;
247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCanvas = new GLCanvasImpl(gl);
2483d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (DEBUG_FPS || DEBUG_PROFILE) {
249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
2503d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        } else {
2513d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    /**
256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * Called when the OpenGL surface is recreated without destroying the
257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     * context.
258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin     */
259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // This is a GLSurfaceView.Renderer callback
260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onSurfaceChanged(GL10 gl1, int width, int height) {
262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Log.i(TAG, "onSurfaceChanged: " + width + "x" + height
263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                + ", gl10: " + gl1.toString());
264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GalleryUtils.setRenderThread();
2663950038a697470bb8b7cd6798716aecd8285eb00Chih-Chung Chang        BasicTexture.invalidateAllTextures();
2673d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (DEBUG_PROFILE) {
2683d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Log.d(TAG, "Start profiling");
2693d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.enable(20);  // take a sample every 20ms
2703d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GL11 gl = (GL11) gl1;
272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Utils.assertTrue(mGL == gl);
273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCanvas.setSize(width, height);
275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void outputFps() {
278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        long now = System.nanoTime();
279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mFrameCountingStart == 0) {
280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFrameCountingStart = now;
281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else if ((now - mFrameCountingStart) > 1000000000) {
282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.d(TAG, "fps: " + (double) mFrameCount
283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    * 1000000000 / (now - mFrameCountingStart));
284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFrameCountingStart = now;
285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFrameCount = 0;
286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ++mFrameCount;
288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onDrawFrame(GL10 gl) {
292cb05834cedb8223fc59456afcd62fa7448f2b3b8Chih-Chung Chang        AnimationTime.update();
2933d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        long t0;
2947d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang        if (DEBUG_PROFILE_SLOW_ONLY) {
2953d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.hold();
2963d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            t0 = System.nanoTime();
2973d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.lock();
299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            onDrawFrameLocked(gl);
301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRenderLock.unlock();
303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
304d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
3057d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang        if (DEBUG_PROFILE_SLOW_ONLY) {
3063d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            long t = System.nanoTime();
3073d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            long durationInMs = (t - mLastDrawFinishTime) / 1000000;
3083d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            long durationDrawInMs = (t - t0) / 1000000;
3093d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            mLastDrawFinishTime = t;
3103d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
3113d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            if (durationInMs > 34) {  // 34ms -> we skipped at least 2 frames
3123d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                Log.v(TAG, "----- SLOW (" + durationDrawInMs + "/" +
3133d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                        durationInMs + ") -----");
3143d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                Profile.commit();
3153d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            } else {
3163d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                Profile.drop();
317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void onDrawFrameLocked(GL10 gl) {
322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (DEBUG_FPS) outputFps();
323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // release the unbound textures and deleted buffers.
325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mCanvas.deleteRecycledResources();
326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // reset texture upload limit
328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        UploadedTexture.resetUploadLimit();
329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderRequested = false;
331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if ((mFlags & FLAG_NEED_LAYOUT) != 0) layoutContentPane();
333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
334bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mCanvas.save(GLCanvas.SAVE_FLAG_ALL);
335bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        rotateCanvas(-mCompensation);
336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mContentView != null) {
337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin           mContentView.render(mCanvas);
338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
339bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mCanvas.restore();
340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!mAnimations.isEmpty()) {
3427d19f7f4281f232b9dceee4a5df390c03e2bd16bChih-Chung Chang            long now = AnimationTime.get();
343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = 0, n = mAnimations.size(); i < n; i++) {
344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mAnimations.get(i).setStartTime(now);
345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mAnimations.clear();
347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (UploadedTexture.uploadLimitReached()) {
350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestRender();
351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        synchronized (mIdleListeners) {
354d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            if (!mIdleListeners.isEmpty()) mIdleRunner.enable();
355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (DEBUG_INVALIDATE) {
358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mCanvas.fillRect(10, 10, 5, 5, mInvalidateColor);
359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mInvalidateColor = ~mInvalidateColor;
360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (DEBUG_DRAWING_STAT) {
363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mCanvas.dumpStatisticsAndClear();
364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
367bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    private void rotateCanvas(int degrees) {
368bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (degrees == 0) return;
369bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int w = getWidth();
370bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int h = getHeight();
371bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int cx = w / 2;
372bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        int cy = h / 2;
373bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mCanvas.translate(cx, cy);
374bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mCanvas.rotate(degrees, 0, 0, 1);
375bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (degrees % 180 != 0) {
376bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mCanvas.translate(-cy, -cx);
377bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        } else {
378bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            mCanvas.translate(-cx, -cy);
379bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
380bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
381bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public boolean dispatchTouchEvent(MotionEvent event) {
384bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (!isEnabled()) return false;
385bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int action = event.getAction();
387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (action == MotionEvent.ACTION_CANCEL
388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                || action == MotionEvent.ACTION_UP) {
389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mInDownState = false;
390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else if (!mInDownState && action != MotionEvent.ACTION_DOWN) {
391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return false;
392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
393bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
394bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mCompensation != 0) {
395bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang            event.transform(mCompensationMatrix);
396bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        }
397bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.lock();
399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // If this has been detached from root, we don't need to handle event
401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean handled = mContentView != null
402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    && mContentView.dispatchTouchEvent(event);
403f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (action == MotionEvent.ACTION_DOWN && handled) {
404f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mInDownState = true;
405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return handled;
407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRenderLock.unlock();
409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
412f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private class IdleRunner implements Runnable {
413f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // true if the idle runner is in the queue
414f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private boolean mActive = false;
415f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
416f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
417f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void run() {
418f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            OnGLIdleListener listener;
419f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            synchronized (mIdleListeners) {
420f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mActive = false;
421f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (mIdleListeners.isEmpty()) return;
422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                listener = mIdleListeners.removeFirst();
423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
424f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mRenderLock.lock();
425f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            try {
426d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin                if (!listener.onGLIdle(mCanvas, mRenderRequested)) return;
427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } finally {
428f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mRenderLock.unlock();
429f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
430f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            synchronized (mIdleListeners) {
431f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mIdleListeners.addLast(listener);
432d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin                if (!mRenderRequested) enable();
433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
435f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void enable() {
437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // Who gets the flag can add it to the queue
438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mActive) return;
439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mActive = true;
440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            queueEvent(this);
441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
442f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
443f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
444f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
445f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void lockRenderThread() {
446f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.lock();
447f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
448f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
449f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
450f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void unlockRenderThread() {
451f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mRenderLock.unlock();
452f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
4533d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
4543d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    @Override
4553d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    public void onPause() {
4563d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        super.onPause();
4573d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (DEBUG_PROFILE) {
4583d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Log.d(TAG, "Stop profiling");
4593d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.disableAll();
4603d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.dumpToFile("/sdcard/gallery.prof");
4613d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Profile.reset();
4623d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
4633d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
464bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang
465bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    @Override
466bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    public void setOrientationCompensation(int degrees) {
467bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        if (mPendingCompensation == degrees) return;
468bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        mPendingCompensation = degrees;
469bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang        requestLayoutContentPane();
470bd141b5a51c96f6fcaddfa547f0928ce69cf0755Chih-Chung Chang    }
471f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
472