PanoramaActivity.java revision e46486104523760a4433f03e09ed615987d83b6c
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;
52bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
53ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport java.io.ByteArrayOutputStream;
54bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport java.util.List;
55bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
56a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong/**
57a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong * Activity to handle panorama capturing.
58a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong */
5998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chenpublic class PanoramaActivity extends Activity implements
6041a2e9735136f372de95652d0828600282c8e967mbansal        ModePicker.OnModeChangeListener,
6136839102e03107e3fb121197036365a58ec2686eAngus Kong        SurfaceTexture.OnFrameAvailableListener,
6236839102e03107e3fb121197036365a58ec2686eAngus Kong        MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener {
63ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    public static final int DEFAULT_SWEEP_ANGLE = 160;
64bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL;
65bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720;
66bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
67ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private static final int MSG_FINAL_MOSAIC_READY = 1;
68142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private static final int MSG_RESET_TO_PREVIEW = 2;
6994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen
70ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private static final String TAG = "PanoramaActivity";
7198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_STOPPED = 0;
7298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_ACTIVE = 1;
7341a2e9735136f372de95652d0828600282c8e967mbansal    private static final int CAPTURE_VIEWFINDER = 0;
7441a2e9735136f372de95652d0828600282c8e967mbansal    private static final int CAPTURE_MOSAIC = 1;
7541a2e9735136f372de95652d0828600282c8e967mbansal
76a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    // Ratio of nanosecond to second
77a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private static final float NS2S = 1.0f / 1000000000.0f;
78142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
79142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mPausing;
80142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
81a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mPanoControlLayout;
82a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mCaptureLayout;
8360fc534ec8f68d95a486984cb396a2da0e200518Angus Kong    private Button mStopCaptureButton;
84a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mReviewLayout;
85bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private ImageView mReview;
86bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private CaptureView mCaptureView;
87eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal    private MosaicRendererSurfaceView mRealTimeMosaicView;
88142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
89bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewWidth;
90bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewHeight;
918a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private Camera mCameraDevice;
9298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private int mCameraState;
9341a2e9735136f372de95652d0828600282c8e967mbansal    private int mCaptureState;
94bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private SensorManager mSensorManager;
95bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private Sensor mSensor;
96a72d73cbac59db43d413291e4db66763be08143arepo sync    private ModePicker mModePicker;
978a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private MosaicFrameProcessor mMosaicFrameProcessor;
988a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private String mCurrentImagePath = null;
998a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private long mTimeTaken;
100ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private Handler mMainHandler;
10141a2e9735136f372de95652d0828600282c8e967mbansal    private SurfaceTexture mSurface;
102142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mThreadRunning;
103142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
104bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
105bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public void onCreate(Bundle icicle) {
106bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onCreate(icicle);
107bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
108bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
109bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
110bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
111bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        createContentView();
112bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
113bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
114bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
115bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (mSensor == null) {
116bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
117bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
1188a2c41754655a3733175fce81fb7506ff7022959Angus Kong
119ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        mMainHandler = new Handler() {
120ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            @Override
121ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            public void handleMessage(Message msg) {
122ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                switch (msg.what) {
123ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                    case MSG_FINAL_MOSAIC_READY:
124142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        mThreadRunning = false;
125142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        showFinalMosaic((Bitmap) msg.obj);
126142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
127142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                    case MSG_RESET_TO_PREVIEW:
128142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        mThreadRunning = false;
129142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        resetToPreview();
130142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
131ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                }
132142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                clearMosaicFrameProcessorIfNeeded();
133ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            }
134ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        };
135bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
136bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
137bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCamera() {
138bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        openCamera();
139bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Parameters parameters = mCameraDevice.getParameters();
140bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setupCaptureParams(parameters);
141bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        configureCamera(parameters);
142bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
143bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
144ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private void releaseCamera() {
145ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        if (mCameraDevice != null) {
146142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mCameraDevice.setPreviewCallbackWithBuffer(null);
147ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            CameraHolder.instance().release();
148ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            mCameraDevice = null;
14998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraState = PREVIEW_STOPPED;
150ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        }
151ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    }
152ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong
153bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void openCamera() {
154bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        try {
155bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId());
156bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        } catch (CameraHardwareException e) {
157bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Util.showErrorAndFinish(this, R.string.cannot_connect_camera);
158bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            return;
159bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        } catch (CameraDisabledException e) {
160bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Util.showErrorAndFinish(this, R.string.camera_disabled);
161bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            return;
162bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
163bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
164bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
165bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3,
166bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            boolean needSmaller) {
167bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int pixelsDiff = DEFAULT_CAPTURE_PIXELS;
168bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        boolean hasFound = false;
1698a2c41754655a3733175fce81fb7506ff7022959Angus Kong        for (Size size : supportedSizes) {
170bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int h = size.height;
171bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int w = size.width;
172bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            // we only want 4:3 format.
173bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int d = DEFAULT_CAPTURE_PIXELS - h * w;
17494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            if (needSmaller && d < 0) { // no bigger preview than 960x720.
175bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
176bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
177bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (need4To3 && (h * 4 != w * 3)) {
178bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
179bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
180bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            d = Math.abs(d);
181bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (d < pixelsDiff) {
182bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewWidth = w;
183bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewHeight = h;
184bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                pixelsDiff = d;
185bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                hasFound = true;
186bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
187bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
188bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return hasFound;
189bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
190bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
191bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCaptureParams(Parameters parameters) {
192bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
193bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (!findBestPreviewSize(supportedSizes, true, true)) {
194bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Log.w(TAG, "No 4:3 ratio preview size supported.");
195bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (!findBestPreviewSize(supportedSizes, false, true)) {
196bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                Log.w(TAG, "Can't find a supported preview size smaller than 960x720.");
197bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                findBestPreviewSize(supportedSizes, false, false);
198bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
199bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
200bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth);
201bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewSize(mPreviewWidth, mPreviewHeight);
202bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
203bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<int[]> frameRates = parameters.getSupportedPreviewFpsRange();
204bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int last = frameRates.size() - 1;
205bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX];
206bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX];
207bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewFpsRange(minFps, maxFps);
208bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview fps: " + minFps + ", " + maxFps);
2093ab4f0912da83f7f5f8266a57a606d521c1649e3Wu-cheng Li
21093ad273a53e7d2975a67d7d1f8a157f845e41cf2Wu-cheng Li        parameters.setRecordingHint(false);
211bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
212bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
213bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public int getPreviewBufSize() {
214bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat pixelInfo = new PixelFormat();
215bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo);
216bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        // TODO: remove this extra 32 byte after the driver bug is fixed.
217bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32;
218bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
219bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
220bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void configureCamera(Parameters parameters) {
221bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCameraDevice.setParameters(parameters);
222bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
2234b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        int orientation = Util.getDisplayOrientation(Util.getDisplayRotation(this),
2244b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li                CameraHolder.instance().getBackCameraId());
2254b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        mCameraDevice.setDisplayOrientation(orientation);
226bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
227bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
228a72d73cbac59db43d413291e4db66763be08143arepo sync    private boolean switchToOtherMode(int mode) {
229a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        if (isFinishing()) {
23094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            return false;
231a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        }
232a72d73cbac59db43d413291e4db66763be08143arepo sync        MenuHelper.gotoMode(mode, this);
233a72d73cbac59db43d413291e4db66763be08143arepo sync        finish();
234a72d73cbac59db43d413291e4db66763be08143arepo sync        return true;
235a72d73cbac59db43d413291e4db66763be08143arepo sync    }
236a72d73cbac59db43d413291e4db66763be08143arepo sync
237a72d73cbac59db43d413291e4db66763be08143arepo sync    public boolean onModeChanged(int mode) {
238a72d73cbac59db43d413291e4db66763be08143arepo sync        if (mode != ModePicker.MODE_PANORAMA) {
239a72d73cbac59db43d413291e4db66763be08143arepo sync            return switchToOtherMode(mode);
240a72d73cbac59db43d413291e4db66763be08143arepo sync        } else {
241a72d73cbac59db43d413291e4db66763be08143arepo sync            return true;
242a72d73cbac59db43d413291e4db66763be08143arepo sync        }
243a72d73cbac59db43d413291e4db66763be08143arepo sync    }
244a72d73cbac59db43d413291e4db66763be08143arepo sync
24536839102e03107e3fb121197036365a58ec2686eAngus Kong    public void onMosaicSurfaceCreated(final SurfaceTexture surface) {
24636839102e03107e3fb121197036365a58ec2686eAngus Kong        runOnUiThread(new Runnable() {
24736839102e03107e3fb121197036365a58ec2686eAngus Kong            @Override
24836839102e03107e3fb121197036365a58ec2686eAngus Kong            public void run() {
24936839102e03107e3fb121197036365a58ec2686eAngus Kong                mSurface = surface;
25036839102e03107e3fb121197036365a58ec2686eAngus Kong                mSurface.setOnFrameAvailableListener(PanoramaActivity.this);
25136839102e03107e3fb121197036365a58ec2686eAngus Kong                startCameraPreview();
25236839102e03107e3fb121197036365a58ec2686eAngus Kong            }
25336839102e03107e3fb121197036365a58ec2686eAngus Kong        });
25436839102e03107e3fb121197036365a58ec2686eAngus Kong    }
25536839102e03107e3fb121197036365a58ec2686eAngus Kong
25641a2e9735136f372de95652d0828600282c8e967mbansal    public void runViewFinder() {
25741a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setWarping(false);
25841a2e9735136f372de95652d0828600282c8e967mbansal
25941a2e9735136f372de95652d0828600282c8e967mbansal        // First update the surface texture...
26041a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.updateSurfaceTexture();
26141a2e9735136f372de95652d0828600282c8e967mbansal        // ...then call preprocess to render it to low-res and high-res RGB textures
26241a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.preprocess();
26341a2e9735136f372de95652d0828600282c8e967mbansal
26441a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setReady();
26541a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.requestRender();
26641a2e9735136f372de95652d0828600282c8e967mbansal    }
26741a2e9735136f372de95652d0828600282c8e967mbansal
26841a2e9735136f372de95652d0828600282c8e967mbansal    public void runMosaicCapture() {
26941a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setWarping(true);
27041a2e9735136f372de95652d0828600282c8e967mbansal
27141a2e9735136f372de95652d0828600282c8e967mbansal        // Lock the condition variable
27241a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.lockPreviewReadyFlag();
27341a2e9735136f372de95652d0828600282c8e967mbansal        // First update the surface texture...
27441a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.updateSurfaceTexture();
27541a2e9735136f372de95652d0828600282c8e967mbansal        // ...then call preprocess to render it to low-res and high-res RGB textures
27641a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.preprocess();
27741a2e9735136f372de95652d0828600282c8e967mbansal        // Now, transfer the textures from GPU to CPU memory for processing
27841a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.transferGPUtoCPU();
27941a2e9735136f372de95652d0828600282c8e967mbansal        // Wait on the condition variable (will be opened when GPU->CPU transfer is done).
28041a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.waitUntilPreviewReady();
28141a2e9735136f372de95652d0828600282c8e967mbansal
2820adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen        mMosaicFrameProcessor.processFrame();
28341a2e9735136f372de95652d0828600282c8e967mbansal    }
28441a2e9735136f372de95652d0828600282c8e967mbansal
285739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    public synchronized void onFrameAvailable(SurfaceTexture surface) {
28641a2e9735136f372de95652d0828600282c8e967mbansal        /* For simplicity, SurfaceTexture calls here when it has new
28741a2e9735136f372de95652d0828600282c8e967mbansal         * data available.  Call may come in from some random thread,
28841a2e9735136f372de95652d0828600282c8e967mbansal         * so let's be safe and use synchronize. No OpenGL calls can be done here.
28941a2e9735136f372de95652d0828600282c8e967mbansal         */
29041a2e9735136f372de95652d0828600282c8e967mbansal        if (mCaptureState == CAPTURE_VIEWFINDER) {
29141a2e9735136f372de95652d0828600282c8e967mbansal            runViewFinder();
29241a2e9735136f372de95652d0828600282c8e967mbansal        } else {
29341a2e9735136f372de95652d0828600282c8e967mbansal            runMosaicCapture();
29441a2e9735136f372de95652d0828600282c8e967mbansal        }
29541a2e9735136f372de95652d0828600282c8e967mbansal    }
29641a2e9735136f372de95652d0828600282c8e967mbansal
297a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    public void startCapture() {
2988a2c41754655a3733175fce81fb7506ff7022959Angus Kong        // Reset values so we can do this again.
2998a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mTimeTaken = System.currentTimeMillis();
30041a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_MOSAIC;
3018a2c41754655a3733175fce81fb7506ff7022959Angus Kong
3028a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() {
3038a2c41754655a3733175fce81fb7506ff7022959Angus Kong            @Override
3048a2c41754655a3733175fce81fb7506ff7022959Angus Kong            public void onProgress(boolean isFinished, float translationRate, int traversedAngleX,
305d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen                    int traversedAngleY) {
3068a2c41754655a3733175fce81fb7506ff7022959Angus Kong                if (isFinished) {
307a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong                    stopCapture();
3088a2c41754655a3733175fce81fb7506ff7022959Angus Kong                } else {
309d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen                    updateProgress(translationRate, traversedAngleX, traversedAngleY);
3108a2c41754655a3733175fce81fb7506ff7022959Angus Kong                }
3118a2c41754655a3733175fce81fb7506ff7022959Angus Kong            }
3128a2c41754655a3733175fce81fb7506ff7022959Angus Kong        });
3138a2c41754655a3733175fce81fb7506ff7022959Angus Kong
31460fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mStopCaptureButton.setVisibility(View.VISIBLE);
315f921d46b1e1c9b4a8f1b017ce26675fd9accd609Wei-Ta Chen        mRealTimeMosaicView.setVisibility(View.VISIBLE);
316a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mPanoControlLayout.setVisibility(View.GONE);
31741a2e9735136f372de95652d0828600282c8e967mbansal
3188a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
3198a2c41754655a3733175fce81fb7506ff7022959Angus Kong
320a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private void stopCapture() {
32141a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
32241a2e9735136f372de95652d0828600282c8e967mbansal
3238a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(null);
32436839102e03107e3fb121197036365a58ec2686eAngus Kong        stopCameraPreview();
32541a2e9735136f372de95652d0828600282c8e967mbansal
32641a2e9735136f372de95652d0828600282c8e967mbansal        mSurface.setOnFrameAvailableListener(null);
32741a2e9735136f372de95652d0828600282c8e967mbansal
328ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        // TODO: show some dialog for long computation.
329142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (!mThreadRunning) {
330142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mThreadRunning = true;
331142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            Thread t = new Thread() {
332142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                @Override
333142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                public void run() {
334ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    byte[] jpegData = generateFinalMosaic(false);
335ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    Bitmap bitmap = null;
336ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    if (jpegData != null) {
337ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                        bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
338ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    }
339ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    mMainHandler.sendMessage(mMainHandler.obtainMessage(
340ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                            MSG_FINAL_MOSAIC_READY, bitmap));
341142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                }
342142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            };
343142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            t.start();
344142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
3458a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
3468a2c41754655a3733175fce81fb7506ff7022959Angus Kong
347d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen    private void updateProgress(float translationRate, int traversedAngleX, int traversedAngleY) {
348eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
349eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView.setReady();
350eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView.requestRender();
351eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
3528a2c41754655a3733175fce81fb7506ff7022959Angus Kong        if (translationRate > 150) {
35394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            // TODO: remove the text and draw implications according to the UI
35494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            // spec.
3558a2c41754655a3733175fce81fb7506ff7022959Angus Kong            mCaptureView.setStatusText("S L O W   D O W N");
35694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1);
3578a2c41754655a3733175fce81fb7506ff7022959Angus Kong            mCaptureView.invalidate();
3588a2c41754655a3733175fce81fb7506ff7022959Angus Kong        } else {
3598a2c41754655a3733175fce81fb7506ff7022959Angus Kong            mCaptureView.setStatusText("");
36094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1);
3618a2c41754655a3733175fce81fb7506ff7022959Angus Kong            mCaptureView.invalidate();
3628a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
3638a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
3648a2c41754655a3733175fce81fb7506ff7022959Angus Kong
365bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void createContentView() {
366bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setContentView(R.layout.panorama);
367bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
36841a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
36941a2e9735136f372de95652d0828600282c8e967mbansal
370a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mCaptureLayout = (View) findViewById(R.id.pano_capture_layout);
37160fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mStopCaptureButton = (Button) findViewById(R.id.pano_capture_stop_button);
372a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mReviewLayout = (View) findViewById(R.id.pano_review_layout);
37398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
374bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCaptureView = (CaptureView) findViewById(R.id.pano_capture_view);
375bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCaptureView.setStartAngle(-DEFAULT_SWEEP_ANGLE / 2);
376bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mReview = (ImageView) findViewById(R.id.pano_reviewarea);
377bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
378eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer);
37936839102e03107e3fb121197036365a58ec2686eAngus Kong        mRealTimeMosaicView.getRenderer().setMosaicSurfaceCreateListener(this);
380eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
381a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mPanoControlLayout = (View) findViewById(R.id.pano_control_layout);
382a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong
383a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker = (ModePicker) findViewById(R.id.mode_picker);
384a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setVisibility(View.VISIBLE);
385a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setOnModeChangeListener(this);
386a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA);
38741a2e9735136f372de95652d0828600282c8e967mbansal
38841a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setVisibility(View.VISIBLE);
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);
430142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPanoControlLayout.setVisibility(View.VISIBLE);
43160fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mCaptureLayout.setVisibility(View.VISIBLE);
432142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.reset();
43341a2e9735136f372de95652d0828600282c8e967mbansal
43441a2e9735136f372de95652d0828600282c8e967mbansal        mSurface.setOnFrameAvailableListener(this);
43541a2e9735136f372de95652d0828600282c8e967mbansal
43636839102e03107e3fb121197036365a58ec2686eAngus Kong        if (!mPausing) startCameraPreview();
43741a2e9735136f372de95652d0828600282c8e967mbansal
43841a2e9735136f372de95652d0828600282c8e967mbansal        mRealTimeMosaicView.setVisibility(View.VISIBLE);
439142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
440142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
441142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void showFinalMosaic(Bitmap bitmap) {
442142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (bitmap != null) {
443142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mReview.setImageBitmap(bitmap);
444142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
445ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureLayout.setVisibility(View.GONE);
446ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mReviewLayout.setVisibility(View.VISIBLE);
447ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureView.setStatusText("");
448ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureView.setSweepAngle(0);
449142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
450142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
451ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    private void savePanorama(byte[] jpegData) {
452ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (jpegData != null) {
453ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            String imagePath = PanoUtil.createName(
454ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    getResources().getString(R.string.pano_file_name_format), mTimeTaken);
455ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null, 0,
456ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    jpegData);
457142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
458142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
459142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
460142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void clearMosaicFrameProcessorIfNeeded() {
461142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (!mPausing || mThreadRunning) return;
462142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.clear();
463142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
464142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
465142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void initMosaicFrameProcessorIfNeeded() {
466142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mPausing || mThreadRunning) return;
467142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mMosaicFrameProcessor == null) {
468142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            // Start the activity for the first time.
469142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mMosaicFrameProcessor = new MosaicFrameProcessor(DEFAULT_SWEEP_ANGLE - 5,
4700adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen                    mPreviewWidth, mPreviewHeight, getPreviewBufSize());
471142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
472142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.initialize();
473bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
474bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
475bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
476bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    protected void onPause() {
477bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onPause();
47841a2e9735136f372de95652d0828600282c8e967mbansal        mSurface.setOnFrameAvailableListener(null);
479bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        releaseCamera();
480142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = true;
48141a2e9735136f372de95652d0828600282c8e967mbansal
482eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView.onPause();
48341a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureView.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();
50794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen        mCaptureView.onResume();
508eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal        mRealTimeMosaicView.onResume();
509bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
510bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
511bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private final SensorEventListener mListener = new SensorEventListener() {
512bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mCompassCurrX; // degrees
513bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mCompassCurrY; // degrees
514bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mTimestamp;
515bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
516bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        public void onSensorChanged(SensorEvent event) {
517bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
518bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                if (mTimestamp != 0) {
519bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    final float dT = (event.timestamp - mTimestamp) * NS2S;
520bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    mCompassCurrX += event.values[1] * dT * 180.0f / Math.PI;
521bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    mCompassCurrY += event.values[0] * dT * 180.0f / Math.PI;
522bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                }
523bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mTimestamp = event.timestamp;
524bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
525bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
526bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mCompassCurrX = event.values[0];
527bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mCompassCurrY = event.values[1];
528bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
529bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
5308a2c41754655a3733175fce81fb7506ff7022959Angus Kong            if (mMosaicFrameProcessor != null) {
5318a2c41754655a3733175fce81fb7506ff7022959Angus Kong                mMosaicFrameProcessor.updateCompassValue(mCompassCurrX, mCompassCurrY);
532bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
533bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
534bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
535bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        @Override
536bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        public void onAccuracyChanged(Sensor sensor, int accuracy) {
537bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
538bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    };
539bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
540ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    public byte[] generateFinalMosaic(boolean highRes) {
5418a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.createMosaic(highRes);
542bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
543ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21();
544ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (imageData == null) {
545ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "getFinalMosaicNV21() returned null.");
546ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            return null;
5478a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
5488a2c41754655a3733175fce81fb7506ff7022959Angus Kong
549ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int len = imageData.length - 8;
550ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16)
551ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF);
552ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16)
553ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF);
554ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height);
5558a2c41754655a3733175fce81fb7506ff7022959Angus Kong
556e46486104523760a4433f03e09ed615987d83b6cAngus Kong        if (width <= 0 || height <= 0) {
557e46486104523760a4433f03e09ed615987d83b6cAngus Kong            // TODO: pop up a error meesage indicating that the final result is not generated.
558e46486104523760a4433f03e09ed615987d83b6cAngus Kong            Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " +
559e46486104523760a4433f03e09ed615987d83b6cAngus Kong                    height);
560e46486104523760a4433f03e09ed615987d83b6cAngus Kong            return null;
561e46486104523760a4433f03e09ed615987d83b6cAngus Kong        }
562e46486104523760a4433f03e09ed615987d83b6cAngus Kong
563ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
564ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        ByteArrayOutputStream out = new ByteArrayOutputStream();
565ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out);
566ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        try {
567ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            out.close();
568ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        } catch (Exception e) {
569ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "Exception in storing final mosaic", e);
570ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            return null;
571ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        }
572ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        return out.toByteArray();
573bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
5748a2c41754655a3733175fce81fb7506ff7022959Angus Kong
57541a2e9735136f372de95652d0828600282c8e967mbansal    private void setPreviewTexture(SurfaceTexture surface) {
57698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
57741a2e9735136f372de95652d0828600282c8e967mbansal            mCameraDevice.setPreviewTexture(surface);
57898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
57998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
58041a2e9735136f372de95652d0828600282c8e967mbansal            throw new RuntimeException("setPreviewTexture failed", ex);
58198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
58298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
58398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
58436839102e03107e3fb121197036365a58ec2686eAngus Kong    private void startCameraPreview() {
58598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // If we're previewing already, stop the preview first (this will blank
58698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // the screen).
58736839102e03107e3fb121197036365a58ec2686eAngus Kong        if (mCameraState != PREVIEW_STOPPED) stopCameraPreview();
58898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
58941a2e9735136f372de95652d0828600282c8e967mbansal        setPreviewTexture(mSurface);
59098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
59198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
59298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "startPreview");
59398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.startPreview();
59498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
59598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
59698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            throw new RuntimeException("startPreview failed", ex);
59798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
59898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_ACTIVE;
59998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
60098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
60136839102e03107e3fb121197036365a58ec2686eAngus Kong    private void stopCameraPreview() {
60298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
60398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "stopPreview");
60498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.stopPreview();
60598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
60698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_STOPPED;
60798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
608bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen}
609