summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera')
-rw-r--r--src/com/android/camera/Camera.java4
-rw-r--r--src/com/android/camera/FaceListener.java20
-rw-r--r--src/com/android/camera/panorama/Mosaic.java14
-rw-r--r--src/com/android/camera/panorama/MosaicFrameProcessor.java21
-rw-r--r--src/com/android/camera/panorama/MosaicRenderer.java34
-rw-r--r--src/com/android/camera/panorama/MosaicRendererSurfaceView.java78
-rw-r--r--src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java67
-rw-r--r--src/com/android/camera/panorama/PanoramaActivity.java193
8 files changed, 330 insertions, 101 deletions
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java
index 86ab4e9..ae883b8 100644
--- a/src/com/android/camera/Camera.java
+++ b/src/com/android/camera/Camera.java
@@ -529,6 +529,7 @@ public class Camera extends ActivityBase implements View.OnClickListener,
if (mParameters.getMaxNumDetectedFaces() > 0) {
mCameraDevice.setFaceDetectionListener(null);
mCameraDevice.stopFaceDetection();
+ if (mFaceListener != null) mFaceListener.clearFaces();
}
}
@@ -1520,6 +1521,9 @@ public class Camera extends ActivityBase implements View.OnClickListener,
}
private void updateFocusUI() {
+ // Do not show focus rectangle if there is any face rectangle.
+ if (mFaceListener != null && mFaceListener.faceExists()) return;
+
if (mCameraState == FOCUSING || mCameraState == FOCUSING_SNAP_ON_FINISH) {
mFocusRectangle.showStart();
} else if (mCameraState == FOCUS_SUCCESS) {
diff --git a/src/com/android/camera/FaceListener.java b/src/com/android/camera/FaceListener.java
index 87d9ec1..dae0bda 100644
--- a/src/com/android/camera/FaceListener.java
+++ b/src/com/android/camera/FaceListener.java
@@ -64,10 +64,24 @@ class FaceListener implements android.hardware.Camera.FaceDetectionListener {
if (LOGV) Log.v(TAG, "mMirror=" + mirror);
}
+ public boolean faceExists() {
+ if (mFaces[0] == null) return false;
+ if (mFaces[0].getVisibility() == View.VISIBLE) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void clearFaces() {
+ for (int i = 0; i < MAX_NUM_FACES; i++) {
+ if (mFaces[i] == null) break;
+ if (mFaces[i].getVisibility() != View.VISIBLE) break;
+ mFaces[i].setVisibility(View.GONE);
+ }
+ }
+
private void showFaces(Face[] faces) {
- // The range of the coordinates from the driver is -1000 to 1000.
- // So the maximum length of the width or height is 2000. We need to
- // convert them to UI layout size later.
for (int i = 0; i < MAX_NUM_FACES; i++) {
if (i < faces.length) {
// Inflate the view if it's not done yet.
diff --git a/src/com/android/camera/panorama/Mosaic.java b/src/com/android/camera/panorama/Mosaic.java
index 5012ff4..80e8263 100644
--- a/src/com/android/camera/panorama/Mosaic.java
+++ b/src/com/android/camera/panorama/Mosaic.java
@@ -99,6 +99,20 @@ public class Mosaic {
public native float[] setSourceImage(byte[] pixels);
/**
+ * This is an alternative to the setSourceImage function above. This should
+ * be called when the image data is already on the native side in a fixed
+ * byte array. In implementation, this array is filled by the GL thread
+ * using glReadPixels directly from GPU memory (where it is accessed by
+ * an associated SurfaceTexture).
+ *
+ * @return Float array of length 10; first 9 entries correspond to the 3x3
+ * transformation matrix between the first frame and the passed frame,
+ * and the last entry is the number of the passed frame,
+ * where the counting starts from 1.
+ */
+ public native float[] setSourceImageFromGPU();
+
+ /**
* Set the type of blending.
*
* @param type the blending type defined in the class. {BLENDTYPE_FULL,
diff --git a/src/com/android/camera/panorama/MosaicFrameProcessor.java b/src/com/android/camera/panorama/MosaicFrameProcessor.java
index 6496f11..502d41f 100644
--- a/src/com/android/camera/panorama/MosaicFrameProcessor.java
+++ b/src/com/android/camera/panorama/MosaicFrameProcessor.java
@@ -56,18 +56,20 @@ public class MosaicFrameProcessor {
private int mPreviewWidth;
private int mPreviewHeight;
private int mPreviewBufferSize;
+ private boolean mUseSurfaceTexture;
public interface ProgressListener {
public void onProgress(boolean isFinished, float translationRate,
int traversedAngleX, int traversedAngleY);
}
- public MosaicFrameProcessor(int sweepAngle, int previewWidth, int previewHeight, int bufSize) {
+ public MosaicFrameProcessor(int sweepAngle, int previewWidth, int previewHeight, int bufSize, boolean useSurfaceTexture) {
mMosaicer = new Mosaic();
mCompassThreshold = sweepAngle;
mPreviewWidth = previewWidth;
mPreviewHeight = previewHeight;
mPreviewBufferSize = bufSize;
+ mUseSurfaceTexture = useSurfaceTexture;
}
public void setProgressListener(ProgressListener listener) {
@@ -75,7 +77,7 @@ public class MosaicFrameProcessor {
}
public void initialize() {
- setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize);
+ setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize, mUseSurfaceTexture);
reset();
}
@@ -87,8 +89,7 @@ public class MosaicFrameProcessor {
}
}
-
- private void setupMosaicer(int previewWidth, int previewHeight, int bufSize) {
+ private void setupMosaicer(int previewWidth, int previewHeight, int bufSize, boolean useSurfaceTexture) {
Log.v(TAG, "setupMosaicer w, h=" + previewWidth + ',' + previewHeight + ',' + bufSize);
mMosaicer.allocateMosaicMemory(previewWidth, previewHeight);
@@ -133,11 +134,14 @@ public class MosaicFrameProcessor {
}
long t1 = System.currentTimeMillis();
mFrameTimestamp[mFillIn] = t1;
- System.arraycopy(data, 0, mFrames[mFillIn], 0, data.length);
+
+ // TODO: Remove the case of byte data copy when SurfaceTexture is ready
+ if(!mUseSurfaceTexture)
+ System.arraycopy(data, 0, mFrames[mFillIn], 0, data.length);
+
mCurrProcessFrameIdx = mFillIn;
mFillIn = ((mFillIn + 1) % NUM_FRAMES_IN_BUFFER);
-
// Check that we are trying to process a frame different from the
// last one processed (useful if this class was running asynchronously)
if (mCurrProcessFrameIdx != mLastProcessFrameIdx) {
@@ -184,11 +188,12 @@ public class MosaicFrameProcessor {
float deltaTime = (now - mLastProcessedFrameTimestamp) / 1000.0f;
mLastProcessedFrameTimestamp = now;
- float[] frameData = mMosaicer.setSourceImage(data);
+ float[] frameData = mUseSurfaceTexture ?
+ mMosaicer.setSourceImageFromGPU() :
+ mMosaicer.setSourceImage(data);
mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX];
float translationCurrX = frameData[X_COORD_INDEX];
float translationCurrY = frameData[Y_COORD_INDEX];
-
mTranslationRate = Math.max(Math.abs(translationCurrX - mTranslationLastX),
Math.abs(translationCurrY - mTranslationLastY)) / deltaTime;
mTranslationLastX = translationCurrX;
diff --git a/src/com/android/camera/panorama/MosaicRenderer.java b/src/com/android/camera/panorama/MosaicRenderer.java
index 8db95c0..2bf471c 100644
--- a/src/com/android/camera/panorama/MosaicRenderer.java
+++ b/src/com/android/camera/panorama/MosaicRenderer.java
@@ -30,9 +30,12 @@ public class MosaicRenderer
/**
* Function to be called in onSurfaceCreated() to initialize
* the GL context, load and link the shaders and create the
- * program.
+ * program. Returns a texture ID to be used for SurfaceTexture.
+ *
+ * @return textureID the texture ID of the newly generated texture to
+ * be assigned to the SurfaceTexture object.
*/
- public static native void init();
+ public static native int init();
/**
* Pass the drawing surface's width and height to initialize the
@@ -44,6 +47,23 @@ public class MosaicRenderer
public static native void reset(int width, int height);
/**
+ * Calling this function will render the SurfaceTexture to a new 2D texture
+ * using the provided STMatrix and then call glReadPixels to fill the data
+ * array that will be processed by the mosaicing thread.
+ *
+ * @param stMatrix texture coordinate transform matrix obtained from the
+ * Surface texture
+ */
+ public static native void preprocess(float[] stMatrix);
+
+ /**
+ * This function calls glReadPixels to transfer both the low-res and high-res
+ * data from the GPU memory to the CPU memory for further processing by the
+ * mosaicing library.
+ */
+ public static native void transferGPUtoCPU();
+
+ /**
* Function to be called in onDrawFrame() to update the screen with
* the new frame data.
*/
@@ -59,9 +79,11 @@ public class MosaicRenderer
/**
* This function allows toggling between showing the input image data
- * (without applying any warp) and the warped image data. This is more
- * for debugging purposes to see if the image data is being updated
- * correctly or not.
+ * (without applying any warp) and the warped image data. For running
+ * the renderer as a viewfinder, we set the flag to false. To see the
+ * preview mosaic, we set the flag to true.
+ *
+ * @param flag boolean flag to set the warping to true or false.
*/
- public static native void togglewarping();
+ public static native void setWarping(boolean flag);
}
diff --git a/src/com/android/camera/panorama/MosaicRendererSurfaceView.java b/src/com/android/camera/panorama/MosaicRendererSurfaceView.java
index 3220b22..6767c87 100644
--- a/src/com/android/camera/panorama/MosaicRendererSurfaceView.java
+++ b/src/com/android/camera/panorama/MosaicRendererSurfaceView.java
@@ -21,9 +21,12 @@ import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
+import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
+import android.graphics.SurfaceTexture;
import android.opengl.GLSurfaceView;
+import android.os.ConditionVariable;
import android.util.AttributeSet;
import android.util.Log;
@@ -31,6 +34,7 @@ public class MosaicRendererSurfaceView extends GLSurfaceView {
private static String TAG = "MosaicRendererSurfaceView";
private static final boolean DEBUG = false;
private MosaicRendererSurfaceViewRenderer mRenderer;
+ private ConditionVariable mPreviewFrameReadyForProcessing;
public MosaicRendererSurfaceView(Context context) {
super(context);
@@ -50,7 +54,6 @@ public class MosaicRendererSurfaceView extends GLSurfaceView {
setZOrderMediaOverlay(true);
}
-
private void init(boolean translucent, int depth, int stencil) {
/* By default, GLSurfaceView() creates a RGB_565 opaque surface.
@@ -80,6 +83,7 @@ public class MosaicRendererSurfaceView extends GLSurfaceView {
mRenderer = new MosaicRendererSurfaceViewRenderer();
setRenderer(mRenderer);
setRenderMode(RENDERMODE_WHEN_DIRTY);
+ mPreviewFrameReadyForProcessing = new ConditionVariable();
}
private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
@@ -298,6 +302,21 @@ public class MosaicRendererSurfaceView extends GLSurfaceView {
private int[] mValue = new int[1];
}
+ public void lockPreviewReadyFlag()
+ {
+ mPreviewFrameReadyForProcessing.close();
+ }
+
+ private void unlockPreviewReadyFlag()
+ {
+ mPreviewFrameReadyForProcessing.open();
+ }
+
+ public void waitUntilPreviewReady()
+ {
+ mPreviewFrameReadyForProcessing.block();
+ }
+
public void setReady()
{
queueEvent(new Runnable() {
@@ -309,14 +328,67 @@ public class MosaicRendererSurfaceView extends GLSurfaceView {
});
}
- public void toggleWarping()
+ public void preprocess()
+ {
+ queueEvent(new Runnable() {
+
+ @Override
+ public void run() {
+ mRenderer.preprocess();
+ }
+ });
+ }
+
+ public void transferGPUtoCPU()
+ {
+ queueEvent(new Runnable() {
+
+ @Override
+ public void run() {
+ mRenderer.transferGPUtoCPU();
+ unlockPreviewReadyFlag();
+ }
+ });
+ }
+
+ public void setUIObject(final Activity activity)
{
queueEvent(new Runnable() {
@Override
public void run() {
- mRenderer.toggleWarping();
+ mRenderer.setUIObject(activity);
}
});
}
+
+ public void setWarping(final boolean flag)
+ {
+ queueEvent(new Runnable() {
+
+ @Override
+ public void run() {
+ mRenderer.setWarping(flag);
+ }
+ });
+ }
+
+ public int getTextureID() {
+ return mRenderer.getTextureID();
+ }
+
+ public void setSurfaceTexture(SurfaceTexture surface) {
+ mRenderer.setSurfaceTexture(surface);
+ }
+
+ public void updateSurfaceTexture() {
+ queueEvent(new Runnable() {
+
+ @Override
+ public void run() {
+ mRenderer.updateSurfaceTexture();
+ }
+ });
+ }
+
}
diff --git a/src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java b/src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java
index a27d4be..d29765a 100644
--- a/src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java
+++ b/src/com/android/camera/panorama/MosaicRendererSurfaceViewRenderer.java
@@ -19,37 +19,78 @@ package com.android.camera.panorama;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
+import android.app.Activity;
+import android.graphics.SurfaceTexture;
import android.opengl.GLSurfaceView;
-
+import android.util.Log;
public class MosaicRendererSurfaceViewRenderer implements GLSurfaceView.Renderer
{
@Override
- public void onDrawFrame(GL10 gl)
- {
+ public void onDrawFrame(GL10 gl) {
MosaicRenderer.step();
}
@Override
- public void onSurfaceChanged(GL10 gl, int width, int height)
- {
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ Log.i(TAG, "Renderer: onSurfaceChanged");
MosaicRenderer.reset(width, height);
+ Log.i(TAG, "Renderer: onSurfaceChanged");
}
@Override
- public void onSurfaceCreated(GL10 gl, EGLConfig config)
- {
- MosaicRenderer.init();
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ mTextureID = MosaicRenderer.init();
+
+ mActivity.runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+ mActivity.createSurfaceTextureAndStartPreview(mTextureID);
+ setSurfaceTexture(mActivity.getSurfaceTexture());
+ }
+ });
}
- public void setReady()
- {
+ public void setReady() {
MosaicRenderer.ready();
}
- public void toggleWarping()
- {
- MosaicRenderer.togglewarping();
+ public void preprocess() {
+ MosaicRenderer.preprocess(mSTMatrix);
+ }
+
+ public void transferGPUtoCPU() {
+ MosaicRenderer.transferGPUtoCPU();
+ }
+
+ public void setWarping(boolean flag) {
+ MosaicRenderer.setWarping(flag);
+ }
+
+ public void updateSurfaceTexture() {
+ mSurface.updateTexImage();
+ mSurface.getTransformMatrix(mSTMatrix);
}
+ public void setUIObject(Activity activity) {
+ mActivity = (PanoramaActivity)activity;
+ }
+
+ public int getTextureID() {
+ return mTextureID;
+ }
+
+ public void setSurfaceTexture(SurfaceTexture surface) {
+ mSurface = surface;
+ }
+
+ private float[] mSTMatrix = new float[16];
+ private int mTextureID;
+
+ private PanoramaActivity mActivity;
+
+ private static String TAG = "MosaicRendererSurfaceViewRenderer";
+
+ private SurfaceTexture mSurface;
}
diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java
index 0b1ec60..d9645ff 100644
--- a/src/com/android/camera/panorama/PanoramaActivity.java
+++ b/src/com/android/camera/panorama/PanoramaActivity.java
@@ -33,19 +33,19 @@ import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera;
-import android.hardware.Camera.Parameters;
-import android.hardware.Camera.Size;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
+import android.hardware.Camera.Parameters;
+import android.hardware.Camera.Size;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
-import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
@@ -58,7 +58,8 @@ import java.util.List;
* Activity to handle panorama capturing.
*/
public class PanoramaActivity extends Activity implements
- ModePicker.OnModeChangeListener, SurfaceHolder.Callback {
+ ModePicker.OnModeChangeListener,
+ SurfaceTexture.OnFrameAvailableListener {
public static final int DEFAULT_SWEEP_ANGLE = 60;
public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL;
public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720;
@@ -69,6 +70,9 @@ public class PanoramaActivity extends Activity implements
private static final String TAG = "PanoramaActivity";
private static final int PREVIEW_STOPPED = 0;
private static final int PREVIEW_ACTIVE = 1;
+ private static final int CAPTURE_VIEWFINDER = 0;
+ private static final int CAPTURE_MOSAIC = 1;
+
// Ratio of nanosecond to second
private static final float NS2S = 1.0f / 1000000000.0f;
@@ -89,6 +93,7 @@ public class PanoramaActivity extends Activity implements
private int mPreviewHeight;
private Camera mCameraDevice;
private int mCameraState;
+ private int mCaptureState;
private SensorManager mSensorManager;
private Sensor mSensor;
private ModePicker mModePicker;
@@ -96,7 +101,8 @@ public class PanoramaActivity extends Activity implements
private String mCurrentImagePath = null;
private long mTimeTaken;
private Handler mMainHandler;
- private SurfaceHolder mSurfaceHolder;
+ private SurfaceTexture mSurface;
+ private boolean mUseSurfaceTexture = true;
private boolean mThreadRunning;
@@ -133,6 +139,22 @@ public class PanoramaActivity extends Activity implements
};
}
+ public void createSurfaceTextureAndStartPreview(int textureID)
+ {
+ /*
+ * Create the SurfaceTexture that will feed this textureID, and pass it to the camera
+ */
+ mSurface = new SurfaceTexture(textureID);
+ mSurface.setOnFrameAvailableListener(this);
+ startPreview();
+ Log.i(TAG, "Created Surface Texture");
+ }
+
+ public SurfaceTexture getSurfaceTexture()
+ {
+ return mSurface;
+ }
+
private void setupCamera() {
openCamera();
Parameters parameters = mCameraDevice.getParameters();
@@ -223,14 +245,16 @@ public class PanoramaActivity extends Activity implements
CameraHolder.instance().getBackCameraId());
mCameraDevice.setDisplayOrientation(orientation);
- int bufSize = getPreviewBufSize();
- Log.v(TAG, "BufSize = " + bufSize);
- for (int i = 0; i < 10; i++) {
- try {
- mCameraDevice.addCallbackBuffer(new byte[bufSize]);
- } catch (OutOfMemoryError e) {
- Log.v(TAG, "Buffer allocation failed: buffer " + i);
- break;
+ if(!mUseSurfaceTexture) {
+ int bufSize = getPreviewBufSize();
+ Log.v(TAG, "BufSize = " + bufSize);
+ for (int i = 0; i < 10; i++) {
+ try {
+ mCameraDevice.addCallbackBuffer(new byte[bufSize]);
+ } catch (OutOfMemoryError e) {
+ Log.v(TAG, "Buffer allocation failed: buffer " + i);
+ break;
+ }
}
}
}
@@ -252,9 +276,51 @@ public class PanoramaActivity extends Activity implements
}
}
+ public void runViewFinder() {
+ mRealTimeMosaicView.setWarping(false);
+
+ // First update the surface texture...
+ mRealTimeMosaicView.updateSurfaceTexture();
+ // ...then call preprocess to render it to low-res and high-res RGB textures
+ mRealTimeMosaicView.preprocess();
+
+ mRealTimeMosaicView.setReady();
+ mRealTimeMosaicView.requestRender();
+ }
+
+ public void runMosaicCapture() {
+ mRealTimeMosaicView.setWarping(true);
+
+ // Lock the condition variable
+ mRealTimeMosaicView.lockPreviewReadyFlag();
+ // First update the surface texture...
+ mRealTimeMosaicView.updateSurfaceTexture();
+ // ...then call preprocess to render it to low-res and high-res RGB textures
+ mRealTimeMosaicView.preprocess();
+ // Now, transfer the textures from GPU to CPU memory for processing
+ mRealTimeMosaicView.transferGPUtoCPU();
+ // Wait on the condition variable (will be opened when GPU->CPU transfer is done).
+ mRealTimeMosaicView.waitUntilPreviewReady();
+
+ mMosaicFrameProcessor.processFrame(null);
+ }
+
+ synchronized public void onFrameAvailable(SurfaceTexture surface) {
+ /* For simplicity, SurfaceTexture calls here when it has new
+ * data available. Call may come in from some random thread,
+ * so let's be safe and use synchronize. No OpenGL calls can be done here.
+ */
+ if (mCaptureState == CAPTURE_VIEWFINDER) {
+ runViewFinder();
+ } else {
+ runMosaicCapture();
+ }
+ }
+
public void startCapture() {
// Reset values so we can do this again.
mTimeTaken = System.currentTimeMillis();
+ mCaptureState = CAPTURE_MOSAIC;
mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() {
@Override
@@ -268,26 +334,38 @@ public class PanoramaActivity extends Activity implements
}
});
- // Preview callback used whenever new viewfinder frame is available
- mCameraDevice.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
- @Override
- public void onPreviewFrame(final byte[] data, Camera camera) {
- mMosaicFrameProcessor.processFrame(data);
- // The returned buffer needs be added back to callback buffer
- // again.
- camera.addCallbackBuffer(data);
- }
- });
+ if (!mUseSurfaceTexture) {
+ // Preview callback used whenever new viewfinder frame is available
+ mCameraDevice.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
+ @Override
+ public void onPreviewFrame(final byte[] data, Camera camera) {
+ mMosaicFrameProcessor.processFrame(data);
+ // The returned buffer needs be added back to callback buffer
+ // again.
+ camera.addCallbackBuffer(data);
+ }
+ });
+ }
mCaptureLayout.setVisibility(View.VISIBLE);
mPreview.setVisibility(View.INVISIBLE); // will be re-used, invisible is better than gone.
mRealTimeMosaicView.setVisibility(View.VISIBLE);
mPanoControlLayout.setVisibility(View.GONE);
+
}
private void stopCapture() {
+ mCaptureState = CAPTURE_VIEWFINDER;
+
mMosaicFrameProcessor.setProgressListener(null);
stopPreview();
+
+ if (!mUseSurfaceTexture) {
+ mCameraDevice.setPreviewCallbackWithBuffer(null);
+ }
+
+ mSurface.setOnFrameAvailableListener(null);
+
// TODO: show some dialog for long computation.
if (!mThreadRunning) {
mThreadRunning = true;
@@ -322,17 +400,19 @@ public class PanoramaActivity extends Activity implements
private void createContentView() {
setContentView(R.layout.panorama);
+ mCaptureState = CAPTURE_VIEWFINDER;
+
mCaptureLayout = (View) findViewById(R.id.pano_capture_layout);
mReviewLayout = (View) findViewById(R.id.pano_review_layout);
mPreview = (SurfaceView) findViewById(R.id.pano_preview_view);
- mPreview.getHolder().addCallback(this);
+
mCaptureView = (CaptureView) findViewById(R.id.pano_capture_view);
mCaptureView.setStartAngle(-DEFAULT_SWEEP_ANGLE / 2);
mReview = (ImageView) findViewById(R.id.pano_reviewarea);
mRealTimeMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer);
- mRealTimeMosaicView.setVisibility(View.GONE);
+ mRealTimeMosaicView.setUIObject(this);
mShutterButton = (ShutterButton) findViewById(R.id.pano_shutter_button);
mShutterButton.setOnClickListener(new View.OnClickListener() {
@@ -349,6 +429,8 @@ public class PanoramaActivity extends Activity implements
mModePicker.setVisibility(View.VISIBLE);
mModePicker.setOnModeChangeListener(this);
mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA);
+
+ mRealTimeMosaicView.setVisibility(View.VISIBLE);
}
@OnClickAttr
@@ -377,13 +459,19 @@ public class PanoramaActivity extends Activity implements
}
private void resetToPreview() {
+ mCaptureState = CAPTURE_VIEWFINDER;
+
+ mReviewLayout.setVisibility(View.GONE);
mPreview.setVisibility(View.VISIBLE);
mPanoControlLayout.setVisibility(View.VISIBLE);
- mRealTimeMosaicView.setVisibility(View.GONE);
mCaptureLayout.setVisibility(View.GONE);
- mReviewLayout.setVisibility(View.GONE);
mMosaicFrameProcessor.reset();
+
+ mSurface.setOnFrameAvailableListener(this);
+
if (!mPausing) startPreview();
+
+ mRealTimeMosaicView.setVisibility(View.VISIBLE);
}
private void showFinalMosaic(Bitmap bitmap) {
@@ -394,6 +482,7 @@ public class PanoramaActivity extends Activity implements
mReviewLayout.setVisibility(View.VISIBLE);
mCaptureView.setStatusText("");
mCaptureView.setSweepAngle(0);
+ mCaptureView.invalidate();
}
}
@@ -416,7 +505,7 @@ public class PanoramaActivity extends Activity implements
if (mMosaicFrameProcessor == null) {
// Start the activity for the first time.
mMosaicFrameProcessor = new MosaicFrameProcessor(DEFAULT_SWEEP_ANGLE - 5,
- mPreviewWidth, mPreviewHeight, getPreviewBufSize());
+ mPreviewWidth, mPreviewHeight, getPreviewBufSize(), mUseSurfaceTexture);
}
mMosaicFrameProcessor.initialize();
}
@@ -424,10 +513,12 @@ public class PanoramaActivity extends Activity implements
@Override
protected void onPause() {
super.onPause();
+ mSurface.setOnFrameAvailableListener(null);
releaseCamera();
mPausing = true;
- mCaptureView.onPause();
+
mRealTimeMosaicView.onPause();
+ mCaptureView.onPause();
mSensorManager.unregisterListener(mListener);
clearMosaicFrameProcessorIfNeeded();
System.gc();
@@ -446,12 +537,11 @@ public class PanoramaActivity extends Activity implements
* resources.
*/
mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI);
-
+ mCaptureState = CAPTURE_VIEWFINDER;
setupCamera();
// Camera must be initialized before MosaicFrameProcessor is initialized. The preview size
// has to be decided by camera device.
initMosaicFrameProcessorIfNeeded();
- startPreview();
mCaptureView.onResume();
mRealTimeMosaicView.onResume();
}
@@ -526,45 +616,12 @@ public class PanoramaActivity extends Activity implements
System.gc();
}
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
- mSurfaceHolder = holder;
-
- if (mCameraDevice == null) return;
-
- // Set preview display if the surface is being created. Preview was
- // already started. Also restart the preview if display rotation has
- // changed. Sometimes this happens when the device is held in portrait
- // and camera app is opened. Rotation animation takes some time and
- // display rotation in onCreate may not be what we want.
- if (holder.isCreating()) {
- // Set preview display if the surface is being created and preview
- // was already started. That means preview display was set to null
- // and we need to set it now.
- setPreviewDisplay(holder);
- } else {
- // 1. Restart the preview if the size of surface was changed. The
- // framework may not support changing preview display on the fly.
- // 2. Start the preview now if surface was destroyed and preview
- // stopped.
- startPreview();
- }
- }
-
- private void setPreviewDisplay(SurfaceHolder holder) {
+ private void setPreviewTexture(SurfaceTexture surface) {
try {
- mCameraDevice.setPreviewDisplay(holder);
+ mCameraDevice.setPreviewTexture(surface);
} catch (Throwable ex) {
releaseCamera();
- throw new RuntimeException("setPreviewDisplay failed", ex);
+ throw new RuntimeException("setPreviewTexture failed", ex);
}
}
@@ -573,7 +630,7 @@ public class PanoramaActivity extends Activity implements
// the screen).
if (mCameraState != PREVIEW_STOPPED) stopPreview();
- setPreviewDisplay(mSurfaceHolder);
+ setPreviewTexture(mSurface);
try {
Log.v(TAG, "startPreview");