PanoramaActivity.java revision 50b3c890986aadb3780b4da8c0b8dbb0f1422eba
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;
295fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kongimport android.app.ProgressDialog;
30bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.content.Context;
31142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.Bitmap;
32142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.BitmapFactory;
338a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.ImageFormat;
34bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.graphics.PixelFormat;
358a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.Rect;
3641a2e9735136f372de95652d0828600282c8e967mbansalimport android.graphics.SurfaceTexture;
378a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.YuvImage;
388a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.hardware.Camera;
39bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.Sensor;
40bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorEvent;
41bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorEventListener;
42bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorManager;
4350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansalimport android.hardware.Camera.Parameters;
4450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansalimport android.hardware.Camera.Size;
45bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.os.Bundle;
468a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.os.Handler;
47ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport android.os.Message;
48bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.util.Log;
49bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.View;
50bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.WindowManager;
51f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kongimport android.view.animation.Animation;
52f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kongimport android.view.animation.AnimationUtils;
5360fc534ec8f68d95a486984cb396a2da0e200518Angus Kongimport android.widget.Button;
54bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.widget.ImageView;
5550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansalimport android.widget.ProgressBar;
56fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kongimport android.widget.TextView;
57bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
58ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport java.io.ByteArrayOutputStream;
59bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport java.util.List;
60bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
61a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong/**
62a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong * Activity to handle panorama capturing.
63a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong */
6498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chenpublic class PanoramaActivity extends Activity implements
6541a2e9735136f372de95652d0828600282c8e967mbansal        ModePicker.OnModeChangeListener,
6636839102e03107e3fb121197036365a58ec2686eAngus Kong        SurfaceTexture.OnFrameAvailableListener,
6736839102e03107e3fb121197036365a58ec2686eAngus Kong        MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener {
68ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    public static final int DEFAULT_SWEEP_ANGLE = 160;
69bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL;
70bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720;
71bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
72ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private static final int MSG_FINAL_MOSAIC_READY = 1;
73142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private static final int MSG_RESET_TO_PREVIEW = 2;
7494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen
75ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private static final String TAG = "PanoramaActivity";
7698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_STOPPED = 0;
7798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_ACTIVE = 1;
7841a2e9735136f372de95652d0828600282c8e967mbansal    private static final int CAPTURE_VIEWFINDER = 0;
7941a2e9735136f372de95652d0828600282c8e967mbansal    private static final int CAPTURE_MOSAIC = 1;
8041a2e9735136f372de95652d0828600282c8e967mbansal
8143b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    // Speed is in unit of deg/sec
8243b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    private static final float PANNING_SPEED_THRESHOLD = 30f;
8343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen
84a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    // Ratio of nanosecond to second
85a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private static final float NS2S = 1.0f / 1000000000.0f;
86142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
87142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mPausing;
88142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
89a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mPanoControlLayout;
90a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mCaptureLayout;
9160fc534ec8f68d95a486984cb396a2da0e200518Angus Kong    private Button mStopCaptureButton;
92a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mReviewLayout;
93bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private ImageView mReview;
94bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private CaptureView mCaptureView;
952faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private MosaicRendererSurfaceView mMosaicView;
96fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong    private TextView mTooFastPrompt;
97f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kong    private Animation mSlideIn, mSlideOut;
98142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
995fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private ProgressDialog mProgressDialog;
1005fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private String mPreparePreviewString;
1015fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private String mGeneratePanoramaString;
1025fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
103bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewWidth;
104bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewHeight;
1058a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private Camera mCameraDevice;
10698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private int mCameraState;
10741a2e9735136f372de95652d0828600282c8e967mbansal    private int mCaptureState;
108bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private SensorManager mSensorManager;
109bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private Sensor mSensor;
110a72d73cbac59db43d413291e4db66763be08143arepo sync    private ModePicker mModePicker;
1118a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private MosaicFrameProcessor mMosaicFrameProcessor;
1128a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private String mCurrentImagePath = null;
1138a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private long mTimeTaken;
114ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private Handler mMainHandler;
1152faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private SurfaceTexture mSurfaceTexture;
116142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mThreadRunning;
1172faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private float[] mTransformMatrix;
11843b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    private float mHorizontalViewAngle;
11943b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    private float mVerticalViewAngle;
120142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
121bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
122bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public void onCreate(Bundle icicle) {
123bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onCreate(icicle);
124bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
125bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
126bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
127bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
128bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        createContentView();
129bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
130bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
131bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
132bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (mSensor == null) {
133bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
134bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
1358a2c41754655a3733175fce81fb7506ff7022959Angus Kong
1362faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mTransformMatrix = new float[16];
1372faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong
1385fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mPreparePreviewString =
1395fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                getResources().getString(R.string.pano_dialog_prepare_preview);
1405fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mGeneratePanoramaString =
1415fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                getResources().getString(R.string.pano_dialog_generate_panorama);
1425fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
143f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kong        Context context = getApplicationContext();
144f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kong        mSlideIn = AnimationUtils.loadAnimation(context, R.anim.slide_in_from_right);
145f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kong        mSlideOut = AnimationUtils.loadAnimation(context, R.anim.slide_out_to_right);
146f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kong
147ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        mMainHandler = new Handler() {
148ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            @Override
149ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            public void handleMessage(Message msg) {
150ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                switch (msg.what) {
151ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                    case MSG_FINAL_MOSAIC_READY:
1525fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                        onBackgroundThreadFinished();
153142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        showFinalMosaic((Bitmap) msg.obj);
154142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
155142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                    case MSG_RESET_TO_PREVIEW:
1565fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                        onBackgroundThreadFinished();
157142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        resetToPreview();
158142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
159ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                }
160142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                clearMosaicFrameProcessorIfNeeded();
161ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            }
162ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        };
163bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
164bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
165bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCamera() {
166bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        openCamera();
167bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Parameters parameters = mCameraDevice.getParameters();
168bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setupCaptureParams(parameters);
169bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        configureCamera(parameters);
170bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
171bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
172ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private void releaseCamera() {
173ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        if (mCameraDevice != null) {
174142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mCameraDevice.setPreviewCallbackWithBuffer(null);
175ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            CameraHolder.instance().release();
176ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            mCameraDevice = null;
17798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraState = PREVIEW_STOPPED;
178ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        }
179ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    }
180ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong
181bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void openCamera() {
182bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        try {
183bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId());
184bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        } catch (CameraHardwareException e) {
185bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Util.showErrorAndFinish(this, R.string.cannot_connect_camera);
186bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            return;
187bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        } catch (CameraDisabledException e) {
188bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Util.showErrorAndFinish(this, R.string.camera_disabled);
189bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            return;
190bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
191bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
192bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
193bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3,
194bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            boolean needSmaller) {
195bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int pixelsDiff = DEFAULT_CAPTURE_PIXELS;
196bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        boolean hasFound = false;
1978a2c41754655a3733175fce81fb7506ff7022959Angus Kong        for (Size size : supportedSizes) {
198bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int h = size.height;
199bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int w = size.width;
200bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            // we only want 4:3 format.
201bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int d = DEFAULT_CAPTURE_PIXELS - h * w;
20294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            if (needSmaller && d < 0) { // no bigger preview than 960x720.
203bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
204bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
205bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (need4To3 && (h * 4 != w * 3)) {
206bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
207bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
208bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            d = Math.abs(d);
209bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (d < pixelsDiff) {
210bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewWidth = w;
211bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewHeight = h;
212bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                pixelsDiff = d;
213bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                hasFound = true;
214bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
215bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
216bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return hasFound;
217bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
218bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
219bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCaptureParams(Parameters parameters) {
220bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
221bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (!findBestPreviewSize(supportedSizes, true, true)) {
222bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Log.w(TAG, "No 4:3 ratio preview size supported.");
223bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (!findBestPreviewSize(supportedSizes, false, true)) {
224bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                Log.w(TAG, "Can't find a supported preview size smaller than 960x720.");
225bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                findBestPreviewSize(supportedSizes, false, false);
226bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
227bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
228bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth);
229bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewSize(mPreviewWidth, mPreviewHeight);
230bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
231bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<int[]> frameRates = parameters.getSupportedPreviewFpsRange();
232bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int last = frameRates.size() - 1;
233bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX];
234bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX];
235bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewFpsRange(minFps, maxFps);
236bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview fps: " + minFps + ", " + maxFps);
2373ab4f0912da83f7f5f8266a57a606d521c1649e3Wu-cheng Li
23893ad273a53e7d2975a67d7d1f8a157f845e41cf2Wu-cheng Li        parameters.setRecordingHint(false);
23943b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen
24043b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        mHorizontalViewAngle = parameters.getHorizontalViewAngle();
24143b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        mVerticalViewAngle = parameters.getVerticalViewAngle();
242bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
243bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
244bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public int getPreviewBufSize() {
245bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat pixelInfo = new PixelFormat();
246bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo);
247bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        // TODO: remove this extra 32 byte after the driver bug is fixed.
248bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32;
249bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
250bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
251bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void configureCamera(Parameters parameters) {
252bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCameraDevice.setParameters(parameters);
253bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
2544b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        int orientation = Util.getDisplayOrientation(Util.getDisplayRotation(this),
2554b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li                CameraHolder.instance().getBackCameraId());
2564b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li        mCameraDevice.setDisplayOrientation(orientation);
257bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
258bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
259a72d73cbac59db43d413291e4db66763be08143arepo sync    private boolean switchToOtherMode(int mode) {
260a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        if (isFinishing()) {
26194f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            return false;
262a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        }
263a72d73cbac59db43d413291e4db66763be08143arepo sync        MenuHelper.gotoMode(mode, this);
264a72d73cbac59db43d413291e4db66763be08143arepo sync        finish();
265a72d73cbac59db43d413291e4db66763be08143arepo sync        return true;
266a72d73cbac59db43d413291e4db66763be08143arepo sync    }
267a72d73cbac59db43d413291e4db66763be08143arepo sync
268a72d73cbac59db43d413291e4db66763be08143arepo sync    public boolean onModeChanged(int mode) {
269a72d73cbac59db43d413291e4db66763be08143arepo sync        if (mode != ModePicker.MODE_PANORAMA) {
270a72d73cbac59db43d413291e4db66763be08143arepo sync            return switchToOtherMode(mode);
271a72d73cbac59db43d413291e4db66763be08143arepo sync        } else {
272a72d73cbac59db43d413291e4db66763be08143arepo sync            return true;
273a72d73cbac59db43d413291e4db66763be08143arepo sync        }
274a72d73cbac59db43d413291e4db66763be08143arepo sync    }
275a72d73cbac59db43d413291e4db66763be08143arepo sync
2762faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    @Override
2772faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    public void onMosaicSurfaceCreated(final int textureID) {
27836839102e03107e3fb121197036365a58ec2686eAngus Kong        runOnUiThread(new Runnable() {
27936839102e03107e3fb121197036365a58ec2686eAngus Kong            @Override
28036839102e03107e3fb121197036365a58ec2686eAngus Kong            public void run() {
2812faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                if (mSurfaceTexture != null) {
2822faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                    mSurfaceTexture.release();
2832faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                }
2842faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture = new SurfaceTexture(textureID);
2852faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                if (!mPausing) {
2862faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                    mSurfaceTexture.setOnFrameAvailableListener(PanoramaActivity.this);
2872faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                    startCameraPreview();
2882faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                }
28936839102e03107e3fb121197036365a58ec2686eAngus Kong            }
29036839102e03107e3fb121197036365a58ec2686eAngus Kong        });
29136839102e03107e3fb121197036365a58ec2686eAngus Kong    }
29236839102e03107e3fb121197036365a58ec2686eAngus Kong
29341a2e9735136f372de95652d0828600282c8e967mbansal    public void runViewFinder() {
2942faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setWarping(false);
2952faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Call preprocess to render it to low-res and high-res RGB textures.
2962faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.preprocess(mTransformMatrix);
2972faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setReady();
2982faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.requestRender();
29941a2e9735136f372de95652d0828600282c8e967mbansal    }
30041a2e9735136f372de95652d0828600282c8e967mbansal
30141a2e9735136f372de95652d0828600282c8e967mbansal    public void runMosaicCapture() {
3022faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setWarping(true);
3032faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Call preprocess to render it to low-res and high-res RGB textures.
3042faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.preprocess(mTransformMatrix);
3052faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Lock the conditional variable to ensure the order of transferGPUtoCPU and
3062faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // mMosaicFrame.processFrame().
3072faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.lockPreviewReadyFlag();
30841a2e9735136f372de95652d0828600282c8e967mbansal        // Now, transfer the textures from GPU to CPU memory for processing
3092faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.transferGPUtoCPU();
31041a2e9735136f372de95652d0828600282c8e967mbansal        // Wait on the condition variable (will be opened when GPU->CPU transfer is done).
3112faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.waitUntilPreviewReady();
3120adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen        mMosaicFrameProcessor.processFrame();
31341a2e9735136f372de95652d0828600282c8e967mbansal    }
31441a2e9735136f372de95652d0828600282c8e967mbansal
315739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    public synchronized void onFrameAvailable(SurfaceTexture surface) {
3164d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong        /* This function may be called by some random thread,
31741a2e9735136f372de95652d0828600282c8e967mbansal         * so let's be safe and use synchronize. No OpenGL calls can be done here.
31841a2e9735136f372de95652d0828600282c8e967mbansal         */
3192faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Updating the texture should be done in the GL thread which mMosaicView is attached.
3202faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.queueEvent(new Runnable() {
3212faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            @Override
3222faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            public void run() {
3232faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture.updateTexImage();
3242faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture.getTransformMatrix(mTransformMatrix);
3252faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            }
3262faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        });
3272faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Update the transformation matrix for mosaic pre-process.
32841a2e9735136f372de95652d0828600282c8e967mbansal        if (mCaptureState == CAPTURE_VIEWFINDER) {
32941a2e9735136f372de95652d0828600282c8e967mbansal            runViewFinder();
33041a2e9735136f372de95652d0828600282c8e967mbansal        } else {
33141a2e9735136f372de95652d0828600282c8e967mbansal            runMosaicCapture();
33241a2e9735136f372de95652d0828600282c8e967mbansal        }
33341a2e9735136f372de95652d0828600282c8e967mbansal    }
33441a2e9735136f372de95652d0828600282c8e967mbansal
335a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    public void startCapture() {
3368a2c41754655a3733175fce81fb7506ff7022959Angus Kong        // Reset values so we can do this again.
3378a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mTimeTaken = System.currentTimeMillis();
33841a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_MOSAIC;
339fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong        mTooFastPrompt.setVisibility(View.GONE);
3408a2c41754655a3733175fce81fb7506ff7022959Angus Kong
3418a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() {
3428a2c41754655a3733175fce81fb7506ff7022959Angus Kong            @Override
34343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen            public void onProgress(boolean isFinished, float panningRateX, float panningRateY,
34443b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen                    int traversedAngleX, int traversedAngleY) {
3458a2c41754655a3733175fce81fb7506ff7022959Angus Kong                if (isFinished) {
346a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong                    stopCapture();
3478a2c41754655a3733175fce81fb7506ff7022959Angus Kong                } else {
34843b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen                    updateProgress(panningRateX, panningRateY, traversedAngleX, traversedAngleY);
3498a2c41754655a3733175fce81fb7506ff7022959Angus Kong                }
3508a2c41754655a3733175fce81fb7506ff7022959Angus Kong            }
3518a2c41754655a3733175fce81fb7506ff7022959Angus Kong        });
3528a2c41754655a3733175fce81fb7506ff7022959Angus Kong
35360fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mStopCaptureButton.setVisibility(View.VISIBLE);
3545af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mCaptureView.setVisibility(View.VISIBLE);
3552faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setVisibility(View.VISIBLE);
356f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kong        mPanoControlLayout.startAnimation(mSlideOut);
357a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mPanoControlLayout.setVisibility(View.GONE);
35841a2e9735136f372de95652d0828600282c8e967mbansal
3598a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
3608a2c41754655a3733175fce81fb7506ff7022959Angus Kong
361a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private void stopCapture() {
36241a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
36341a2e9735136f372de95652d0828600282c8e967mbansal
3648a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(null);
36536839102e03107e3fb121197036365a58ec2686eAngus Kong        stopCameraPreview();
36641a2e9735136f372de95652d0828600282c8e967mbansal
3672faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mSurfaceTexture.setOnFrameAvailableListener(null);
36841a2e9735136f372de95652d0828600282c8e967mbansal
369ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        // TODO: show some dialog for long computation.
370142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (!mThreadRunning) {
3715fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong            runBackgroundThread(mPreparePreviewString, new Thread() {
372142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                @Override
373142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                public void run() {
374ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    byte[] jpegData = generateFinalMosaic(false);
375ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    Bitmap bitmap = null;
376ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    if (jpegData != null) {
377ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                        bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
378ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    }
379ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    mMainHandler.sendMessage(mMainHandler.obtainMessage(
380ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                            MSG_FINAL_MOSAIC_READY, bitmap));
381142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                }
3825fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong            });
38350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            reportProgress(false);
384142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
3858a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
3868a2c41754655a3733175fce81fb7506ff7022959Angus Kong
38743b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    private void updateProgress(float panningRateX, float panningRateY,
38843b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen            int traversedAngleX, int traversedAngleY) {
389eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
3902faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setReady();
3912faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.requestRender();
392eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
39343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // TODO: Now we just display warning message by the panning speed.
39443b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // Since we only support horizontal panning, we should display a warning message
39543b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // in UI when there're significant vertical movements.
39643b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        if ((panningRateX * mHorizontalViewAngle > PANNING_SPEED_THRESHOLD)
39743b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen                || (panningRateY * mVerticalViewAngle > PANNING_SPEED_THRESHOLD)) {
398fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong            // TODO: draw speed indication according to the UI spec.
399fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong            mTooFastPrompt.setVisibility(View.VISIBLE);
40094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1);
4018a2c41754655a3733175fce81fb7506ff7022959Angus Kong            mCaptureView.invalidate();
4028a2c41754655a3733175fce81fb7506ff7022959Angus Kong        } else {
403fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong            mTooFastPrompt.setVisibility(View.GONE);
40494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1);
4058a2c41754655a3733175fce81fb7506ff7022959Angus Kong            mCaptureView.invalidate();
4068a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
4078a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
4088a2c41754655a3733175fce81fb7506ff7022959Angus Kong
409bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void createContentView() {
410bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setContentView(R.layout.panorama);
411bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
41241a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
41341a2e9735136f372de95652d0828600282c8e967mbansal
414a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mCaptureLayout = (View) findViewById(R.id.pano_capture_layout);
415bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCaptureView = (CaptureView) findViewById(R.id.pano_capture_view);
416bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCaptureView.setStartAngle(-DEFAULT_SWEEP_ANGLE / 2);
4175af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mStopCaptureButton = (Button) findViewById(R.id.pano_capture_stop_button);
418fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong        mTooFastPrompt = (TextView) findViewById(R.id.pano_capture_too_fast_textview);
419bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
4205af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mReviewLayout = (View) findViewById(R.id.pano_review_layout);
4215af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mReview = (ImageView) findViewById(R.id.pano_reviewarea);
4222faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer);
4232faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.getRenderer().setMosaicSurfaceCreateListener(this);
4242faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setVisibility(View.VISIBLE);
425eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
426a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mPanoControlLayout = (View) findViewById(R.id.pano_control_layout);
427a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker = (ModePicker) findViewById(R.id.mode_picker);
428a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setVisibility(View.VISIBLE);
429a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setOnModeChangeListener(this);
430a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA);
431bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
432bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
433142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    @OnClickAttr
434739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    public void onStartButtonClicked(View v) {
4352faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // If mSurfaceTexture == null then GL setup is not finished yet.
4362faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // No buttons can be pressed.
4372faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        if (mPausing || mThreadRunning || mSurfaceTexture == null) return;
438739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong        startCapture();
439739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    }
440739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong
441739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    @OnClickAttr
442142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    public void onStopButtonClicked(View v) {
4432faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        if (mPausing || mThreadRunning || mSurfaceTexture == null) return;
444142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        stopCapture();
445142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
446142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
44750b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal    public void reportProgress(final boolean highRes) {
44850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        Thread t = new Thread() {
44950b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            @Override
45050b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            public void run() {
45150b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                while(true)
45250b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                {
45350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    final int progress = mMosaicFrameProcessor.reportProgress(highRes);
45450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
45550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    try{
45650b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                        Thread.sleep(50);
45750b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    }catch(Exception e) {}
45850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
45950b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                     // Update the progress bar
46050b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    runOnUiThread(new Runnable() {
46150b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                        public void run() {
46250b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                            //TODO: Set the the progress-bar progress update here...
46350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                        }
46450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    });
46550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
46650b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    if(progress>=100)
46750b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                        break;
46850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                }
46950b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            }
47050b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        };
47150b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        t.start();
47250b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal    }
47350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
474142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    @OnClickAttr
475142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    public void onOkButtonClicked(View v) {
4762faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        if (mPausing || mThreadRunning || mSurfaceTexture == null) return;
4775fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        runBackgroundThread(mGeneratePanoramaString, new Thread() {
478142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            @Override
479142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            public void run() {
480ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                byte[] jpegData = generateFinalMosaic(true);
481ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                savePanorama(jpegData);
482ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                mMainHandler.sendMessage(mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW));
483142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            }
4845fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        });
48550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        reportProgress(true);
4865fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    }
4875fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
4885fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private void runBackgroundThread(String str, Thread thread) {
4895fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mThreadRunning = true;
4905fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mProgressDialog = ProgressDialog.show(this, "", str);
4915fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        thread.start();
4925fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    }
4935fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
4945fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private void onBackgroundThreadFinished() {
4955fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mThreadRunning = false;
4965fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mProgressDialog.dismiss();
4975fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mProgressDialog = null;
498142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
499142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
500142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    @OnClickAttr
501142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    public void onRetakeButtonClicked(View v) {
5022faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        if (mPausing || mThreadRunning || mSurfaceTexture == null) return;
503142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        resetToPreview();
504142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
505142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
506142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void resetToPreview() {
50741a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
50841a2e9735136f372de95652d0828600282c8e967mbansal
50941a2e9735136f372de95652d0828600282c8e967mbansal        mReviewLayout.setVisibility(View.GONE);
51060fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mStopCaptureButton.setVisibility(View.GONE);
5115af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mCaptureView.setVisibility(View.GONE);
512142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPanoControlLayout.setVisibility(View.VISIBLE);
513f26e1ab12cb3f359fe1d6efcbe65344a3a0bf276Angus Kong        mPanoControlLayout.startAnimation(mSlideIn);
51460fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mCaptureLayout.setVisibility(View.VISIBLE);
515142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.reset();
51641a2e9735136f372de95652d0828600282c8e967mbansal
5172faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mSurfaceTexture.setOnFrameAvailableListener(this);
51841a2e9735136f372de95652d0828600282c8e967mbansal
51936839102e03107e3fb121197036365a58ec2686eAngus Kong        if (!mPausing) startCameraPreview();
52041a2e9735136f372de95652d0828600282c8e967mbansal
5212faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setVisibility(View.VISIBLE);
522142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
523142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
524142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void showFinalMosaic(Bitmap bitmap) {
525142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (bitmap != null) {
526142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mReview.setImageBitmap(bitmap);
527142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
528ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureLayout.setVisibility(View.GONE);
529ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mReviewLayout.setVisibility(View.VISIBLE);
530ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureView.setSweepAngle(0);
531142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
532142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
533ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    private void savePanorama(byte[] jpegData) {
534ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (jpegData != null) {
535ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            String imagePath = PanoUtil.createName(
536ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    getResources().getString(R.string.pano_file_name_format), mTimeTaken);
537ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null, 0,
538ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    jpegData);
539142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
540142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
541142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
542142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void clearMosaicFrameProcessorIfNeeded() {
543142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (!mPausing || mThreadRunning) return;
544142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.clear();
545142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
546142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
547142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void initMosaicFrameProcessorIfNeeded() {
548142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mPausing || mThreadRunning) return;
549142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mMosaicFrameProcessor == null) {
550142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            // Start the activity for the first time.
551142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mMosaicFrameProcessor = new MosaicFrameProcessor(DEFAULT_SWEEP_ANGLE - 5,
5520adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen                    mPreviewWidth, mPreviewHeight, getPreviewBufSize());
553142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
554142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.initialize();
555bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
556bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
557bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
558bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    protected void onPause() {
559bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onPause();
5604d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong
561bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        releaseCamera();
562142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = true;
5632faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.onPause();
56494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen        mSensorManager.unregisterListener(mListener);
565142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        clearMosaicFrameProcessorIfNeeded();
56694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen        System.gc();
567bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
568bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
569bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
570bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    protected void onResume() {
571bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onResume();
572bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
573142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = false;
574bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        /*
57594f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * It is not necessary to get accelerometer events at a very high rate,
57694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * by using a slower rate (SENSOR_DELAY_UI), we get an automatic
57794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * low-pass filter, which "extracts" the gravity component of the
57894f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * acceleration. As an added benefit, we use less power and CPU
57994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * resources.
580bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen         */
581bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI);
58241a2e9735136f372de95652d0828600282c8e967mbansal        mCaptureState = CAPTURE_VIEWFINDER;
583bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setupCamera();
5844d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong        if (mSurfaceTexture != null) {
5854d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong            mSurfaceTexture.setOnFrameAvailableListener(this);
5864d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong            startCameraPreview();
5874d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong        }
588142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        // Camera must be initialized before MosaicFrameProcessor is initialized. The preview size
589142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        // has to be decided by camera device.
590142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        initMosaicFrameProcessorIfNeeded();
5912faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.onResume();
592bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
593bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
594bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private final SensorEventListener mListener = new SensorEventListener() {
595bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mCompassCurrX; // degrees
596bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mCompassCurrY; // degrees
597bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        private float mTimestamp;
598bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
599bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        public void onSensorChanged(SensorEvent event) {
600bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
601bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                if (mTimestamp != 0) {
602bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    final float dT = (event.timestamp - mTimestamp) * NS2S;
603bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    mCompassCurrX += event.values[1] * dT * 180.0f / Math.PI;
604bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    mCompassCurrY += event.values[0] * dT * 180.0f / Math.PI;
605bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                }
606bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mTimestamp = event.timestamp;
607bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
608bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) {
609bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mCompassCurrX = event.values[0];
610bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mCompassCurrY = event.values[1];
611bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
612bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
6138a2c41754655a3733175fce81fb7506ff7022959Angus Kong            if (mMosaicFrameProcessor != null) {
6148a2c41754655a3733175fce81fb7506ff7022959Angus Kong                mMosaicFrameProcessor.updateCompassValue(mCompassCurrX, mCompassCurrY);
615bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
616bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
617bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
618bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        @Override
619bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        public void onAccuracyChanged(Sensor sensor, int accuracy) {
620bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
621bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    };
622bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
623ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    public byte[] generateFinalMosaic(boolean highRes) {
6248a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.createMosaic(highRes);
625bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
626ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21();
627ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (imageData == null) {
628ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "getFinalMosaicNV21() returned null.");
629ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            return null;
6308a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
6318a2c41754655a3733175fce81fb7506ff7022959Angus Kong
632ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int len = imageData.length - 8;
633ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16)
634ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF);
635ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16)
636ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF);
637ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height);
6388a2c41754655a3733175fce81fb7506ff7022959Angus Kong
639e46486104523760a4433f03e09ed615987d83b6cAngus Kong        if (width <= 0 || height <= 0) {
640e46486104523760a4433f03e09ed615987d83b6cAngus Kong            // TODO: pop up a error meesage indicating that the final result is not generated.
641e46486104523760a4433f03e09ed615987d83b6cAngus Kong            Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " +
642e46486104523760a4433f03e09ed615987d83b6cAngus Kong                    height);
643e46486104523760a4433f03e09ed615987d83b6cAngus Kong            return null;
644e46486104523760a4433f03e09ed615987d83b6cAngus Kong        }
645e46486104523760a4433f03e09ed615987d83b6cAngus Kong
646ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
647ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        ByteArrayOutputStream out = new ByteArrayOutputStream();
648ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out);
649ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        try {
650ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            out.close();
651ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        } catch (Exception e) {
652ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "Exception in storing final mosaic", e);
653ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            return null;
654ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        }
655ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        return out.toByteArray();
656bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
6578a2c41754655a3733175fce81fb7506ff7022959Angus Kong
65841a2e9735136f372de95652d0828600282c8e967mbansal    private void setPreviewTexture(SurfaceTexture surface) {
65998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
66041a2e9735136f372de95652d0828600282c8e967mbansal            mCameraDevice.setPreviewTexture(surface);
66198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
66298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
66341a2e9735136f372de95652d0828600282c8e967mbansal            throw new RuntimeException("setPreviewTexture failed", ex);
66498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
66598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
66698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
66736839102e03107e3fb121197036365a58ec2686eAngus Kong    private void startCameraPreview() {
66898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // If we're previewing already, stop the preview first (this will blank
66998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // the screen).
67036839102e03107e3fb121197036365a58ec2686eAngus Kong        if (mCameraState != PREVIEW_STOPPED) stopCameraPreview();
67198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
6722faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        setPreviewTexture(mSurfaceTexture);
67398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
67498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
67598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "startPreview");
67698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.startPreview();
67798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
67898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
67998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            throw new RuntimeException("startPreview failed", ex);
68098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
68198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_ACTIVE;
68298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
68398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
68436839102e03107e3fb121197036365a58ec2686eAngus Kong    private void stopCameraPreview() {
68598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
68698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "stopPreview");
68798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.stopPreview();
68898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
68998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_STOPPED;
69098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
691bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen}
692