CameraScreenNail.java revision 4fabf52f7e8b2419749f5cdc03925d5f8b1c0199
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
19import android.graphics.SurfaceTexture;
20
21import com.android.gallery3d.ui.GLCanvas;
22import com.android.gallery3d.ui.RawTexture;
23import com.android.gallery3d.ui.SurfaceTextureScreenNail;
24
25import android.util.Log;
26
27/*
28 * This is a ScreenNail which can displays camera preview.
29 */
30public class CameraScreenNail extends SurfaceTextureScreenNail {
31    private static final String TAG = "CameraScreenNail";
32    private static final int ANIM_NONE = 0;
33    // Capture animation is about to start.
34    private static final int ANIM_CAPTURE_START = 1;
35    // Capture animation is running.
36    private static final int ANIM_CAPTURE_RUNNING = 2;
37    // Switch camera animation needs to copy texture.
38    private static final int ANIM_SWITCH_COPY_TEXTURE = 3;
39    // Switch camera animation shows the initial feedback by darkening the
40    // preview.
41    private static final int ANIM_SWITCH_DARK_PREVIEW = 4;
42    // Switch camera animation is waiting for the first frame.
43    private static final int ANIM_SWITCH_WAITING_FIRST_FRAME = 5;
44    // Switch camera animation is about to start.
45    private static final int ANIM_SWITCH_START = 6;
46    // Switch camera animation is running.
47    private static final int ANIM_SWITCH_RUNNING = 7;
48
49    private boolean mVisible;
50    private Listener mListener;
51    private final float[] mTextureTransformMatrix = new float[16];
52
53    // Animation.
54    private CaptureAnimManager mCaptureAnimManager = new CaptureAnimManager();
55    private SwitchAnimManager mSwitchAnimManager =new SwitchAnimManager();
56    private int mAnimState = ANIM_NONE;
57    private RawTexture mAnimTexture;
58    // Some methods are called by GL thread and some are called by main thread.
59    // This protects mAnimState and mVisible. The access of either one should be
60    // synchronized. This also makes sure some code are atomic. For example,
61    // requestRender and setting mAnimState.
62    private Object mLock = new Object();
63
64    public interface Listener {
65        void requestRender();
66        // Preview has been copied to a texture.
67        void onPreviewTextureCopied();
68    }
69
70    public CameraScreenNail(Listener listener) {
71        mListener = listener;
72    }
73
74    @Override
75    public void acquireSurfaceTexture() {
76        super.acquireSurfaceTexture();
77        mAnimTexture = new RawTexture(getWidth(), getHeight(), true);
78    }
79
80    @Override
81    public void releaseSurfaceTexture() {
82        super.releaseSurfaceTexture();
83        synchronized (mLock) {
84            mAnimState = ANIM_NONE; // stop the animation
85        }
86    }
87
88    public void copyTexture() {
89        synchronized (mLock) {
90            mListener.requestRender();
91            mAnimState = ANIM_SWITCH_COPY_TEXTURE;
92        }
93    }
94
95    public void animateSwitchCamera(boolean backToFront) {
96        synchronized (mLock) {
97            if (mAnimState == ANIM_SWITCH_DARK_PREVIEW) {
98                mSwitchAnimManager.setSwitchDirection(backToFront);
99                // Do not request render here because camera has been just
100                // started. We do not want to draw black frames.
101                mAnimState = ANIM_SWITCH_WAITING_FIRST_FRAME;
102            }
103        }
104    }
105
106    public void animateCapture(int animOrientation) {
107        synchronized (mLock) {
108            mCaptureAnimManager.setOrientation(animOrientation);
109            mListener.requestRender();
110            mAnimState = ANIM_CAPTURE_START;
111        }
112    }
113
114    public void directDraw(GLCanvas canvas, int x, int y, int width, int height) {
115        super.draw(canvas, x, y, width, height);
116    }
117
118    @Override
119    public void draw(GLCanvas canvas, int x, int y, int width, int height) {
120        if (getSurfaceTexture() == null) return;
121        synchronized (mLock) {
122            if (!mVisible) mVisible = true;
123
124            if (mAnimState == ANIM_NONE) {
125                super.draw(canvas, x, y, width, height);
126                return;
127            }
128
129            switch (mAnimState) {
130                case ANIM_SWITCH_COPY_TEXTURE:
131                    copyPreviewTexture(canvas);
132                    mListener.onPreviewTextureCopied();
133                    mAnimState = ANIM_SWITCH_DARK_PREVIEW;
134                    // The texture is ready. Fall through to draw darkened
135                    // preview.
136                case ANIM_SWITCH_DARK_PREVIEW:
137                    float alpha = canvas.getAlpha();
138                    canvas.setAlpha(SwitchAnimManager.INITIAL_DARKEN_ALPHA);
139                    mAnimTexture.draw(canvas, x, y, width, height);
140                    canvas.setAlpha(alpha);
141                    return;
142                case ANIM_SWITCH_START:
143                    mSwitchAnimManager.startAnimation(x, y, width, height);
144                    mAnimState = ANIM_SWITCH_RUNNING;
145                    break;
146                case ANIM_CAPTURE_START:
147                    copyPreviewTexture(canvas);
148                    mCaptureAnimManager.startAnimation(x, y, width, height);
149                    mAnimState = ANIM_CAPTURE_RUNNING;
150                    break;
151            }
152
153            if (mAnimState == ANIM_CAPTURE_RUNNING || mAnimState == ANIM_SWITCH_RUNNING) {
154                boolean drawn;
155                if (mAnimState == ANIM_CAPTURE_RUNNING) {
156                    drawn = mCaptureAnimManager.drawAnimation(canvas, this, mAnimTexture);
157                } else {
158                    drawn = mSwitchAnimManager.drawAnimation(canvas, this, mAnimTexture);
159                }
160                if (drawn) {
161                    mListener.requestRender();
162                } else {
163                    // Continue to the normal draw procedure if the animation is
164                    // not drawn.
165                    mAnimState = ANIM_NONE;
166                    super.draw(canvas, x, y, width, height);
167                }
168            }
169        } // mLock
170    }
171
172    private void copyPreviewTexture(GLCanvas canvas) {
173        int width = mAnimTexture.getWidth();
174        int height = mAnimTexture.getHeight();
175        canvas.beginRenderTarget(mAnimTexture);
176        // Flip preview texture vertically. OpenGL uses bottom left point
177        // as the origin (0, 0).
178        canvas.translate(0, height);
179        canvas.scale(1, -1, 1);
180        getSurfaceTexture().getTransformMatrix(mTextureTransformMatrix);
181        canvas.drawTexture(mExtTexture,
182                mTextureTransformMatrix, 0, 0, width, height);
183        canvas.endRenderTarget();
184    }
185
186    @Override
187    public void noDraw() {
188        synchronized (mLock) {
189            mVisible = false;
190        }
191    }
192
193    @Override
194    public void recycle() {
195        synchronized (mLock) {
196            mVisible = false;
197        }
198    }
199
200    @Override
201    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
202        synchronized (mLock) {
203            if (mVisible) {
204                if (mAnimState == ANIM_SWITCH_WAITING_FIRST_FRAME) {
205                    mAnimState = ANIM_SWITCH_START;
206                }
207                // We need to ask for re-render if the SurfaceTexture receives a new
208                // frame.
209                mListener.requestRender();
210            }
211        }
212    }
213}
214