diff options
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/camera/Mosaic.java | 206 | ||||
-rw-r--r-- | src/com/android/camera/MosaicFrameProcessor.java | 237 | ||||
-rw-r--r-- | src/com/android/camera/MosaicPreviewRenderer.java | 183 | ||||
-rw-r--r-- | src/com/android/camera/MosaicRenderer.java | 89 | ||||
-rw-r--r-- | src/com/android/camera/WideAnglePanoramaController.java | 35 | ||||
-rw-r--r-- | src/com/android/camera/WideAnglePanoramaModule.java | 1062 | ||||
-rw-r--r-- | src/com/android/camera/WideAnglePanoramaUI.java | 495 | ||||
-rw-r--r-- | src/com/android/camera/module/ModulesInfo.java | 2 |
8 files changed, 0 insertions, 2309 deletions
diff --git a/src/com/android/camera/Mosaic.java b/src/com/android/camera/Mosaic.java deleted file mode 100644 index b1d10c05b..000000000 --- a/src/com/android/camera/Mosaic.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -/** - * The Java interface to JNI calls regarding mosaic stitching. - * - * A high-level usage is: - * - * Mosaic mosaic = new Mosaic(); - * mosaic.setSourceImageDimensions(width, height); - * mosaic.reset(blendType); - * - * while ((pixels = hasNextImage()) != null) { - * mosaic.setSourceImage(pixels); - * } - * - * mosaic.createMosaic(highRes); - * byte[] result = mosaic.getFinalMosaic(); - * - */ -public class Mosaic { - /** - * In this mode, the images are stitched together in the same spatial arrangement as acquired - * i.e. if the user follows a curvy trajectory, the image boundary of the resulting mosaic will - * be curved in the same manner. This mode is useful if the user wants to capture a mosaic as - * if "painting" the scene using the smart-phone device and does not want any corrective warps - * to distort the captured images. - */ - public static final int BLENDTYPE_FULL = 0; - - /** - * This mode is the same as BLENDTYPE_FULL except that the resulting mosaic is rotated - * to balance the first and last images to be approximately at the same vertical offset in the - * output mosaic. This is useful when acquiring a mosaic by a typical panning-like motion to - * remove a one-sided curve in the mosaic (typically due to the camera not staying horizontal - * during the video capture) and convert it to a more symmetrical "smiley-face" like output. - */ - public static final int BLENDTYPE_PAN = 1; - - /** - * This mode compensates for typical "smiley-face" like output in longer mosaics and creates - * a rectangular mosaic with minimal black borders (by unwrapping the mosaic onto an imaginary - * cylinder). If the user follows a curved trajectory (instead of a perfect panning trajectory), - * the resulting mosaic here may suffer from some image distortions in trying to map the - * trajectory to a cylinder. - */ - public static final int BLENDTYPE_CYLINDERPAN = 2; - - /** - * This mode is basically BLENDTYPE_CYLINDERPAN plus doing a rectangle cropping before returning - * the mosaic. The mode is useful for making the resulting mosaic have a rectangle shape. - */ - public static final int BLENDTYPE_HORIZONTAL =3; - - /** - * This strip type will use the default thin strips where the strips are - * spaced according to the image capture rate. - */ - public static final int STRIPTYPE_THIN = 0; - - /** - * This strip type will use wider strips for blending. The strip separation - * is controlled by a threshold on the native side. Since the strips are - * wider, there is an additional cross-fade blending step to make the seam - * boundaries smoother. Since this mode uses lesser image frames, it is - * computationally more efficient than the thin strip mode. - */ - public static final int STRIPTYPE_WIDE = 1; - - /** - * Return flags returned by createMosaic() are one of the following. - */ - public static final int MOSAIC_RET_OK = 1; - public static final int MOSAIC_RET_ERROR = -1; - public static final int MOSAIC_RET_CANCELLED = -2; - public static final int MOSAIC_RET_LOW_TEXTURE = -3; - public static final int MOSAIC_RET_FEW_INLIERS = 2; - - - static { - System.loadLibrary("jni_mosaic"); - } - - /** - * Allocate memory for the image frames at the given resolution. - * - * @param width width of the input frames in pixels - * @param height height of the input frames in pixels - */ - public native void allocateMosaicMemory(int width, int height); - - /** - * Free memory allocated by allocateMosaicMemory. - * - */ - public native void freeMosaicMemory(); - - /** - * Pass the input image frame to the native layer. Each time the a new - * source image t is set, the transformation matrix from the first source - * image to t is computed and returned. - * - * @param pixels source image of NV21 format. - * @return Float array of length 11; first 9 entries correspond to the 3x3 - * transformation matrix between the first frame and the passed frame; - * the 10th entry is the number of the passed frame, where the counting - * starts from 1; and the 11th entry is the returning code, whose value - * is one of those MOSAIC_RET_* returning flags defined above. - */ - 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 11; first 9 entries correspond to the 3x3 - * transformation matrix between the first frame and the passed frame; - * the 10th entry is the number of the passed frame, where the counting - * starts from 1; and the 11th entry is the returning code, whose value - * is one of those MOSAIC_RET_* returning flags defined above. - */ - public native float[] setSourceImageFromGPU(); - - /** - * Set the type of blending. - * - * @param type the blending type defined in the class. {BLENDTYPE_FULL, - * BLENDTYPE_PAN, BLENDTYPE_CYLINDERPAN, BLENDTYPE_HORIZONTAL} - */ - public native void setBlendingType(int type); - - /** - * Set the type of strips to use for blending. - * @param type the blending strip type to use {STRIPTYPE_THIN, - * STRIPTYPE_WIDE}. - */ - public native void setStripType(int type); - - /** - * Tell the native layer to create the final mosaic after all the input frame - * data have been collected. - * The case of generating high-resolution mosaic may take dozens of seconds to finish. - * - * @param value True means generating a high-resolution mosaic - - * which is based on the original images set in setSourceImage(). - * False means generating a low-resolution version - - * which is based on 1/4 downscaled images from the original images. - * @return Returns a status code suggesting if the mosaic building was - * successful, in error, or was cancelled by the user. - */ - public native int createMosaic(boolean value); - - /** - * Get the data for the created mosaic. - * - * @return Returns an integer array which contains the final mosaic in the ARGB_8888 format. - * The first MosaicWidth*MosaicHeight values contain the image data, followed by 2 - * integers corresponding to the values MosaicWidth and MosaicHeight respectively. - */ - public native int[] getFinalMosaic(); - - /** - * Get the data for the created mosaic. - * - * @return Returns a byte array which contains the final mosaic in the NV21 format. - * The first MosaicWidth*MosaicHeight*1.5 values contain the image data, followed by - * 8 bytes which pack the MosaicWidth and MosaicHeight integers into 4 bytes each - * respectively. - */ - public native byte[] getFinalMosaicNV21(); - - /** - * Reset the state of the frame arrays which maintain the captured frame data. - * Also re-initializes the native mosaic object to make it ready for capturing a new mosaic. - */ - public native void reset(); - - /** - * Get the progress status of the mosaic computation process. - * @param hires Boolean flag to select whether to report progress of the - * low-res or high-res mosaicer. - * @param cancelComputation Boolean flag to allow cancelling the - * mosaic computation when needed from the GUI end. - * @return Returns a number from 0-100 where 50 denotes that the mosaic - * computation is 50% done. - */ - public native int reportProgress(boolean hires, boolean cancelComputation); -} diff --git a/src/com/android/camera/MosaicFrameProcessor.java b/src/com/android/camera/MosaicFrameProcessor.java deleted file mode 100644 index cb305344d..000000000 --- a/src/com/android/camera/MosaicFrameProcessor.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.util.Log; - -/** - * A singleton to handle the processing of each frame by {@link Mosaic}. - */ -public class MosaicFrameProcessor { - private static final String TAG = "MosaicFrameProcessor"; - private static final int NUM_FRAMES_IN_BUFFER = 2; - private static final int MAX_NUMBER_OF_FRAMES = 100; - private static final int MOSAIC_RET_CODE_INDEX = 10; - private static final int FRAME_COUNT_INDEX = 9; - private static final int X_COORD_INDEX = 2; - private static final int Y_COORD_INDEX = 5; - private static final int HR_TO_LR_DOWNSAMPLE_FACTOR = 4; - private static final int WINDOW_SIZE = 3; - - private Mosaic mMosaicer; - private boolean mIsMosaicMemoryAllocated = false; - private float mTranslationLastX; - private float mTranslationLastY; - - private int mFillIn = 0; - private int mTotalFrameCount = 0; - private int mLastProcessFrameIdx = -1; - private int mCurrProcessFrameIdx = -1; - private boolean mFirstRun; - - // Panning rate is in unit of percentage of image content translation per - // frame. Use moving average to calculate the panning rate. - private float mPanningRateX; - private float mPanningRateY; - - private float[] mDeltaX = new float[WINDOW_SIZE]; - private float[] mDeltaY = new float[WINDOW_SIZE]; - private int mOldestIdx = 0; - private float mTotalTranslationX = 0f; - private float mTotalTranslationY = 0f; - - private ProgressListener mProgressListener; - - private int mPreviewWidth; - private int mPreviewHeight; - private int mPreviewBufferSize; - - private static MosaicFrameProcessor sMosaicFrameProcessor; // singleton - - public interface ProgressListener { - public void onProgress(boolean isFinished, float panningRateX, float panningRateY, - float progressX, float progressY); - } - - public static MosaicFrameProcessor getInstance() { - if (sMosaicFrameProcessor == null) { - sMosaicFrameProcessor = new MosaicFrameProcessor(); - } - return sMosaicFrameProcessor; - } - - private MosaicFrameProcessor() { - mMosaicer = new Mosaic(); - } - - public void setProgressListener(ProgressListener listener) { - mProgressListener = listener; - } - - public int reportProgress(boolean hires, boolean cancel) { - return mMosaicer.reportProgress(hires, cancel); - } - - public void initialize(int previewWidth, int previewHeight, int bufSize) { - mPreviewWidth = previewWidth; - mPreviewHeight = previewHeight; - mPreviewBufferSize = bufSize; - setupMosaicer(mPreviewWidth, mPreviewHeight, mPreviewBufferSize); - setStripType(Mosaic.STRIPTYPE_WIDE); - // no need to call reset() here. reset() should be called by the client - // after this initialization before calling other methods of this object. - } - - public void clear() { - if (mIsMosaicMemoryAllocated) { - mMosaicer.freeMosaicMemory(); - mIsMosaicMemoryAllocated = false; - } - synchronized (this) { - notify(); - } - } - - public boolean isMosaicMemoryAllocated() { - return mIsMosaicMemoryAllocated; - } - - public void setStripType(int type) { - mMosaicer.setStripType(type); - } - - private void setupMosaicer(int previewWidth, int previewHeight, int bufSize) { - Log.v(TAG, "setupMosaicer w, h=" + previewWidth + ',' + previewHeight + ',' + bufSize); - - if (mIsMosaicMemoryAllocated) throw new RuntimeException("MosaicFrameProcessor in use!"); - mIsMosaicMemoryAllocated = true; - mMosaicer.allocateMosaicMemory(previewWidth, previewHeight); - } - - public void reset() { - // reset() can be called even if MosaicFrameProcessor is not initialized. - // Only counters will be changed. - mFirstRun = true; - mTotalFrameCount = 0; - mFillIn = 0; - mTotalTranslationX = 0; - mTranslationLastX = 0; - mTotalTranslationY = 0; - mTranslationLastY = 0; - mPanningRateX = 0; - mPanningRateY = 0; - mLastProcessFrameIdx = -1; - mCurrProcessFrameIdx = -1; - for (int i = 0; i < WINDOW_SIZE; ++i) { - mDeltaX[i] = 0f; - mDeltaY[i] = 0f; - } - mMosaicer.reset(); - } - - public int createMosaic(boolean highRes) { - return mMosaicer.createMosaic(highRes); - } - - public byte[] getFinalMosaicNV21() { - return mMosaicer.getFinalMosaicNV21(); - } - - // Processes the last filled image frame through the mosaicer and - // updates the UI to show progress. - // When done, processes and displays the final mosaic. - public void processFrame() { - if (!mIsMosaicMemoryAllocated) { - // clear() is called and buffers are cleared, stop computation. - // This can happen when the onPause() is called in the activity, but still some frames - // are not processed yet and thus the callback may be invoked. - return; - } - - 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) { - mLastProcessFrameIdx = mCurrProcessFrameIdx; - - // TODO: make the termination condition regarding reaching - // MAX_NUMBER_OF_FRAMES solely determined in the library. - if (mTotalFrameCount < MAX_NUMBER_OF_FRAMES) { - // If we are still collecting new frames for the current mosaic, - // process the new frame. - calculateTranslationRate(); - - // Publish progress of the ongoing processing - if (mProgressListener != null) { - mProgressListener.onProgress(false, mPanningRateX, mPanningRateY, - mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, - mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); - } - } else { - if (mProgressListener != null) { - mProgressListener.onProgress(true, mPanningRateX, mPanningRateY, - mTranslationLastX * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewWidth, - mTranslationLastY * HR_TO_LR_DOWNSAMPLE_FACTOR / mPreviewHeight); - } - } - } - } - - public void calculateTranslationRate() { - float[] frameData = mMosaicer.setSourceImageFromGPU(); - int ret_code = (int) frameData[MOSAIC_RET_CODE_INDEX]; - mTotalFrameCount = (int) frameData[FRAME_COUNT_INDEX]; - float translationCurrX = frameData[X_COORD_INDEX]; - float translationCurrY = frameData[Y_COORD_INDEX]; - - if (mFirstRun) { - // First time: no need to update delta values. - mTranslationLastX = translationCurrX; - mTranslationLastY = translationCurrY; - mFirstRun = false; - return; - } - - // Moving average: remove the oldest translation/deltaTime and - // add the newest translation/deltaTime in - int idx = mOldestIdx; - mTotalTranslationX -= mDeltaX[idx]; - mTotalTranslationY -= mDeltaY[idx]; - mDeltaX[idx] = Math.abs(translationCurrX - mTranslationLastX); - mDeltaY[idx] = Math.abs(translationCurrY - mTranslationLastY); - mTotalTranslationX += mDeltaX[idx]; - mTotalTranslationY += mDeltaY[idx]; - - // The panning rate is measured as the rate of the translation percentage in - // image width/height. Take the horizontal panning rate for example, the image width - // used in finding the translation is (PreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR). - // To get the horizontal translation percentage, the horizontal translation, - // (translationCurrX - mTranslationLastX), is divided by the - // image width. We then get the rate by dividing the translation percentage with the - // number of frames. - mPanningRateX = mTotalTranslationX / - (mPreviewWidth / HR_TO_LR_DOWNSAMPLE_FACTOR) / WINDOW_SIZE; - mPanningRateY = mTotalTranslationY / - (mPreviewHeight / HR_TO_LR_DOWNSAMPLE_FACTOR) / WINDOW_SIZE; - - mTranslationLastX = translationCurrX; - mTranslationLastY = translationCurrY; - mOldestIdx = (mOldestIdx + 1) % WINDOW_SIZE; - } -} diff --git a/src/com/android/camera/MosaicPreviewRenderer.java b/src/com/android/camera/MosaicPreviewRenderer.java deleted file mode 100644 index 42da4d9e7..000000000 --- a/src/com/android/camera/MosaicPreviewRenderer.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.graphics.SurfaceTexture; -import android.os.ConditionVariable; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; - -import javax.microedition.khronos.opengles.GL10; - -public class MosaicPreviewRenderer { - - @SuppressWarnings("unused") - private static final String TAG = "CAM_MosaicPreviewRenderer"; - - private int mWidth; // width of the view in UI - private int mHeight; // height of the view in UI - - private boolean mIsLandscape = true; - private final float[] mTransformMatrix = new float[16]; - - private ConditionVariable mEglThreadBlockVar = new ConditionVariable(); - private HandlerThread mEglThread; - private MyHandler mHandler; - private SurfaceTextureRenderer mSTRenderer; - - private SurfaceTexture mInputSurfaceTexture; - - private class MyHandler extends Handler { - public static final int MSG_INIT_SYNC = 0; - public static final int MSG_SHOW_PREVIEW_FRAME_SYNC = 1; - public static final int MSG_SHOW_PREVIEW_FRAME = 2; - public static final int MSG_ALIGN_FRAME_SYNC = 3; - public static final int MSG_RELEASE = 4; - - public MyHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_INIT_SYNC: - doInit(); - mEglThreadBlockVar.open(); - break; - case MSG_SHOW_PREVIEW_FRAME_SYNC: - doShowPreviewFrame(); - mEglThreadBlockVar.open(); - break; - case MSG_SHOW_PREVIEW_FRAME: - doShowPreviewFrame(); - break; - case MSG_ALIGN_FRAME_SYNC: - doAlignFrame(); - mEglThreadBlockVar.open(); - break; - case MSG_RELEASE: - doRelease(); - mEglThreadBlockVar.open(); - break; - } - } - - private void doAlignFrame() { - mInputSurfaceTexture.updateTexImage(); - mInputSurfaceTexture.getTransformMatrix(mTransformMatrix); - - MosaicRenderer.setWarping(true); - // Call preprocess to render it to low-res and high-res RGB textures. - MosaicRenderer.preprocess(mTransformMatrix); - // Now, transfer the textures from GPU to CPU memory for processing - MosaicRenderer.transferGPUtoCPU(); - MosaicRenderer.updateMatrix(); - MosaicRenderer.step(); - } - - private void doShowPreviewFrame() { - mInputSurfaceTexture.updateTexImage(); - mInputSurfaceTexture.getTransformMatrix(mTransformMatrix); - - MosaicRenderer.setWarping(false); - // Call preprocess to render it to low-res and high-res RGB textures. - MosaicRenderer.preprocess(mTransformMatrix); - MosaicRenderer.updateMatrix(); - MosaicRenderer.step(); - } - - private void doInit() { - mInputSurfaceTexture = new SurfaceTexture(MosaicRenderer.init()); - MosaicRenderer.reset(mWidth, mHeight, mIsLandscape); - } - - private void doRelease() { - releaseSurfaceTexture(mInputSurfaceTexture); - mEglThread.quit(); - } - - private void releaseSurfaceTexture(SurfaceTexture st) { - st.release(); - } - - // Should be called from other thread. - public void sendMessageSync(int msg) { - mEglThreadBlockVar.close(); - sendEmptyMessage(msg); - mEglThreadBlockVar.block(); - } - } - - /** - * Constructor. - * - * @param tex The {@link SurfaceTexture} for the final UI output. - * @param w The width of the UI view. - * @param h The height of the UI view. - * @param isLandscape The UI orientation. {@code true} if in landscape, - * false if in portrait. - */ - public MosaicPreviewRenderer(SurfaceTexture tex, int w, int h, boolean isLandscape) { - mIsLandscape = isLandscape; - - mEglThread = new HandlerThread("PanoramaRealtimeRenderer"); - mEglThread.start(); - mHandler = new MyHandler(mEglThread.getLooper()); - mWidth = w; - mHeight = h; - - SurfaceTextureRenderer.FrameDrawer dummy = new SurfaceTextureRenderer.FrameDrawer() { - @Override - public void onDrawFrame(GL10 gl) { - // nothing, we have our draw functions. - } - }; - mSTRenderer = new SurfaceTextureRenderer(tex, mHandler, dummy); - - // We need to sync this because the generation of surface texture for input is - // done here and the client will continue with the assumption that the - // generation is completed. - mHandler.sendMessageSync(MyHandler.MSG_INIT_SYNC); - } - - public void release() { - mSTRenderer.release(); - mHandler.sendMessageSync(MyHandler.MSG_RELEASE); - } - - public void showPreviewFrameSync() { - mHandler.sendMessageSync(MyHandler.MSG_SHOW_PREVIEW_FRAME_SYNC); - mSTRenderer.draw(true); - } - - public void showPreviewFrame() { - mHandler.sendEmptyMessage(MyHandler.MSG_SHOW_PREVIEW_FRAME); - mSTRenderer.draw(false); - } - - public void alignFrameSync() { - mHandler.sendMessageSync(MyHandler.MSG_ALIGN_FRAME_SYNC); - mSTRenderer.draw(true); - } - - public SurfaceTexture getInputSurfaceTexture() { - return mInputSurfaceTexture; - } -} diff --git a/src/com/android/camera/MosaicRenderer.java b/src/com/android/camera/MosaicRenderer.java deleted file mode 100644 index c50ca0d52..000000000 --- a/src/com/android/camera/MosaicRenderer.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -/** - * The Java interface to JNI calls regarding mosaic preview rendering. - * - */ -public class MosaicRenderer -{ - static - { - System.loadLibrary("jni_mosaic"); - } - - /** - * Function to be called in onSurfaceCreated() to initialize - * the GL context, load and link the shaders and create the - * 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 int init(); - - /** - * Pass the drawing surface's width and height to initialize the - * renderer viewports and FBO dimensions. - * - * @param width width of the drawing surface in pixels. - * @param height height of the drawing surface in pixels. - * @param isLandscapeOrientation is the orientation of the activity layout in landscape. - */ - public static native void reset(int width, int height, boolean isLandscapeOrientation); - - /** - * Calling this function will render the SurfaceTexture to a new 2D texture - * using the provided STMatrix. - * - * @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. - */ - public static native void step(); - - /** - * Call this function when a new low-res frame has been processed by - * the mosaicing library. This will tell the renderer library to - * update its texture and warping transformation. Any calls to step() - * after this call will use the new image frame and transformation data. - */ - public static native void updateMatrix(); - - /** - * This function allows toggling between showing the input image data - * (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 setWarping(boolean flag); -} diff --git a/src/com/android/camera/WideAnglePanoramaController.java b/src/com/android/camera/WideAnglePanoramaController.java deleted file mode 100644 index d711c0942..000000000 --- a/src/com/android/camera/WideAnglePanoramaController.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -/** - * The interface that controls the wide angle panorama module. - */ -public interface WideAnglePanoramaController { - - public void onPreviewUIReady(); - - public void onPreviewUIDestroyed(); - - public void cancelHighResStitching(); - - public void onShutterButtonClick(); - - public void onPreviewUILayoutChange(int l, int t, int r, int b); - - public int getCameraOrientation(); -} diff --git a/src/com/android/camera/WideAnglePanoramaModule.java b/src/com/android/camera/WideAnglePanoramaModule.java deleted file mode 100644 index 7981bae2b..000000000 --- a/src/com/android/camera/WideAnglePanoramaModule.java +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.ImageFormat; -import android.graphics.PixelFormat; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.SurfaceTexture; -import android.graphics.YuvImage; -import android.hardware.Camera.Parameters; -import android.hardware.Camera.Size; -import android.location.Location; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Handler; -import android.os.Message; -import android.os.PowerManager; -import android.util.Log; -import android.view.KeyEvent; -import android.view.OrientationEventListener; -import android.view.View; -import android.view.ViewGroup; - -import com.android.camera.app.CameraManager.CameraProxy; -import com.android.camera.app.AppController; -import com.android.camera.app.MediaSaver; -import com.android.camera.data.LocalData; -import com.android.camera.exif.ExifInterface; -import com.android.camera.module.ModuleController; -import com.android.camera.util.CameraUtil; -import com.android.camera.util.UsageStatistics; -import com.android.camera2.R; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.TimeZone; - -/** - * Activity to handle panorama capturing. - */ -public class WideAnglePanoramaModule - extends CameraModule - implements ModuleController, - WideAnglePanoramaController, - SurfaceTexture.OnFrameAvailableListener { - - public static final int DEFAULT_SWEEP_ANGLE = 160; - public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; - public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; - - private static final int MSG_LOW_RES_FINAL_MOSAIC_READY = 1; - private static final int MSG_GENERATE_FINAL_MOSAIC_ERROR = 2; - private static final int MSG_END_DIALOG_RESET_TO_PREVIEW = 3; - private static final int MSG_RESET_TO_PREVIEW = 4; - - private static final int SCREEN_DELAY = 2 * 60 * 1000; - - @SuppressWarnings("unused") - private static final String TAG = "CAM_WidePanoModule"; - private static final int PREVIEW_STOPPED = 0; - private static final int PREVIEW_ACTIVE = 1; - public static final int CAPTURE_STATE_VIEWFINDER = 0; - public static final int CAPTURE_STATE_MOSAIC = 1; - - // The unit of speed is degrees per frame. - private static final float PANNING_SPEED_THRESHOLD = 2.5f; - private static final boolean DEBUG = false; - - private ContentResolver mContentResolver; - private WideAnglePanoramaUI mUI; - - private MosaicPreviewRenderer mMosaicPreviewRenderer; - private final Object mRendererLock = new Object(); - private final Object mWaitObject = new Object(); - - private String mPreparePreviewString; - private String mDialogTitle; - private String mDialogOkString; - private String mDialogPanoramaFailedString; - private String mDialogWaitingPreviousString; - - private int mPreviewUIWidth; - private int mPreviewUIHeight; - private boolean mUsingFrontCamera; - private int mCameraPreviewWidth; - private int mCameraPreviewHeight; - private int mCameraState; - private int mCaptureState; - private PowerManager.WakeLock mPartialWakeLock; - private MosaicFrameProcessor mMosaicFrameProcessor; - private boolean mMosaicFrameProcessorInitialized; - private AsyncTask <Void, Void, Void> mWaitProcessorTask; - private long mTimeTaken; - private Handler mMainHandler; - private SurfaceTexture mCameraTexture; - private boolean mThreadRunning; - private boolean mCancelComputation; - private float mHorizontalViewAngle; - private float mVerticalViewAngle; - - // Prefer FOCUS_MODE_INFINITY to FOCUS_MODE_CONTINUOUS_VIDEO because of - // getting a better image quality by the former. - private final String mTargetFocusMode = Parameters.FOCUS_MODE_INFINITY; - - private PanoOrientationEventListener mOrientationEventListener; - // The value could be 0, 90, 180, 270 for the 4 different orientations measured in clockwise - // respectively. - private int mDeviceOrientation; - private int mDeviceOrientationAtCapture; - private int mCameraOrientation; - private int mOrientationCompensation; - - private SoundClips.Player mSoundPlayer; - - private Runnable mOnFrameAvailableRunnable; - - private CameraActivity mActivity; - private View mRootView; - private CameraProxy mCameraDevice; - private boolean mPaused; - - private LocationManager mLocationManager; - private ComboPreferences mPreferences; - private boolean mMosaicPreviewConfigured; - private boolean mPreviewFocused = true; - - /** - * Constructs a new Wide-Angle panorama module. - */ - public WideAnglePanoramaModule(AppController app) { - super(app); - } - - @Override - public void onPreviewUIReady() { - configMosaicPreview(); - } - - @Override - public void onPreviewUIDestroyed() { - - } - - private class MosaicJpeg { - public MosaicJpeg(byte[] data, int width, int height) { - this.data = data; - this.width = width; - this.height = height; - this.isValid = true; - } - - public MosaicJpeg() { - this.data = null; - this.width = 0; - this.height = 0; - this.isValid = false; - } - - public final byte[] data; - public final int width; - public final int height; - public final boolean isValid; - } - - private class PanoOrientationEventListener extends OrientationEventListener { - public PanoOrientationEventListener(Context context) { - super(context); - } - - @Override - public void onOrientationChanged(int orientation) { - // We keep the last known orientation. So if the user first orient - // the camera then point the camera to floor or sky, we still have - // the correct orientation. - if (orientation == ORIENTATION_UNKNOWN) return; - mDeviceOrientation = CameraUtil.roundOrientation(orientation, mDeviceOrientation); - // When the screen is unlocked, display rotation may change. Always - // calculate the up-to-date orientationCompensation. - int orientationCompensation = mDeviceOrientation - + CameraUtil.getDisplayRotation(mActivity) % 360; - if (mOrientationCompensation != orientationCompensation) { - mOrientationCompensation = orientationCompensation; - } - } - } - - @Override - public void init(AppController app, boolean isSecureCamera, boolean isCaptureIntent) { - mActivity = (CameraActivity) app.getAndroidContext(); - mRootView = app.getModuleLayoutRoot(); - - mCaptureState = CAPTURE_STATE_VIEWFINDER; - mUI = new WideAnglePanoramaUI(mActivity, this, (ViewGroup) mRootView); - mUI.setCaptureProgressOnDirectionChangeListener( - new PanoProgressBar.OnDirectionChangeListener() { - @Override - public void onDirectionChange(int direction) { - if (mCaptureState == CAPTURE_STATE_MOSAIC) { - mUI.showDirectionIndicators(direction); - } - } - }); - - mContentResolver = mActivity.getContentResolver(); - // This runs in UI thread. - mOnFrameAvailableRunnable = new Runnable() { - @Override - public void run() { - // Frames might still be available after the activity is paused. - // If we call onFrameAvailable after pausing, the GL thread will crash. - if (mPaused) return; - - MosaicPreviewRenderer renderer = null; - synchronized (mRendererLock) { - if (mMosaicPreviewRenderer == null) { - return; - } - renderer = mMosaicPreviewRenderer; - } - if (mRootView.getVisibility() != View.VISIBLE) { - renderer.showPreviewFrameSync(); - mRootView.setVisibility(View.VISIBLE); - } else { - if (mCaptureState == CAPTURE_STATE_VIEWFINDER) { - renderer.showPreviewFrame(); - } else { - renderer.alignFrameSync(); - mMosaicFrameProcessor.processFrame(); - } - } - } - }; - - PowerManager pm = (PowerManager) mActivity.getSystemService(Context.POWER_SERVICE); - mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Panorama"); - - mOrientationEventListener = new PanoOrientationEventListener(mActivity); - - mMosaicFrameProcessor = MosaicFrameProcessor.getInstance(); - - Resources appRes = mActivity.getResources(); - mPreparePreviewString = appRes.getString(R.string.pano_dialog_prepare_preview); - mDialogTitle = appRes.getString(R.string.pano_dialog_title); - mDialogOkString = appRes.getString(R.string.dialog_ok); - mDialogPanoramaFailedString = appRes.getString(R.string.pano_dialog_panorama_failed); - mDialogWaitingPreviousString = appRes.getString(R.string.pano_dialog_waiting_previous); - - mPreferences = new ComboPreferences(mActivity); - mLocationManager = mActivity.getLocationManager(); - - mMainHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_LOW_RES_FINAL_MOSAIC_READY: - onBackgroundThreadFinished(); - showFinalMosaic((Bitmap) msg.obj); - saveHighResMosaic(); - break; - case MSG_GENERATE_FINAL_MOSAIC_ERROR: - onBackgroundThreadFinished(); - if (mPaused) { - resetToPreviewIfPossible(); - } else { - mUI.showAlertDialog( - mDialogTitle, mDialogPanoramaFailedString, - mDialogOkString, new Runnable() { - @Override - public void run() { - resetToPreviewIfPossible(); - } - }); - } - clearMosaicFrameProcessorIfNeeded(); - break; - case MSG_END_DIALOG_RESET_TO_PREVIEW: - onBackgroundThreadFinished(); - resetToPreviewIfPossible(); - clearMosaicFrameProcessorIfNeeded(); - break; - case MSG_RESET_TO_PREVIEW: - resetToPreviewIfPossible(); - break; - } - } - }; - } - - @Override - public void onPreviewFocusChanged(boolean previewFocused) { - mPreviewFocused = previewFocused; - mUI.onPreviewFocusChanged(previewFocused); - } - - @Override - public boolean arePreviewControlsVisible() { - return mUI.arePreviewControlsVisible(); - } - - /** - * Opens camera and sets the parameters. - * - * @return Whether the camera was opened successfully. - */ - private boolean setupCamera() { - if (!openCamera()) { - return false; - } - Parameters parameters = mCameraDevice.getParameters(); - setupCaptureParams(parameters); - configureCamera(parameters); - return true; - } - - private void releaseCamera() { - if (mCameraDevice != null) { - CameraHolder.instance().release(); - mCameraDevice = null; - mCameraState = PREVIEW_STOPPED; - } - } - - /** - * Opens the camera device. The back camera has priority over the front - * one. - * - * @return Whether the camera was opened successfully. - */ - private boolean openCamera() { - int cameraId = CameraHolder.instance().getBackCameraId(); - // If there is no back camera, use the first camera. Camera id starts - // from 0. Currently if a camera is not back facing, it is front facing. - // This is also forward compatible if we have a new facing other than - // back or front in the future. - if (cameraId == -1) cameraId = 0; - mCameraDevice = CameraUtil.openCamera(mActivity, cameraId, - mMainHandler, mActivity.getCameraOpenErrorCallback()); - if (mCameraDevice == null) { - return false; - } - mCameraOrientation = CameraUtil.getCameraOrientation(cameraId); - if (cameraId == CameraHolder.instance().getFrontCameraId()) mUsingFrontCamera = true; - return true; - } - - private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, - boolean needSmaller) { - int pixelsDiff = DEFAULT_CAPTURE_PIXELS; - boolean hasFound = false; - for (Size size : supportedSizes) { - int h = size.height; - int w = size.width; - // we only want 4:3 format. - int d = DEFAULT_CAPTURE_PIXELS - h * w; - if (needSmaller && d < 0) { // no bigger preview than 960x720. - continue; - } - if (need4To3 && (h * 4 != w * 3)) { - continue; - } - d = Math.abs(d); - if (d < pixelsDiff) { - mCameraPreviewWidth = w; - mCameraPreviewHeight = h; - pixelsDiff = d; - hasFound = true; - } - } - return hasFound; - } - - private void setupCaptureParams(Parameters parameters) { - List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); - if (!findBestPreviewSize(supportedSizes, true, true)) { - Log.w(TAG, "No 4:3 ratio preview size supported."); - if (!findBestPreviewSize(supportedSizes, false, true)) { - Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); - findBestPreviewSize(supportedSizes, false, false); - } - } - Log.d(TAG, "camera preview h = " - + mCameraPreviewHeight + " , w = " + mCameraPreviewWidth); - parameters.setPreviewSize(mCameraPreviewWidth, mCameraPreviewHeight); - - List<int[]> frameRates = parameters.getSupportedPreviewFpsRange(); - int last = frameRates.size() - 1; - int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX]; - int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX]; - parameters.setPreviewFpsRange(minFps, maxFps); - Log.d(TAG, "preview fps: " + minFps + ", " + maxFps); - - List<String> supportedFocusModes = parameters.getSupportedFocusModes(); - if (supportedFocusModes.indexOf(mTargetFocusMode) >= 0) { - parameters.setFocusMode(mTargetFocusMode); - } else { - // Use the default focus mode and log a message - Log.w(TAG, "Cannot set the focus mode to " + mTargetFocusMode + - " becuase the mode is not supported."); - } - - parameters.set(CameraUtil.RECORDING_HINT, CameraUtil.FALSE); - - mHorizontalViewAngle = parameters.getHorizontalViewAngle(); - mVerticalViewAngle = parameters.getVerticalViewAngle(); - } - - public int getPreviewBufSize() { - PixelFormat pixelInfo = new PixelFormat(); - PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo); - // TODO: remove this extra 32 byte after the driver bug is fixed. - return (mCameraPreviewWidth * mCameraPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32; - } - - private void configureCamera(Parameters parameters) { - mCameraDevice.setParameters(parameters); - } - - /** - * Configures the preview renderer according to the dimension defined by - * {@code mPreviewUIWidth} and {@code mPreviewUIHeight}. - * Will stop the camera preview first. - */ - private void configMosaicPreview() { - if (mPreviewUIWidth == 0 || mPreviewUIHeight == 0 - || mUI.getSurfaceTexture() == null) { - return; - } - - stopCameraPreview(); - synchronized (mRendererLock) { - if (mMosaicPreviewRenderer != null) { - mMosaicPreviewRenderer.release(); - } - mMosaicPreviewRenderer = null; - } - final boolean isLandscape = - (mActivity.getResources().getConfiguration().orientation == - Configuration.ORIENTATION_LANDSCAPE); - mUI.flipPreviewIfNeeded(); - MosaicPreviewRenderer renderer = new MosaicPreviewRenderer( - mUI.getSurfaceTexture(), - mPreviewUIWidth, mPreviewUIHeight, isLandscape); - synchronized (mRendererLock) { - mMosaicPreviewRenderer = renderer; - mCameraTexture = mMosaicPreviewRenderer.getInputSurfaceTexture(); - - if (!mPaused && !mThreadRunning && mWaitProcessorTask == null) { - mMainHandler.sendEmptyMessage(MSG_RESET_TO_PREVIEW); - } - mRendererLock.notifyAll(); - } - mMosaicPreviewConfigured = true; - resetToPreviewIfPossible(); - } - - /** - * Receives the layout change event from the preview area. So we can - * initialize the mosaic preview renderer. - */ - @Override - public void onPreviewUILayoutChange(int l, int t, int r, int b) { - Log.d(TAG, "layout change: " + (r - l) + "/" + (b - t)); - mPreviewUIWidth = r - l; - mPreviewUIHeight = b - t; - configMosaicPreview(); - } - - @Override - public void onFrameAvailable(SurfaceTexture surface) { - /* This function may be called by some random thread, - * so let's be safe and jump back to ui thread. - * No OpenGL calls can be done here. */ - mActivity.runOnUiThread(mOnFrameAvailableRunnable); - } - - public void startCapture() { - // Reset values so we can do this again. - mCancelComputation = false; - mTimeTaken = System.currentTimeMillis(); - mActivity.setSwipingEnabled(false); - mCaptureState = CAPTURE_STATE_MOSAIC; - mUI.onStartCapture(); - - mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() { - @Override - public void onProgress(boolean isFinished, float panningRateX, float panningRateY, - float progressX, float progressY) { - float accumulatedHorizontalAngle = progressX * mHorizontalViewAngle; - float accumulatedVerticalAngle = progressY * mVerticalViewAngle; - if (isFinished - || (Math.abs(accumulatedHorizontalAngle) >= DEFAULT_SWEEP_ANGLE) - || (Math.abs(accumulatedVerticalAngle) >= DEFAULT_SWEEP_ANGLE)) { - stopCapture(false); - } else { - float panningRateXInDegree = panningRateX * mHorizontalViewAngle; - float panningRateYInDegree = panningRateY * mVerticalViewAngle; - mUI.updateCaptureProgress(panningRateXInDegree, panningRateYInDegree, - accumulatedHorizontalAngle, accumulatedVerticalAngle, - PANNING_SPEED_THRESHOLD); - } - } - }); - - mUI.resetCaptureProgress(); - // TODO: calculate the indicator width according to different devices to reflect the actual - // angle of view of the camera device. - mUI.setMaxCaptureProgress(DEFAULT_SWEEP_ANGLE); - mUI.showCaptureProgress(); - mDeviceOrientationAtCapture = mDeviceOrientation; - mActivity.enableKeepScreenOn(true); - // TODO: mActivity.getOrientationManager().lockOrientation(); - mActivity.lockOrientation(); - int degrees = CameraUtil.getDisplayRotation(mActivity); - int cameraId = CameraHolder.instance().getBackCameraId(); - int orientation = CameraUtil.getDisplayOrientation(degrees, cameraId); - mUI.setProgressOrientation(orientation); - } - - private void stopCapture(boolean aborted) { - mCaptureState = CAPTURE_STATE_VIEWFINDER; - mUI.onStopCapture(); - - mMosaicFrameProcessor.setProgressListener(null); - stopCameraPreview(); - - mCameraTexture.setOnFrameAvailableListener(null); - - if (!aborted && !mThreadRunning) { - mUI.showWaitingDialog(mPreparePreviewString); - // Hide shutter button, shutter icon, etc when waiting for - // panorama to stitch - mUI.hideUI(); - runBackgroundThread(new Thread() { - @Override - public void run() { - MosaicJpeg jpeg = generateFinalMosaic(false); - - if (jpeg != null && jpeg.isValid) { - Bitmap bitmap = null; - bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length); - mMainHandler.sendMessage(mMainHandler.obtainMessage( - MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap)); - } else { - mMainHandler.sendMessage(mMainHandler.obtainMessage( - MSG_END_DIALOG_RESET_TO_PREVIEW)); - } - } - }); - } - mActivity.enableKeepScreenOn(false); - } - - @Override - public void onShutterButtonClick() { - // If mCameraTexture == null then GL setup is not finished yet. - // No buttons can be pressed. - if (mPaused || mThreadRunning || mCameraTexture == null) { - return; - } - // Since this button will stay on the screen when capturing, we need to check the state - // right now. - switch (mCaptureState) { - case CAPTURE_STATE_VIEWFINDER: - final long storageSpaceBytes = mActivity.getStorageSpaceBytes(); - if(storageSpaceBytes <= Storage.LOW_STORAGE_THRESHOLD_BYTES) { - Log.w(TAG, "Low storage warning: " + storageSpaceBytes); - return; - } - mSoundPlayer.play(SoundClips.START_VIDEO_RECORDING); - startCapture(); - break; - case CAPTURE_STATE_MOSAIC: - mSoundPlayer.play(SoundClips.STOP_VIDEO_RECORDING); - stopCapture(false); - break; - default: - Log.w(TAG, "Unknown capture state: " + mCaptureState); - break; - } - } - - public void reportProgress() { - mUI.resetSavingProgress(); - Thread t = new Thread() { - @Override - public void run() { - while (mThreadRunning) { - final int progress = mMosaicFrameProcessor.reportProgress( - true, mCancelComputation); - - try { - synchronized (mWaitObject) { - mWaitObject.wait(50); - } - } catch (InterruptedException e) { - throw new RuntimeException("Panorama reportProgress failed", e); - } - // Update the progress bar - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mUI.updateSavingProgress(progress); - } - }); - } - } - }; - t.start(); - } - - private int getCaptureOrientation() { - // The panorama image returned from the library is oriented based on the - // natural orientation of a camera. We need to set an orientation for the image - // in its EXIF header, so the image can be displayed correctly. - // The orientation is calculated from compensating the - // device orientation at capture and the camera orientation respective to - // the natural orientation of the device. - int orientation; - if (mUsingFrontCamera) { - // mCameraOrientation is negative with respect to the front facing camera. - // See document of android.hardware.Camera.Parameters.setRotation. - orientation = (mDeviceOrientationAtCapture - mCameraOrientation + 360) % 360; - } else { - orientation = (mDeviceOrientationAtCapture + mCameraOrientation) % 360; - } - return orientation; - } - - /** The orientation of the camera image. The value is the angle that the camera - * image needs to be rotated clockwise so it shows correctly on the display - * in its natural orientation. It should be 0, 90, 180, or 270.*/ - @Override - public int getCameraOrientation() { - return mCameraOrientation; - } - - public void saveHighResMosaic() { - runBackgroundThread(new Thread() { - @Override - public void run() { - mPartialWakeLock.acquire(); - MosaicJpeg jpeg; - try { - jpeg = generateFinalMosaic(true); - } finally { - mPartialWakeLock.release(); - } - - if (jpeg == null) { // Cancelled by user. - mMainHandler.sendEmptyMessage(MSG_END_DIALOG_RESET_TO_PREVIEW); - } else if (!jpeg.isValid) { // Error when generating mosaic. - mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR); - } else { - int orientation = getCaptureOrientation(); - final Uri uri = savePanorama(jpeg.data, jpeg.width, jpeg.height, orientation); - if (uri != null) { - mActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mActivity.notifyNewMedia(uri); - } - }); - } - mMainHandler.sendMessage( - mMainHandler.obtainMessage(MSG_END_DIALOG_RESET_TO_PREVIEW)); - } - } - }); - reportProgress(); - } - - private void runBackgroundThread(Thread thread) { - mThreadRunning = true; - thread.start(); - } - - private void onBackgroundThreadFinished() { - mThreadRunning = false; - mUI.dismissAllDialogs(); - } - - private void cancelHighResComputation() { - mCancelComputation = true; - synchronized (mWaitObject) { - mWaitObject.notify(); - } - } - - // This function will be called upon the first camera frame is available. - private void reset() { - mCaptureState = CAPTURE_STATE_VIEWFINDER; - - mActivity.unlockOrientation(); - mUI.reset(); - mActivity.setSwipingEnabled(true); - // Orientation change will trigger onLayoutChange->configMosaicPreview-> - // resetToPreview. Do not show the capture UI in film strip. - if (mPreviewFocused) { - mUI.showPreviewUI(); - } - mMosaicFrameProcessor.reset(); - } - - private void resetToPreviewIfPossible() { - reset(); - if (!mMosaicFrameProcessorInitialized - || mUI.getSurfaceTexture() == null - || !mMosaicPreviewConfigured) { - return; - } - if (!mPaused) { - startCameraPreview(); - } - } - - private void showFinalMosaic(Bitmap bitmap) { - mUI.showFinalMosaic(bitmap, getCaptureOrientation()); - } - - private Uri savePanorama(byte[] jpegData, int width, int height, int orientation) { - if (jpegData != null) { - String filename = PanoUtil.createName( - mActivity.getResources().getString(R.string.pano_file_name_format), mTimeTaken); - String filepath = Storage.generateFilepath(filename); - - UsageStatistics.onEvent(UsageStatistics.COMPONENT_PANORAMA, - UsageStatistics.ACTION_CAPTURE_DONE, null, 0, - UsageStatistics.hashFileName(filename + ".jpg")); - - Location loc = mLocationManager.getCurrentLocation(); - ExifInterface exif = new ExifInterface(); - try { - exif.readExif(jpegData); - exif.addGpsDateTimeStampTag(mTimeTaken); - exif.addDateTimeStampTag(ExifInterface.TAG_DATE_TIME, mTimeTaken, - TimeZone.getDefault()); - exif.setTag(exif.buildTag(ExifInterface.TAG_ORIENTATION, - ExifInterface.getOrientationValueForRotation(orientation))); - writeLocation(loc, exif); - exif.writeExif(jpegData, filepath); - } catch (IOException e) { - Log.e(TAG, "Cannot set exif for " + filepath, e); - Storage.writeFile(filepath, jpegData); - } - int jpegLength = (int) (new File(filepath).length()); - return Storage.addImage(mContentResolver, filename, mTimeTaken, loc, orientation, - jpegLength, filepath, width, height, LocalData.MIME_TYPE_JPEG); - } - return null; - } - - private static void writeLocation(Location location, ExifInterface exif) { - if (location == null) { - return; - } - exif.addGpsTags(location.getLatitude(), location.getLongitude()); - exif.setTag(exif.buildTag(ExifInterface.TAG_GPS_PROCESSING_METHOD, location.getProvider())); - } - - private void clearMosaicFrameProcessorIfNeeded() { - if (!mPaused || mThreadRunning) return; - // Only clear the processor if it is initialized by this activity - // instance. Other activity instances may be using it. - if (mMosaicFrameProcessorInitialized) { - mMosaicFrameProcessor.clear(); - mMosaicFrameProcessorInitialized = false; - } - } - - private void initMosaicFrameProcessorIfNeeded() { - if (mPaused || mThreadRunning) { - return; - } - - mMosaicFrameProcessor.initialize( - mCameraPreviewWidth, mCameraPreviewHeight, getPreviewBufSize()); - mMosaicFrameProcessorInitialized = true; - } - - @Override - public void resume() { - mPaused = false; - mOrientationEventListener.enable(); - - mCaptureState = CAPTURE_STATE_VIEWFINDER; - - if (!setupCamera()) { - Log.e(TAG, "Failed to open camera, aborting"); - return; - } - - // Set up sound playback for shutter button - mSoundPlayer = SoundClips.getPlayer(mActivity); - - // Check if another panorama instance is using the mosaic frame processor. - mUI.dismissAllDialogs(); - if (!mThreadRunning && mMosaicFrameProcessor.isMosaicMemoryAllocated()) { - mUI.showWaitingDialog(mDialogWaitingPreviousString); - // If stitching is still going on, make sure switcher and shutter button - // are not showing - mUI.hideUI(); - mWaitProcessorTask = new WaitProcessorTask().execute(); - } else { - // Camera must be initialized before MosaicFrameProcessor is - // initialized. The preview size has to be decided by camera device. - initMosaicFrameProcessorIfNeeded(); - Point size = mUI.getPreviewAreaSize(); - mPreviewUIWidth = size.x; - mPreviewUIHeight = size.y; - configMosaicPreview(); - mActivity.updateStorageSpaceAndHint(); - } - - // Initialize location service. - boolean recordLocation = RecordLocationPreference.get(mPreferences, - mContentResolver); - mLocationManager.recordLocation(recordLocation); - UsageStatistics.onContentViewChanged( - UsageStatistics.COMPONENT_CAMERA, "PanoramaModule"); - } - - @Override - public void pause() { - mPaused = true; - if (mLocationManager != null) mLocationManager.recordLocation(false); - mOrientationEventListener.disable(); - if (mCameraDevice == null) { - // Camera open failed. Nothing should be done here. - return; - } - // Stop the capturing first. - if (mCaptureState == CAPTURE_STATE_MOSAIC) { - stopCapture(true); - reset(); - } - mUI.showPreviewCover(); - releaseCamera(); - synchronized (mRendererLock) { - mCameraTexture = null; - - // The preview renderer might not have a chance to be initialized - // before onPause(). - if (mMosaicPreviewRenderer != null) { - mMosaicPreviewRenderer.release(); - mMosaicPreviewRenderer = null; - } - } - - clearMosaicFrameProcessorIfNeeded(); - if (mWaitProcessorTask != null) { - mWaitProcessorTask.cancel(true); - mWaitProcessorTask = null; - } - mActivity.enableKeepScreenOn(false); - if (mSoundPlayer != null) { - mSoundPlayer.release(); - mSoundPlayer = null; - } - System.gc(); - } - - @Override - public void destroy() { - // TODO: implement this. - } - - @Override - public void onPreviewSizeChanged(int width, int height) { - // TODO: implement this. - } - - @Override - public void onLayoutOrientationChanged(boolean isLandscape) { - mUI.onConfigurationChanged(isLandscape, mThreadRunning); - } - - @Override - public void onOrientationChanged(int orientation) { - } - - @Override - public void onCameraAvailable(CameraProxy cameraProxy) { - // TODO: implement this. - } - - /** - * Generate the final mosaic image. - * - * @param highRes flag to indicate whether we want to get a high-res version. - * @return a MosaicJpeg with its isValid flag set to true if successful; null if the generation - * process is cancelled; and a MosaicJpeg with its isValid flag set to false if there - * is an error in generating the final mosaic. - */ - public MosaicJpeg generateFinalMosaic(boolean highRes) { - int mosaicReturnCode = mMosaicFrameProcessor.createMosaic(highRes); - if (mosaicReturnCode == Mosaic.MOSAIC_RET_CANCELLED) { - return null; - } else if (mosaicReturnCode == Mosaic.MOSAIC_RET_ERROR) { - return new MosaicJpeg(); - } - - byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21(); - if (imageData == null) { - Log.e(TAG, "getFinalMosaicNV21() returned null."); - return new MosaicJpeg(); - } - - int len = imageData.length - 8; - int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16) - + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF); - int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16) - + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF); - Log.d(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height); - - if (width <= 0 || height <= 0) { - // TODO: pop up an error message indicating that the final result is not generated. - Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " + - height); - return new MosaicJpeg(); - } - - YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out); - try { - out.close(); - } catch (Exception e) { - Log.e(TAG, "Exception in storing final mosaic", e); - return new MosaicJpeg(); - } - return new MosaicJpeg(out.toByteArray(), width, height); - } - - private void startCameraPreview() { - if (mCameraDevice == null) { - // Camera open failed. Return. - return; - } - - if (mUI.getSurfaceTexture() == null) { - // UI is not ready. - return; - } - - // This works around a driver issue. startPreview may fail if - // stopPreview/setPreviewTexture/startPreview are called several times - // in a row. mCameraTexture can be null after pressing home during - // mosaic generation and coming back. Preview will be started later in - // onLayoutChange->configMosaicPreview. This also reduces the latency. - synchronized (mRendererLock) { - if (mCameraTexture == null) return; - - // If we're previewing already, stop the preview first (this will - // blank the screen). - if (mCameraState != PREVIEW_STOPPED) stopCameraPreview(); - - // Set the display orientation to 0, so that the underlying mosaic - // library can always get undistorted mCameraPreviewWidth x mCameraPreviewHeight - // image data from SurfaceTexture. - mCameraDevice.setDisplayOrientation(0); - - mCameraTexture.setOnFrameAvailableListener(this); - mCameraDevice.setPreviewTexture(mCameraTexture); - } - mCameraDevice.startPreview(); - mCameraState = PREVIEW_ACTIVE; - } - - private void stopCameraPreview() { - if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { - mCameraDevice.stopPreview(); - } - mCameraState = PREVIEW_STOPPED; - } - - @Override - public boolean onBackPressed() { - // If panorama is generating low res or high res mosaic, ignore back - // key. So the activity will not be destroyed. - if (mThreadRunning) return true; - return false; - } - - private class WaitProcessorTask extends AsyncTask<Void, Void, Void> { - @Override - protected Void doInBackground(Void... params) { - synchronized (mMosaicFrameProcessor) { - while (!isCancelled() && mMosaicFrameProcessor.isMosaicMemoryAllocated()) { - try { - mMosaicFrameProcessor.wait(); - } catch (Exception e) { - // ignore - } - } - } - mActivity.updateStorageSpace(); - return null; - } - - @Override - protected void onPostExecute(Void result) { - mWaitProcessorTask = null; - mUI.dismissAllDialogs(); - // TODO (shkong): mGLRootView.setVisibility(View.VISIBLE); - initMosaicFrameProcessorIfNeeded(); - Point size = mUI.getPreviewAreaSize(); - mPreviewUIWidth = size.x; - mPreviewUIHeight = size.y; - configMosaicPreview(); - resetToPreviewIfPossible(); - mActivity.updateStorageHint(mActivity.getStorageSpaceBytes()); - } - } - - @Override - public void cancelHighResStitching() { - if (mPaused || mCameraTexture == null) return; - cancelHighResComputation(); - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - return false; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - return false; - } - - @Override - public void onSingleTapUp(View view, int x, int y) { - } - - @Override - public void onMediaSaverAvailable(MediaSaver s) { - // do nothing. - } -} diff --git a/src/com/android/camera/WideAnglePanoramaUI.java b/src/com/android/camera/WideAnglePanoramaUI.java deleted file mode 100644 index 58a1a3231..000000000 --- a/src/com/android/camera/WideAnglePanoramaUI.java +++ /dev/null @@ -1,495 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.camera; - -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.SurfaceTexture; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.TextureView; -import android.view.View; -import android.view.ViewGroup; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.android.camera.ui.CameraControls; -import com.android.camera.util.CameraUtil; -import com.android.camera2.R; - -/** - * The UI of {@link WideAnglePanoramaModule}. - */ -public class WideAnglePanoramaUI implements - TextureView.SurfaceTextureListener, - ShutterButton.OnShutterButtonListener, - View.OnLayoutChangeListener { - - @SuppressWarnings("unused") - private static final String TAG = "CAM_WidePanoramaUI"; - - private CameraActivity mActivity; - private WideAnglePanoramaController mController; - - private ViewGroup mRootView; - private FrameLayout mCaptureLayout; - private View mReviewLayout; - private ImageView mReview; - private View mPreviewBorder; - private View mLeftIndicator; - private View mRightIndicator; - private View mCaptureIndicator; - private PanoProgressBar mCaptureProgressBar; - private PanoProgressBar mSavingProgressBar; - private TextView mTooFastPrompt; - private View mPreviewLayout; - private ViewGroup mReviewControl; - private TextureView mTextureView; - private ShutterButton mShutterButton; - private CameraControls mCameraControls; - - private Matrix mProgressDirectionMatrix = new Matrix(); - private float[] mProgressAngle = new float[2]; - - private DialogHelper mDialogHelper; - - // Color definitions. - private int mIndicatorColor; - private int mIndicatorColorFast; - private int mReviewBackground; - private SurfaceTexture mSurfaceTexture; - private View mPreviewCover; - - /** Constructor. */ - public WideAnglePanoramaUI( - CameraActivity activity, - WideAnglePanoramaController controller, - ViewGroup root) { - mActivity = activity; - mController = controller; - mRootView = root; - - createContentView(); - } - - public void onStartCapture() { - mShutterButton.setImageResource(R.drawable.btn_shutter_recording); - mCaptureIndicator.setVisibility(View.VISIBLE); - showDirectionIndicators(PanoProgressBar.DIRECTION_NONE); - } - - public void showPreviewUI() { - mCaptureLayout.setVisibility(View.VISIBLE); - showUI(); - } - - public void onStopCapture() { - mCaptureIndicator.setVisibility(View.INVISIBLE); - hideTooFastIndication(); - hideDirectionIndicators(); - } - - public void hideUI() { - mCameraControls.setVisibility(View.INVISIBLE); - } - - public void showUI() { - mCameraControls.setVisibility(View.VISIBLE); - } - - public void onPreviewFocusChanged(boolean previewFocused) { - if (previewFocused) { - showUI(); - } else { - hideUI(); - } - } - - public boolean arePreviewControlsVisible() { - return (mCameraControls.getVisibility() == View.VISIBLE); - } - - public void setCaptureProgressOnDirectionChangeListener( - PanoProgressBar.OnDirectionChangeListener listener) { - mCaptureProgressBar.setOnDirectionChangeListener(listener); - } - - public void resetCaptureProgress() { - mCaptureProgressBar.reset(); - } - - public void setMaxCaptureProgress(int max) { - mCaptureProgressBar.setMaxProgress(max); - } - - public void showCaptureProgress() { - mCaptureProgressBar.setVisibility(View.VISIBLE); - } - - public void updateCaptureProgress( - float panningRateXInDegree, float panningRateYInDegree, - float progressHorizontalAngle, float progressVerticalAngle, - float maxPanningSpeed) { - - if ((Math.abs(panningRateXInDegree) > maxPanningSpeed) - || (Math.abs(panningRateYInDegree) > maxPanningSpeed)) { - showTooFastIndication(); - } else { - hideTooFastIndication(); - } - - // progressHorizontalAngle and progressVerticalAngle are relative to the - // camera. Convert them to UI direction. - mProgressAngle[0] = progressHorizontalAngle; - mProgressAngle[1] = progressVerticalAngle; - mProgressDirectionMatrix.mapPoints(mProgressAngle); - - int angleInMajorDirection = - (Math.abs(mProgressAngle[0]) > Math.abs(mProgressAngle[1])) - ? (int) mProgressAngle[0] - : (int) mProgressAngle[1]; - mCaptureProgressBar.setProgress((angleInMajorDirection)); - } - - public void setProgressOrientation(int orientation) { - mProgressDirectionMatrix.reset(); - mProgressDirectionMatrix.postRotate(orientation); - } - - public void showDirectionIndicators(int direction) { - switch (direction) { - case PanoProgressBar.DIRECTION_NONE: - mLeftIndicator.setVisibility(View.VISIBLE); - mRightIndicator.setVisibility(View.VISIBLE); - break; - case PanoProgressBar.DIRECTION_LEFT: - mLeftIndicator.setVisibility(View.VISIBLE); - mRightIndicator.setVisibility(View.INVISIBLE); - break; - case PanoProgressBar.DIRECTION_RIGHT: - mLeftIndicator.setVisibility(View.INVISIBLE); - mRightIndicator.setVisibility(View.VISIBLE); - break; - } - } - - public SurfaceTexture getSurfaceTexture() { - return mSurfaceTexture; - } - - @Override - public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) { - mSurfaceTexture = surfaceTexture; - mController.onPreviewUIReady(); - } - - @Override - public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) { - - } - - @Override - public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { - mController.onPreviewUIDestroyed(); - mSurfaceTexture = null; - Log.d(TAG, "surfaceTexture is destroyed"); - return true; - } - - @Override - public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { - // Make sure preview cover is hidden if preview data is available. - if (mPreviewCover.getVisibility() != View.GONE) { - mPreviewCover.setVisibility(View.GONE); - } - } - - private void hideDirectionIndicators() { - mLeftIndicator.setVisibility(View.INVISIBLE); - mRightIndicator.setVisibility(View.INVISIBLE); - } - - public Point getPreviewAreaSize() { - return new Point( - mTextureView.getWidth(), mTextureView.getHeight()); - } - - public void reset() { - mShutterButton.setImageResource(R.drawable.btn_new_shutter); - mReviewLayout.setVisibility(View.GONE); - mCaptureProgressBar.setVisibility(View.INVISIBLE); - } - - public void showFinalMosaic(Bitmap bitmap, int orientation) { - if (bitmap != null && orientation != 0) { - Matrix rotateMatrix = new Matrix(); - rotateMatrix.setRotate(orientation); - bitmap = Bitmap.createBitmap( - bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), - rotateMatrix, false); - } - - mReview.setImageBitmap(bitmap); - mCaptureLayout.setVisibility(View.GONE); - mReviewLayout.setVisibility(View.VISIBLE); - } - - public void onConfigurationChanged( - boolean isLandscape, boolean threadRunning) { - Drawable lowResReview = null; - if (threadRunning) lowResReview = mReview.getDrawable(); - - // Change layout in response to configuration change - LayoutInflater inflater = (LayoutInflater) - mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - mReviewControl.removeAllViews(); - inflater.inflate(R.layout.pano_review_control, mReviewControl, true); - - mRootView.bringChildToFront(mCameraControls); - setViews(mActivity.getResources()); - if (threadRunning) { - mReview.setImageDrawable(lowResReview); - mCaptureLayout.setVisibility(View.GONE); - mReviewLayout.setVisibility(View.VISIBLE); - } - } - - public void resetSavingProgress() { - mSavingProgressBar.reset(); - mSavingProgressBar.setRightIncreasing(true); - } - - public void updateSavingProgress(int progress) { - mSavingProgressBar.setProgress(progress); - } - - @Override - public void onShutterButtonFocus(boolean pressed) { - // Do nothing. - } - - @Override - public void onShutterButtonClick() { - mController.onShutterButtonClick(); - } - - @Override - public void onLayoutChange( - View v, int l, int t, int r, int b, - int oldl, int oldt, int oldr, int oldb) { - mController.onPreviewUILayoutChange(l, t, r, b); - } - - public void showAlertDialog( - String title, String failedString, - String OKString, Runnable runnable) { - mDialogHelper.showAlertDialog(title, failedString, OKString, runnable); - } - - public void showWaitingDialog(String title) { - mDialogHelper.showWaitingDialog(title); - } - - public void dismissAllDialogs() { - mDialogHelper.dismissAll(); - } - - private void createContentView() { - LayoutInflater inflator = (LayoutInflater) mActivity - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflator.inflate(R.layout.panorama_module, mRootView, true); - - Resources appRes = mActivity.getResources(); - mIndicatorColor = appRes.getColor(R.color.pano_progress_indication); - mReviewBackground = appRes.getColor(R.color.review_background); - mIndicatorColorFast = appRes.getColor(R.color.pano_progress_indication_fast); - - mPreviewCover = mRootView.findViewById(R.id.preview_cover); - mPreviewLayout = mRootView.findViewById(R.id.pano_preview_layout); - mReviewControl = (ViewGroup) mRootView.findViewById(R.id.pano_review_control); - mReviewLayout = mRootView.findViewById(R.id.pano_review_layout); - mReview = (ImageView) mRootView.findViewById(R.id.pano_reviewarea); - mCaptureLayout = (FrameLayout) mRootView.findViewById(R.id.panorama_capture_layout); - mCaptureProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_pan_progress_bar); - mCaptureProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); - mCaptureProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_done)); - mCaptureProgressBar.setIndicatorColor(mIndicatorColor); - mCaptureProgressBar.setIndicatorWidth(20); - - mPreviewBorder = mCaptureLayout.findViewById(R.id.pano_preview_area_border); - - mLeftIndicator = mRootView.findViewById(R.id.pano_pan_left_indicator); - mRightIndicator = mRootView.findViewById(R.id.pano_pan_right_indicator); - mLeftIndicator.setEnabled(false); - mRightIndicator.setEnabled(false); - mTooFastPrompt = (TextView) mRootView.findViewById(R.id.pano_capture_too_fast_textview); - mCaptureIndicator = mRootView.findViewById(R.id.pano_capture_indicator); - - mShutterButton = (ShutterButton) mRootView.findViewById(R.id.shutter_button); - mShutterButton.setImageResource(R.drawable.btn_new_shutter); - mShutterButton.setOnShutterButtonListener(this); - // Hide menu and indicators. - mRootView.findViewById(R.id.menu).setVisibility(View.GONE); - mRootView.findViewById(R.id.on_screen_indicators).setVisibility(View.GONE); - mReview.setBackgroundColor(mReviewBackground); - - mTextureView = (TextureView) mRootView.findViewById(R.id.pano_preview_textureview); - mTextureView.setSurfaceTextureListener(this); - mTextureView.addOnLayoutChangeListener(this); - mCameraControls = (CameraControls) mRootView.findViewById(R.id.camera_controls); - - mDialogHelper = new DialogHelper(); - setViews(appRes); - } - - private void setViews(Resources appRes) { - int weight = appRes.getInteger(R.integer.SRI_pano_layout_weight); - - LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) mPreviewLayout.getLayoutParams(); - lp.weight = weight; - mPreviewLayout.setLayoutParams(lp); - - lp = (LinearLayout.LayoutParams) mReview.getLayoutParams(); - lp.weight = weight; - mPreviewLayout.setLayoutParams(lp); - - mSavingProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_saving_progress_bar); - mSavingProgressBar.setIndicatorWidth(0); - mSavingProgressBar.setMaxProgress(100); - mSavingProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); - mSavingProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_indication)); - - View cancelButton = mRootView.findViewById(R.id.pano_review_cancel_button); - cancelButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View arg0) { - mController.cancelHighResStitching(); - } - }); - - - } - - private void showTooFastIndication() { - mTooFastPrompt.setVisibility(View.VISIBLE); - // The PreviewArea also contains the border for "too fast" indication. - mPreviewBorder.setVisibility(View.VISIBLE); - mCaptureProgressBar.setIndicatorColor(mIndicatorColorFast); - mLeftIndicator.setEnabled(true); - mRightIndicator.setEnabled(true); - } - - private void hideTooFastIndication() { - mTooFastPrompt.setVisibility(View.GONE); - mPreviewBorder.setVisibility(View.INVISIBLE); - mCaptureProgressBar.setIndicatorColor(mIndicatorColor); - mLeftIndicator.setEnabled(false); - mRightIndicator.setEnabled(false); - } - - public void flipPreviewIfNeeded() { - // Rotation needed to display image correctly clockwise - int cameraOrientation = mController.getCameraOrientation(); - // Display rotated counter-clockwise - int displayRotation = CameraUtil.getDisplayRotation(mActivity); - // Rotation needed to display image correctly on current display - int rotation = (cameraOrientation - displayRotation + 360) % 360; - if (rotation >= 180) { - mTextureView.setRotation(180); - } else { - mTextureView.setRotation(0); - } - } - - public void showPreviewCover() { - mPreviewCover.setVisibility(View.VISIBLE); - } - - private class DialogHelper { - private ProgressDialog mProgressDialog; - private AlertDialog mAlertDialog; - - DialogHelper() { - mProgressDialog = null; - mAlertDialog = null; - } - - public void dismissAll() { - if (mAlertDialog != null) { - mAlertDialog.dismiss(); - mAlertDialog = null; - } - if (mProgressDialog != null) { - mProgressDialog.dismiss(); - mProgressDialog = null; - } - } - - public void showAlertDialog( - CharSequence title, CharSequence message, - CharSequence buttonMessage, final Runnable buttonRunnable) { - dismissAll(); - mAlertDialog = (new AlertDialog.Builder(mActivity)) - .setTitle(title) - .setMessage(message) - .setNeutralButton(buttonMessage, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - buttonRunnable.run(); - } - }) - .show(); - } - - public void showWaitingDialog(CharSequence message) { - dismissAll(); - mProgressDialog = ProgressDialog.show(mActivity, null, message, true, false); - } - } - - private static class FlipBitmapDrawable extends BitmapDrawable { - - public FlipBitmapDrawable(Resources res, Bitmap bitmap) { - super(res, bitmap); - } - - @Override - public void draw(Canvas canvas) { - Rect bounds = getBounds(); - int cx = bounds.centerX(); - int cy = bounds.centerY(); - canvas.save(Canvas.MATRIX_SAVE_FLAG); - canvas.rotate(180, cx, cy); - super.draw(canvas); - canvas.restore(); - } - } -} diff --git a/src/com/android/camera/module/ModulesInfo.java b/src/com/android/camera/module/ModulesInfo.java index b7a1ecce9..9fbd09525 100644 --- a/src/com/android/camera/module/ModulesInfo.java +++ b/src/com/android/camera/module/ModulesInfo.java @@ -20,9 +20,7 @@ import android.content.Context; import com.android.camera.PhotoModule; import com.android.camera.VideoModule; -import com.android.camera.WideAnglePanoramaModule; import com.android.camera.app.AppController; -import com.android.camera.app.CameraServices; import com.android.camera.app.ModuleManager; import com.android.camera.ui.ModeListView; import com.android.camera.util.GcamHelper; |