PanoramaActivity.java revision fbc5751416caa3a0d065ae15f56d1fb0253552c5
1bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen/*
2bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Copyright (C) 2011 The Android Open Source Project
3bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen *
4bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Licensed under the Apache License, Version 2.0 (the "License");
5bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * you may not use this file except in compliance with the License.
6bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * You may obtain a copy of the License at
7bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen *
8bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen *      http://www.apache.org/licenses/LICENSE-2.0
9bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen *
10bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Unless required by applicable law or agreed to in writing, software
11bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * distributed under the License is distributed on an "AS IS" BASIS,
12bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * See the License for the specific language governing permissions and
14bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * limitations under the License.
15bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen */
16bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
17bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenpackage com.android.camera.panorama;
18bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
19d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraDisabledException;
20d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraHardwareException;
21d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraHolder;
22d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.MenuHelper;
23d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.ModePicker;
24d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.R;
25d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Storage;
26d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Util;
27d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Li
28bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.app.Activity;
29bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.content.Context;
30142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.Bitmap;
31142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.BitmapFactory;
328a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.ImageFormat;
33bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.graphics.PixelFormat;
348a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.Rect;
3541a2e9735136f372de95652d0828600282c8e967mbansalimport android.graphics.SurfaceTexture;
368a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.YuvImage;
378a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.hardware.Camera;
3836839102e03107e3fb121197036365a58ec2686eAngus Kongimport android.hardware.Camera.Parameters;
3936839102e03107e3fb121197036365a58ec2686eAngus Kongimport android.hardware.Camera.Size;
40bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.Sensor;
41bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorEvent;
42bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorEventListener;
43bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorManager;
44bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.os.Bundle;
458a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.os.Handler;
46ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport android.os.Message;
47bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.util.Log;
48bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.View;
49bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.WindowManager;
5060fc534ec8f68d95a486984cb396a2da0e200518Angus Kongimport android.widget.Button;
51bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.widget.ImageView;
52fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kongimport android.widget.TextView;
53bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
54ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport java.io.ByteArrayOutputStream;
55bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport java.util.List;
56bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
57a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong/**
58a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong * Activity to handle panorama capturing.
59a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong */
6098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chenpublic class PanoramaActivity extends Activity implements
6141a2e9735136f372de95652d0828600282c8e967mbansal        ModePicker.OnModeChangeListener,
6236839102e03107e3fb121197036365a58ec2686eAngus Kong        SurfaceTexture.OnFrameAvailableListener,
6336839102e03107e3fb121197036365a58ec2686eAngus Kong        MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener {
64ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    public static final int DEFAULT_SWEEP_ANGLE = 160;
65bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL;
66bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720;
67bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
68ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private static final int MSG_FINAL_MOSAIC_READY = 1;
69142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private static final int MSG_RESET_TO_PREVIEW = 2;
7094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen
71ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private static final String TAG = "PanoramaActivity";
7298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_STOPPED = 0;
7398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_ACTIVE = 1;
7441a2e9735136f372de95652d0828600282c8e967mbansal    private static final int CAPTURE_VIEWFINDER = 0;
7541a2e9735136f372de95652d0828600282c8e967mbansal    private static final int CAPTURE_MOSAIC = 1;
7641a2e9735136f372de95652d0828600282c8e967mbansal
77a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    // Ratio of nanosecond to second
78a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private static final float NS2S = 1.0f / 1000000000.0f;
79142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
80142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mPausing;
81142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
82a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mPanoControlLayout;
83a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mCaptureLayout;
8460fc534ec8f68d95a486984cb396a2da0e200518Angus Kong    private Button mStopCaptureButton;
85a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mReviewLayout;
86bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private ImageView mReview;
87bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private CaptureView mCaptureView;
88eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    private MosaicRendererSurfaceView mRealTimeMosaicView;
89fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong    private TextView mTooFastPrompt;
90142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
91bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewWidth;
92bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewHeight;
938a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private Camera mCameraDevice;
9498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private int mCameraState;
9541a2e9735136f372de95652d0828600282c8e967mbansal    private int mCaptureState;
96bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private SensorManager mSensorManager;
97bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private Sensor mSensor;
98a72d73cbac59db43d413291e4db66763be08143arepo sync    private ModePicker mModePicker;
998a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private MosaicFrameProcessor mMosaicFrameProcessor;
1008a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private String mCurrentImagePath = null;
1018a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private long mTimeTaken;
102ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private Handler mMainHandler;
10341a2e9735136f372de95652d0828600282c8e967mbansal    private SurfaceTexture mSurface;
104142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mThreadRunning;
105142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
106bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
107bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public void onCreate(Bundle icicle) {
108bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onCreate(icicle);
109bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
110bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
111bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
112bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
113bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        createContentView();
114bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
115bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
116bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
117bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (mSensor == null) {
118bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
119bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
1208a2c41754655a3733175fce81fb7506ff7022959Angus Kong
121ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        mMainHandler = new Handler() {
122ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            @Override
123ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            public void handleMessage(Message msg) {
124ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                switch (msg.what) {
125ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                    case MSG_FINAL_MOSAIC_READY:
126142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        mThreadRunning = false;
127142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        showFinalMosaic((Bitmap) msg.obj);
128142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
129142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                    case MSG_RESET_TO_PREVIEW:
130142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        mThreadRunning = false;
131142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        resetToPreview();
132142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
133ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                }
134142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                clearMosaicFrameProcessorIfNeeded();
135ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            }
136ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        };
137bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
138bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
139bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCamera() {
140bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        openCamera();
141bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Parameters parameters = mCameraDevice.getParameters();
142bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setupCaptureParams(parameters);
143bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        configureCamera(parameters);
144bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
145bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
146ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private void releaseCamera() {
147ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        if (mCameraDevice != null) {
148142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mCameraDevice.setPreviewCallbackWithBuffer(null);
149ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            CameraHolder.instance().release();
150ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            mCameraDevice = null;
15198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraState = PREVIEW_STOPPED;
152ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        }
153ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    }
154ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong
155bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void openCamera() {
156bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        try {
157bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId());
158bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        } catch (CameraHardwareException e) {
159bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Util.showErrorAndFinish(this, R.string.cannot_connect_camera);
160bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            return;
161bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        } catch (CameraDisabledException e) {
162bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Util.showErrorAndFinish(this, R.string.camera_disabled);
163bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            return;
164bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
165bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
166bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
167bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3,
168bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            boolean needSmaller) {
169bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int pixelsDiff = DEFAULT_CAPTURE_PIXELS;
170bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        boolean hasFound = false;
1718a2c41754655a3733175fce81fb7506ff7022959Angus Kong        for (Size size : supportedSizes) {
172bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int h = size.height;
173bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int w = size.width;
174bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            // we only want 4:3 format.
175bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int d = DEFAULT_CAPTURE_PIXELS - h * w;
17694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            if (needSmaller && d < 0) { // no bigger preview than 960x720.
177bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
178bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
179bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (need4To3 && (h * 4 != w * 3)) {
180bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
181bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
182bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            d = Math.abs(d);
183bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (d < pixelsDiff) {
184bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewWidth = w;
185bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewHeight = h;
186bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                pixelsDiff = d;
187bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                hasFound = true;
188bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
189bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
190bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return hasFound;
191bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
192bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
193bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCaptureParams(Parameters parameters) {
194bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
195bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (!findBestPreviewSize(supportedSizes, true, true)) {
196bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Log.w(TAG, "No 4:3 ratio preview size supported.");
197bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (!findBestPreviewSize(supportedSizes, false, true)) {
198bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                Log.w(TAG, "Can't find a supported preview size smaller than 960x720.");
199bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                findBestPreviewSize(supportedSizes, false, false);
200bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
201bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
202bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth);
203bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewSize(mPreviewWidth, mPreviewHeight);
204bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
205bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<int[]> frameRates = parameters.getSupportedPreviewFpsRange();
206bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int last = frameRates.size() - 1;
207bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX];
208bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX];
209bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewFpsRange(minFps, maxFps);
210bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview fps: " + minFps + ", " + maxFps);
2113ab4f0912da83f7f5f8266a57a606d521c1649e3Wu-cheng Li
21293ad273a53e7d2975a67d7d1f8a157f845e41cf2Wu-cheng Li        parameters.setRecordingHint(false);
213bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
214bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
215bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public int getPreviewBufSize() {
216bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat pixelInfo = new PixelFormat();
217bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo);
218bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        // TODO: remove this extra 32 byte after the driver bug is fixed.
219bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32;
220bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
221bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
222bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void configureCamera(Parameters parameters) {
223bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCameraDevice.setParameters(parameters);
224bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
2254b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        int orientation = Util.getDisplayOrientation(Util.getDisplayRotation(this),
2264b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li                CameraHolder.instance().getBackCameraId());
2274b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        mCameraDevice.setDisplayOrientation(orientation);
228bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
229bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
230a72d73cbac59db43d413291e4db66763be08143arepo sync    private boolean switchToOtherMode(int mode) {
231a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        if (isFinishing()) {
23294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            return false;
233a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        }
234a72d73cbac59db43d413291e4db66763be08143arepo sync        MenuHelper.gotoMode(mode, this);
235a72d73cbac59db43d413291e4db66763be08143arepo sync        finish();
236a72d73cbac59db43d413291e4db66763be08143arepo sync        return true;
237a72d73cbac59db43d413291e4db66763be08143arepo sync    }
238a72d73cbac59db43d413291e4db66763be08143arepo sync
239a72d73cbac59db43d413291e4db66763be08143arepo sync    public boolean onModeChanged(int mode) {
240a72d73cbac59db43d413291e4db66763be08143arepo sync        if (mode != ModePicker.MODE_PANORAMA) {
241a72d73cbac59db43d413291e4db66763be08143arepo sync            return switchToOtherMode(mode);
242a72d73cbac59db43d413291e4db66763be08143arepo sync        } else {
243a72d73cbac59db43d413291e4db66763be08143arepo sync            return true;
244a72d73cbac59db43d413291e4db66763be08143arepo sync        }
245a72d73cbac59db43d413291e4db66763be08143arepo sync    }
246a72d73cbac59db43d413291e4db66763be08143arepo sync
24736839102e03107e3fb121197036365a58ec2686eAngus Kong    public void onMosaicSurfaceCreated(final SurfaceTexture surface) {
24836839102e03107e3fb121197036365a58ec2686eAngus Kong        runOnUiThread(new Runnable() {
24936839102e03107e3fb121197036365a58ec2686eAngus Kong            @Override
25036839102e03107e3fb121197036365a58ec2686eAngus Kong            public void run() {
25136839102e03107e3fb121197036365a58ec2686eAngus Kong                mSurface = surface;
25236839102e03107e3fb121197036365a58ec2686eAngus Kong                mSurface.setOnFrameAvailableListener(PanoramaActivity.this);
25336839102e03107e3fb121197036365a58ec2686eAngus Kong                startCameraPreview();
25436839102e03107e3fb121197036365a58ec2686eAngus Kong            }
25536839102e03107e3fb121197036365a58ec2686eAngus Kong        });
25636839102e03107e3fb121197036365a58ec2686eAngus Kong    }
25736839102e03107e3fb121197036365a58ec2686eAngus Kong
25841a2e9735136f372de95652d0828600282c8e967mbansal    public void runViewFinder() {
25941a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setWarping(false);
26041a2e9735136f372de95652d0828600282c8e967mbansal
26141a2e9735136f372de95652d0828600282c8e967mbansal        // First update the surface texture...
26241a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.updateSurfaceTexture();
26341a2e9735136f372de95652d0828600282c8e967mbansal        // ...then call preprocess to render it to low-res and high-res RGB textures
26441a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.preprocess();
26541a2e9735136f372de95652d0828600282c8e967mbansal
26641a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setReady();
26741a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.requestRender();
26841a2e9735136f372de95652d0828600282c8e967mbansal    }
26941a2e9735136f372de95652d0828600282c8e967mbansal
27041a2e9735136f372de95652d0828600282c8e967mbansal    public void runMosaicCapture() {
27141a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setWarping(true);
27241a2e9735136f372de95652d0828600282c8e967mbansal
27341a2e9735136f372de95652d0828600282c8e967mbansal        // Lock the condition variable
27441a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.lockPreviewReadyFlag();
27541a2e9735136f372de95652d0828600282c8e967mbansal        // First update the surface texture...
27641a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.updateSurfaceTexture();
27741a2e9735136f372de95652d0828600282c8e967mbansal        // ...then call preprocess to render it to low-res and high-res RGB textures
27841a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.preprocess();
27941a2e9735136f372de95652d0828600282c8e967mbansal        // Now, transfer the textures from GPU to CPU memory for processing
28041a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.transferGPUtoCPU();
28141a2e9735136f372de95652d0828600282c8e967mbansal        // Wait on the condition variable (will be opened when GPU->CPU transfer is done).
28241a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.waitUntilPreviewReady();
28341a2e9735136f372de95652d0828600282c8e967mbansal
2840adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen        mMosaicFrameProcessor.processFrame();
28541a2e9735136f372de95652d0828600282c8e967mbansal    }
28641a2e9735136f372de95652d0828600282c8e967mbansal
287739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    public synchronized void onFrameAvailable(SurfaceTexture surface) {
28841a2e9735136f372de95652d0828600282c8e967mbansal        /* For simplicity, SurfaceTexture calls here when it has new
28941a2e9735136f372de95652d0828600282c8e967mbansal         * data available.  Call may come in from some random thread,
29041a2e9735136f372de95652d0828600282c8e967mbansal         * so let's be safe and use synchronize. No OpenGL calls can be done here.
29141a2e9735136f372de95652d0828600282c8e967mbansal         */
29241a2e9735136f372de95652d0828600282c8e967mbansal        if (mCaptureState == CAPTURE_VIEWFINDER) {
29341a2e9735136f372de95652d0828600282c8e967mbansal            runViewFinder();
29441a2e9735136f372de95652d0828600282c8e967mbansal        } else {
29541a2e9735136f372de95652d0828600282c8e967mbansal            runMosaicCapture();
29641a2e9735136f372de95652d0828600282c8e967mbansal        }
29741a2e9735136f372de95652d0828600282c8e967mbansal    }
29841a2e9735136f372de95652d0828600282c8e967mbansal
299a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    public void startCapture() {
3008a2c41754655a3733175fce81fb7506ff7022959Angus Kong        // Reset values so we can do this again.
3018a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mTimeTaken = System.currentTimeMillis();
30241a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_MOSAIC;
303fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong        mTooFastPrompt.setVisibility(View.GONE);
3048a2c41754655a3733175fce81fb7506ff7022959Angus Kong
3058a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() {
3068a2c41754655a3733175fce81fb7506ff7022959Angus Kong            @Override
3078a2c41754655a3733175fce81fb7506ff7022959Angus Kong            public void onProgress(boolean isFinished, float translationRate, int traversedAngleX,
308d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen                    int traversedAngleY) {
3098a2c41754655a3733175fce81fb7506ff7022959Angus Kong                if (isFinished) {
310a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong                    stopCapture();
3118a2c41754655a3733175fce81fb7506ff7022959Angus Kong                } else {
312d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen                    updateProgress(translationRate, traversedAngleX, traversedAngleY);
3138a2c41754655a3733175fce81fb7506ff7022959Angus Kong                }
3148a2c41754655a3733175fce81fb7506ff7022959Angus Kong            }
3158a2c41754655a3733175fce81fb7506ff7022959Angus Kong        });
3168a2c41754655a3733175fce81fb7506ff7022959Angus Kong
31760fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mStopCaptureButton.setVisibility(View.VISIBLE);
3185af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mCaptureView.setVisibility(View.VISIBLE);
319f921d46b1e1c9b4a8f1b017ce26675fd9accd609Wei-Ta Chen        mRealTimeMosaicView.setVisibility(View.VISIBLE);
320a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mPanoControlLayout.setVisibility(View.GONE);
32141a2e9735136f372de95652d0828600282c8e967mbansal
3228a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
3238a2c41754655a3733175fce81fb7506ff7022959Angus Kong
324a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private void stopCapture() {
32541a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
32641a2e9735136f372de95652d0828600282c8e967mbansal
3278a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(null);
32836839102e03107e3fb121197036365a58ec2686eAngus Kong        stopCameraPreview();
32941a2e9735136f372de95652d0828600282c8e967mbansal
33041a2e9735136f372de95652d0828600282c8e967mbansal        mSurface.setOnFrameAvailableListener(null);
33141a2e9735136f372de95652d0828600282c8e967mbansal
332ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        // TODO: show some dialog for long computation.
333142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (!mThreadRunning) {
334142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mThreadRunning = true;
335142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            Thread t = new Thread() {
336142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                @Override
337142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                public void run() {
338ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    byte[] jpegData = generateFinalMosaic(false);
339ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    Bitmap bitmap = null;
340ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    if (jpegData != null) {
341ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                        bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
342ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    }
343ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    mMainHandler.sendMessage(mMainHandler.obtainMessage(
344ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                            MSG_FINAL_MOSAIC_READY, bitmap));
345142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                }
346142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            };
347142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            t.start();
348142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
3498a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
3508a2c41754655a3733175fce81fb7506ff7022959Angus Kong
351d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen    private void updateProgress(float translationRate, int traversedAngleX, int traversedAngleY) {
352eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
353eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView.setReady();
354eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView.requestRender();
355eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
3568a2c41754655a3733175fce81fb7506ff7022959Angus Kong        if (translationRate > 150) {
357fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong            // TODO: draw speed indication according to the UI spec.
358fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong            mTooFastPrompt.setVisibility(View.VISIBLE);
35994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1);
3608a2c41754655a3733175fce81fb7506ff7022959Angus Kong            mCaptureView.invalidate();
3618a2c41754655a3733175fce81fb7506ff7022959Angus Kong        } else {
362fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong            mTooFastPrompt.setVisibility(View.GONE);
36394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1);
3648a2c41754655a3733175fce81fb7506ff7022959Angus Kong            mCaptureView.invalidate();
3658a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
3668a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
3678a2c41754655a3733175fce81fb7506ff7022959Angus Kong
368bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void createContentView() {
369bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setContentView(R.layout.panorama);
370bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
37141a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
37241a2e9735136f372de95652d0828600282c8e967mbansal
373a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mCaptureLayout = (View) findViewById(R.id.pano_capture_layout);
3745af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mRealTimeMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer);
3755af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mRealTimeMosaicView.getRenderer().setMosaicSurfaceCreateListener(this);
376bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCaptureView = (CaptureView) findViewById(R.id.pano_capture_view);
377bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCaptureView.setStartAngle(-DEFAULT_SWEEP_ANGLE / 2);
3785af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mStopCaptureButton = (Button) findViewById(R.id.pano_capture_stop_button);
379fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong        mTooFastPrompt = (TextView) findViewById(R.id.pano_capture_too_fast_textview);
380bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
3815af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mReviewLayout = (View) findViewById(R.id.pano_review_layout);
3825af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mReview = (ImageView) findViewById(R.id.pano_reviewarea);
383eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
384a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mPanoControlLayout = (View) findViewById(R.id.pano_control_layout);
385a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker = (ModePicker) findViewById(R.id.mode_picker);
386a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setVisibility(View.VISIBLE);
387a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setOnModeChangeListener(this);
388a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA);
389bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
390bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
391142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    @OnClickAttr
392739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    public void onStartButtonClicked(View v) {
39336839102e03107e3fb121197036365a58ec2686eAngus Kong        // If mSurface == null then GL setup is not finished yet. All buttons cannot be pressed.
39436839102e03107e3fb121197036365a58ec2686eAngus Kong        if (mPausing || mThreadRunning || mSurface == null) return;
395739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong        startCapture();
396739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    }
397739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong
398739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    @OnClickAttr
399142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    public void onStopButtonClicked(View v) {
40036839102e03107e3fb121197036365a58ec2686eAngus Kong        if (mPausing || mThreadRunning || mSurface == null) return;
401142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        stopCapture();
402142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
403142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
404142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    @OnClickAttr
405142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    public void onOkButtonClicked(View v) {
40636839102e03107e3fb121197036365a58ec2686eAngus Kong        if (mPausing || mThreadRunning || mSurface == null) return;
407142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mThreadRunning = true;
408142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        Thread t = new Thread() {
409142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            @Override
410142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            public void run() {
411ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                byte[] jpegData = generateFinalMosaic(true);
412ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                savePanorama(jpegData);
413ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                mMainHandler.sendMessage(mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW));
414142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            }
415142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        };
416142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        t.start();
417142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
418142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
419142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    @OnClickAttr
420142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    public void onRetakeButtonClicked(View v) {
421142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mPausing || mThreadRunning) return;
422142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        resetToPreview();
423142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
424142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
425142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void resetToPreview() {
42641a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
42741a2e9735136f372de95652d0828600282c8e967mbansal
42841a2e9735136f372de95652d0828600282c8e967mbansal        mReviewLayout.setVisibility(View.GONE);
42960fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mStopCaptureButton.setVisibility(View.GONE);
4305af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mCaptureView.setVisibility(View.GONE);
431142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPanoControlLayout.setVisibility(View.VISIBLE);
43260fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mCaptureLayout.setVisibility(View.VISIBLE);
433142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.reset();
43441a2e9735136f372de95652d0828600282c8e967mbansal
43541a2e9735136f372de95652d0828600282c8e967mbansal        mSurface.setOnFrameAvailableListener(this);
43641a2e9735136f372de95652d0828600282c8e967mbansal
43736839102e03107e3fb121197036365a58ec2686eAngus Kong        if (!mPausing) startCameraPreview();
43841a2e9735136f372de95652d0828600282c8e967mbansal
43941a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setVisibility(View.VISIBLE);
440142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
441142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
442142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void showFinalMosaic(Bitmap bitmap) {
443142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (bitmap != null) {
444142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mReview.setImageBitmap(bitmap);
445142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
446ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureLayout.setVisibility(View.GONE);
447ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mReviewLayout.setVisibility(View.VISIBLE);
448ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureView.setStatusText("");
449ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureView.setSweepAngle(0);
450142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
451142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
452ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    private void savePanorama(byte[] jpegData) {
453ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (jpegData != null) {
454ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            String imagePath = PanoUtil.createName(
455ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    getResources().getString(R.string.pano_file_name_format), mTimeTaken);
456ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null, 0,
457ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    jpegData);
458142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
459142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
460142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
461142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void clearMosaicFrameProcessorIfNeeded() {
462142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (!mPausing || mThreadRunning) return;
463142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.clear();
464142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
465142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
466142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void initMosaicFrameProcessorIfNeeded() {
467142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mPausing || mThreadRunning) return;
468142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mMosaicFrameProcessor == null) {
469142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            // Start the activity for the first time.
470142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mMosaicFrameProcessor = new MosaicFrameProcessor(DEFAULT_SWEEP_ANGLE - 5,
4710adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen                    mPreviewWidth, mPreviewHeight, getPreviewBufSize());
472142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
473142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.initialize();
474bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
475bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
476bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
477bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    protected void onPause() {
478bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onPause();
47941a2e9735136f372de95652d0828600282c8e967mbansal        mSurface.setOnFrameAvailableListener(null);
480bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        releaseCamera();
481142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = true;
48241a2e9735136f372de95652d0828600282c8e967mbansal
483eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView.onPause();
48494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen        mSensorManager.unregisterListener(mListener);
485142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        clearMosaicFrameProcessorIfNeeded();
48694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen        System.gc();
487bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
488bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
489bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
490bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    protected void onResume() {
491bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onResume();
492bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
493142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = false;
494bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        /*
49594f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * It is not necessary to get accelerometer events at a very high rate,
49694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * by using a slower rate (SENSOR_DELAY_UI), we get an automatic
49794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * low-pass filter, which "extracts" the gravity component of the
49894f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * acceleration. As an added benefit, we use less power and CPU
49994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * resources.
500bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen         */
501bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI);
50241a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
503bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setupCamera();
504142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        // Camera must be initialized before MosaicFrameProcessor is initialized. The preview size
505142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        // has to be decided by camera device.
506142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        initMosaicFrameProcessorIfNeeded();
507eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView.onResume();
508bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
509bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
510bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private final SensorEventListener mListener = new SensorEventListener() {
511bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mCompassCurrX; // degrees
512bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mCompassCurrY; // degrees
513bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mTimestamp;
514bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
515bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        public void onSensorChanged(SensorEvent event) {
516bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
517bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                if (mTimestamp != 0) {
518bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    final float dT = (event.timestamp - mTimestamp) * NS2S;
519bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    mCompassCurrX += event.values[1] * dT * 180.0f / Math.PI;
520bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    mCompassCurrY += event.values[0] * dT * 180.0f / Math.PI;
521bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                }
522bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mTimestamp = event.timestamp;
523bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
524bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
525bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mCompassCurrX = event.values[0];
526bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mCompassCurrY = event.values[1];
527bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
528bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
5298a2c41754655a3733175fce81fb7506ff7022959Angus Kong            if (mMosaicFrameProcessor != null) {
5308a2c41754655a3733175fce81fb7506ff7022959Angus Kong                mMosaicFrameProcessor.updateCompassValue(mCompassCurrX, mCompassCurrY);
531bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
532bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
533bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
534bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        @Override
535bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        public void onAccuracyChanged(Sensor sensor, int accuracy) {
536bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
537bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    };
538bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
539ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    public byte[] generateFinalMosaic(boolean highRes) {
5408a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.createMosaic(highRes);
541bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
542ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21();
543ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (imageData == null) {
544ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "getFinalMosaicNV21() returned null.");
545ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            return null;
5468a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
5478a2c41754655a3733175fce81fb7506ff7022959Angus Kong
548ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int len = imageData.length - 8;
549ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16)
550ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF);
551ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16)
552ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF);
553ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height);
5548a2c41754655a3733175fce81fb7506ff7022959Angus Kong
555e46486104523760a4433f03e09ed615987d83b6cAngus Kong        if (width <= 0 || height <= 0) {
556e46486104523760a4433f03e09ed615987d83b6cAngus Kong            // TODO: pop up a error meesage indicating that the final result is not generated.
557e46486104523760a4433f03e09ed615987d83b6cAngus Kong            Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " +
558e46486104523760a4433f03e09ed615987d83b6cAngus Kong                    height);
559e46486104523760a4433f03e09ed615987d83b6cAngus Kong            return null;
560e46486104523760a4433f03e09ed615987d83b6cAngus Kong        }
561e46486104523760a4433f03e09ed615987d83b6cAngus Kong
562ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
563ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        ByteArrayOutputStream out = new ByteArrayOutputStream();
564ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out);
565ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        try {
566ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            out.close();
567ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        } catch (Exception e) {
568ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "Exception in storing final mosaic", e);
569ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            return null;
570ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        }
571ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        return out.toByteArray();
572bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
5738a2c41754655a3733175fce81fb7506ff7022959Angus Kong
57441a2e9735136f372de95652d0828600282c8e967mbansal    private void setPreviewTexture(SurfaceTexture surface) {
57598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
57641a2e9735136f372de95652d0828600282c8e967mbansal            mCameraDevice.setPreviewTexture(surface);
57798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
57898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
57941a2e9735136f372de95652d0828600282c8e967mbansal            throw new RuntimeException("setPreviewTexture failed", ex);
58098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
58198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
58298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
58336839102e03107e3fb121197036365a58ec2686eAngus Kong    private void startCameraPreview() {
58498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // If we're previewing already, stop the preview first (this will blank
58598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // the screen).
58636839102e03107e3fb121197036365a58ec2686eAngus Kong        if (mCameraState != PREVIEW_STOPPED) stopCameraPreview();
58798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
58841a2e9735136f372de95652d0828600282c8e967mbansal        setPreviewTexture(mSurface);
58998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
59098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
59198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "startPreview");
59298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.startPreview();
59398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
59498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
59598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            throw new RuntimeException("startPreview failed", ex);
59698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
59798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_ACTIVE;
59898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
59998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
60036839102e03107e3fb121197036365a58ec2686eAngus Kong    private void stopCameraPreview() {
60198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
60298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "stopPreview");
60398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.stopPreview();
60498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
60598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_STOPPED;
60698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
607bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen}
608