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