PanoramaActivity.java revision 9a7cba43937e7c74ebd9778bca40afc89145e3e1
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
195f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wangimport com.android.camera.ActivityBase;
20d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraDisabledException;
21d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraHardwareException;
22d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraHolder;
23a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.Exif;
24d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.MenuHelper;
25d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.ModePicker;
26a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.OnClickAttr;
27d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.R;
28fcdf619d92701052621a96572d956d047e07cf24Angus Kongimport com.android.camera.ShutterButton;
29d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Storage;
30a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.Thumbnail;
31d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Util;
32a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.ui.RotateImageView;
33a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.ui.SharePopup;
34d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Li
35b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kongimport android.animation.AnimatorSet;
362f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kongimport android.animation.ObjectAnimator;
37b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kongimport android.animation.ValueAnimator;
38bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.app.Activity;
3922d4b7fbace56c03092eb088a4df98e04a6681afAngus Kongimport android.app.AlertDialog;
405fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kongimport android.app.ProgressDialog;
419a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagnerimport android.content.ContentResolver;
42bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.content.Context;
4322d4b7fbace56c03092eb088a4df98e04a6681afAngus Kongimport android.content.DialogInterface;
44057040c0e19834d98719143c2627a9f0df3e4c35Angus Kongimport android.content.res.Resources;
45142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.Bitmap;
46142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.BitmapFactory;
478a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.ImageFormat;
48bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.graphics.PixelFormat;
498a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.Rect;
5041a2e9735136f372de95652d0828600282c8e967mbansalimport android.graphics.SurfaceTexture;
518a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.YuvImage;
528a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.hardware.Camera;
536f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kongimport android.hardware.Camera.Parameters;
546f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kongimport android.hardware.Camera.Size;
55bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.Sensor;
56bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorEvent;
57bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorEventListener;
58bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorManager;
59a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport android.net.Uri;
60bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.os.Bundle;
618a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.os.Handler;
62ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport android.os.Message;
63bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.util.Log;
64a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport android.view.Gravity;
65c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kongimport android.view.Menu;
66c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kongimport android.view.OrientationEventListener;
67bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.View;
68a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chenimport android.view.Window;
69bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.WindowManager;
70b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kongimport android.view.animation.LinearInterpolator;
71bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.widget.ImageView;
72fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kongimport android.widget.TextView;
73bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
74ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport java.io.ByteArrayOutputStream;
759a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagnerimport java.io.File;
76bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport java.util.List;
77bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
78a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong/**
79a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong * Activity to handle panorama capturing.
80a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong */
815f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wangpublic class PanoramaActivity extends ActivityBase implements
82fcdf619d92701052621a96572d956d047e07cf24Angus Kong        ModePicker.OnModeChangeListener, SurfaceTexture.OnFrameAvailableListener,
83fcdf619d92701052621a96572d956d047e07cf24Angus Kong        ShutterButton.OnShutterButtonListener,
8436839102e03107e3fb121197036365a58ec2686eAngus Kong        MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener {
85ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    public static final int DEFAULT_SWEEP_ANGLE = 160;
86bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL;
87bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720;
88bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
892f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong    private static final int MSG_LOW_RES_FINAL_MOSAIC_READY = 1;
90a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private static final int MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL = 2;
9122d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong    private static final int MSG_GENERATE_FINAL_MOSAIC_ERROR = 3;
9259a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong    private static final int MSG_RESET_TO_PREVIEW = 4;
9394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen
94ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private static final String TAG = "PanoramaActivity";
9598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_STOPPED = 0;
9698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_ACTIVE = 1;
97a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong    private static final int CAPTURE_STATE_VIEWFINDER = 0;
98a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong    private static final int CAPTURE_STATE_MOSAIC = 1;
9941a2e9735136f372de95652d0828600282c8e967mbansal
10043b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    // Speed is in unit of deg/sec
101e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen    private static final float PANNING_SPEED_THRESHOLD = 20f;
10243b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen
103a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    // Ratio of nanosecond to second
104a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private static final float NS2S = 1.0f / 1000000000.0f;
105142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
106142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mPausing;
107142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
1087648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li    private View mPanoLayout;
109a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mCaptureLayout;
110a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mReviewLayout;
111bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private ImageView mReview;
1128df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong    private TextView mCaptureIndicator;
113057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong    private PanoProgressBar mPanoProgressBar;
114215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    private PanoProgressBar mSavingProgressBar;
1158b0e23544474480345937c0c0985429f61569761Angus Kong    private View mFastIndicationBorder;
1166108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    private View mLeftIndicator;
1176108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    private View mRightIndicator;
1182faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private MosaicRendererSurfaceView mMosaicView;
119fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong    private TextView mTooFastPrompt;
120fcdf619d92701052621a96572d956d047e07cf24Angus Kong    private ShutterButton mShutterButton;
121215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    private Object mWaitObject = new Object();
122142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
1235fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private String mPreparePreviewString;
1242f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong    private AlertDialog mAlertDialog;
125215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    private ProgressDialog mProgressDialog;
12622d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong    private String mDialogTitle;
12722d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong    private String mDialogOk;
1282f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong
129fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong    private int mIndicatorColor;
130fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong    private int mIndicatorColorFast;
131fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong
132c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueX;
133c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueY;
134c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueXStart;
135c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueYStart;
136c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueXStartBuffer;
137c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueYStartBuffer;
138c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mCompassThreshold;
139c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mTraversedAngleX;
140c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mTraversedAngleY;
141c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private long mTimestamp;
142c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    // Control variables for the terminate condition.
143c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mMinAngleX;
144c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mMaxAngleX;
145c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mMinAngleY;
146c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mMaxAngleY;
147c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
148a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private RotateImageView mThumbnailView;
149a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private Thumbnail mThumbnail;
150a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private SharePopup mSharePopup;
151a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong
152b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong    private AnimatorSet mThumbnailViewAndModePickerOut;
153b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong    private AnimatorSet mThumbnailViewAndModePickerIn;
154b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong
155bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewWidth;
156bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewHeight;
1578a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private Camera mCameraDevice;
15898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private int mCameraState;
15941a2e9735136f372de95652d0828600282c8e967mbansal    private int mCaptureState;
160bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private SensorManager mSensorManager;
161bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private Sensor mSensor;
162a72d73cbac59db43d413291e4db66763be08143arepo sync    private ModePicker mModePicker;
1638a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private MosaicFrameProcessor mMosaicFrameProcessor;
1648a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private long mTimeTaken;
165ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private Handler mMainHandler;
1662faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private SurfaceTexture mSurfaceTexture;
167142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mThreadRunning;
168e1178a73fd5756771d25d0b8375452450f509e99mbansal    private boolean mCancelComputation;
1692faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private float[] mTransformMatrix;
17043b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    private float mHorizontalViewAngle;
171c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
172d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen    // Prefer FOCUS_MODE_INFINITY to FOCUS_MODE_CONTINUOUS_VIDEO because of
173d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen    // getting a better image quality by the former.
174d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen    private String mTargetFocusMode = Parameters.FOCUS_MODE_INFINITY;
175d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen
176c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private PanoOrientationEventListener mOrientationEventListener;
177c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    // The value could be 0, 1, 2, 3 for the 4 different orientations measured in clockwise
178c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    // respectively.
179c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mDeviceOrientation;
180142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
1817648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li    private class MosaicJpeg {
1827648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        public MosaicJpeg(byte[] data, int width, int height) {
1837648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li            this.data = data;
1847648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li            this.width = width;
1857648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li            this.height = height;
18613e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.isValid = true;
18713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        }
18813e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong
18913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        public MosaicJpeg() {
19013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.data = null;
19113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.width = 0;
19213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.height = 0;
19313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.isValid = false;
1947648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        }
1957648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li
1967648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        public final byte[] data;
1977648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        public final int width;
1987648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        public final int height;
19913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        public final boolean isValid;
2007648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li    }
2017648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li
202c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private class PanoOrientationEventListener extends OrientationEventListener {
203c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        public PanoOrientationEventListener(Context context) {
204c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            super(context);
205c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        }
206c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
207c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        @Override
208c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        public void onOrientationChanged(int orientation) {
209c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            // Default to the last known orientation.
210c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            if (orientation == ORIENTATION_UNKNOWN) return;
211c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            mDeviceOrientation = ((orientation + 45) / 90) % 4;
212c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        }
213c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    }
214c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
215bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
216c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    public boolean onCreateOptionsMenu(Menu menu) {
217c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        super.onCreateOptionsMenu(menu);
218c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong
219c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        addBaseMenuItems(menu);
220c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        return true;
221c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    }
222c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong
223c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    private void addBaseMenuItems(Menu menu) {
224c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        MenuHelper.addSwitchModeMenuItem(menu, ModePicker.MODE_CAMERA, new Runnable() {
225c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong            public void run() {
226c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong                switchToOtherMode(ModePicker.MODE_CAMERA);
227c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong            }
228c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        });
229c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        MenuHelper.addSwitchModeMenuItem(menu, ModePicker.MODE_VIDEO, new Runnable() {
230c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong            public void run() {
231c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong                switchToOtherMode(ModePicker.MODE_VIDEO);
232c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong            }
233c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        });
234c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    }
235c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong
236c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    @Override
237bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public void onCreate(Bundle icicle) {
238bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onCreate(icicle);
239bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
240a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        Window window = getWindow();
241a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        window.setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
242bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
243a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        Util.enterLightsOutMode(window);
244a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        Util.initializeScreenBrightness(window, getContentResolver());
245bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
246bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        createContentView();
247bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
248bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
249bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
250bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (mSensor == null) {
251bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
252bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
2538a2c41754655a3733175fce81fb7506ff7022959Angus Kong
254c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mOrientationEventListener = new PanoOrientationEventListener(this);
255c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
2562faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mTransformMatrix = new float[16];
2572faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong
2585fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mPreparePreviewString =
2595fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                getResources().getString(R.string.pano_dialog_prepare_preview);
26022d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong        mDialogTitle = getResources().getString(R.string.pano_dialog_title);
26122d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong        mDialogOk = getResources().getString(R.string.dialog_ok);
2625fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
263ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        mMainHandler = new Handler() {
264ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            @Override
265ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            public void handleMessage(Message msg) {
266ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                switch (msg.what) {
2672f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong                    case MSG_LOW_RES_FINAL_MOSAIC_READY:
2685fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                        onBackgroundThreadFinished();
269142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        showFinalMosaic((Bitmap) msg.obj);
270215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                        saveHighResMosaic();
271142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
272a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong                    case MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL:
2735fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                        onBackgroundThreadFinished();
274a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong                        // Set the thumbnail bitmap here because mThumbnailView must be accessed
275a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong                        // from the UI thread.
2769a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner                        updateThumbnailButton();
2779a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner
278db288b8686e5bcecef620176b934b00eb0742597Wu-cheng Li                        // Share popup may still have the reference to the old thumbnail. Clear it.
279db288b8686e5bcecef620176b934b00eb0742597Wu-cheng Li                        mSharePopup = null;
280142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        resetToPreview();
281142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
28222d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                    case MSG_GENERATE_FINAL_MOSAIC_ERROR:
28322d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                        onBackgroundThreadFinished();
2843eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                        if (mPausing) {
2853eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                            resetToPreview();
2863eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                        } else {
2873eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                            mAlertDialog.show();
2883eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                        }
28922d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                        break;
29013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    case MSG_RESET_TO_PREVIEW:
291e1178a73fd5756771d25d0b8375452450f509e99mbansal                        onBackgroundThreadFinished();
292e1178a73fd5756771d25d0b8375452450f509e99mbansal                        resetToPreview();
293ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                }
294142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                clearMosaicFrameProcessorIfNeeded();
295ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            }
296ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        };
29759a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong
29859a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong        mAlertDialog = (new AlertDialog.Builder(this))
29959a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                .setTitle(mDialogTitle)
30059a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                .setMessage(R.string.pano_dialog_panorama_failed)
30159a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                .create();
30259a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong        mAlertDialog.setCancelable(false);
30359a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong        mAlertDialog.setButton(DialogInterface.BUTTON_POSITIVE, mDialogOk,
30459a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                new DialogInterface.OnClickListener() {
30559a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                    @Override
30659a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                    public void onClick(DialogInterface dialog, int which) {
30759a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                        dialog.dismiss();
30859a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                        resetToPreview();
30959a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                    }
31059a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong                });
311bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
312bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
3139a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner    @Override
3149a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner    public void onStart() {
3159a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        super.onStart();
3169a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        updateThumbnailButton();
3179a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner    }
3189a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner
319bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCamera() {
320bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        openCamera();
321bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Parameters parameters = mCameraDevice.getParameters();
322bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setupCaptureParams(parameters);
323bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        configureCamera(parameters);
324bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
325bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
326ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private void releaseCamera() {
327ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        if (mCameraDevice != null) {
328142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mCameraDevice.setPreviewCallbackWithBuffer(null);
329ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            CameraHolder.instance().release();
330ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            mCameraDevice = null;
33198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraState = PREVIEW_STOPPED;
332ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        }
333ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    }
334ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong
335bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void openCamera() {
336bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        try {
337bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId());
338bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        } catch (CameraHardwareException e) {
339bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Util.showErrorAndFinish(this, R.string.cannot_connect_camera);
340bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            return;
341bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        } catch (CameraDisabledException e) {
342bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Util.showErrorAndFinish(this, R.string.camera_disabled);
343bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            return;
344bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
345bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
346bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
347bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3,
348bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            boolean needSmaller) {
349bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int pixelsDiff = DEFAULT_CAPTURE_PIXELS;
350bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        boolean hasFound = false;
3518a2c41754655a3733175fce81fb7506ff7022959Angus Kong        for (Size size : supportedSizes) {
352bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int h = size.height;
353bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int w = size.width;
354bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            // we only want 4:3 format.
355bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int d = DEFAULT_CAPTURE_PIXELS - h * w;
35694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            if (needSmaller && d < 0) { // no bigger preview than 960x720.
357bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
358bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
359bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (need4To3 && (h * 4 != w * 3)) {
360bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
361bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
362bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            d = Math.abs(d);
363bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (d < pixelsDiff) {
364bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewWidth = w;
365bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewHeight = h;
366bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                pixelsDiff = d;
367bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                hasFound = true;
368bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
369bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
370bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return hasFound;
371bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
372bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
373bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCaptureParams(Parameters parameters) {
374bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
375bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (!findBestPreviewSize(supportedSizes, true, true)) {
376bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Log.w(TAG, "No 4:3 ratio preview size supported.");
377bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (!findBestPreviewSize(supportedSizes, false, true)) {
378bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                Log.w(TAG, "Can't find a supported preview size smaller than 960x720.");
379bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                findBestPreviewSize(supportedSizes, false, false);
380bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
381bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
382bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth);
383bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewSize(mPreviewWidth, mPreviewHeight);
384bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
385bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<int[]> frameRates = parameters.getSupportedPreviewFpsRange();
386bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int last = frameRates.size() - 1;
387bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX];
388bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX];
389bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewFpsRange(minFps, maxFps);
390bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview fps: " + minFps + ", " + maxFps);
3913ab4f0912da83f7f5f8266a57a606d521c1649e3Wu-cheng Li
392d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen        List<String> supportedFocusModes = parameters.getSupportedFocusModes();
393d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen        if (supportedFocusModes.indexOf(mTargetFocusMode) >= 0) {
394d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen            parameters.setFocusMode(mTargetFocusMode);
395d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen        } else {
396d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen            // Use the default focus mode and log a message
397d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen            Log.w(TAG, "Cannot set the focus mode to " + mTargetFocusMode +
398d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen                  " becuase the mode is not supported.");
399d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen        }
400d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen
40193ad273a53e7d2975a67d7d1f8a157f845e41cf2Wu-cheng Li        parameters.setRecordingHint(false);
40243b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen
403c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mHorizontalViewAngle = ((mDeviceOrientation % 2) == 0) ?
404c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                parameters.getHorizontalViewAngle() : parameters.getVerticalViewAngle();
405bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
406bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
407bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public int getPreviewBufSize() {
408bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat pixelInfo = new PixelFormat();
409bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo);
410bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        // TODO: remove this extra 32 byte after the driver bug is fixed.
411bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32;
412bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
413bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
414bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void configureCamera(Parameters parameters) {
415bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCameraDevice.setParameters(parameters);
416bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
417bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
418a72d73cbac59db43d413291e4db66763be08143arepo sync    private boolean switchToOtherMode(int mode) {
419a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        if (isFinishing()) {
42094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            return false;
421a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        }
422a72d73cbac59db43d413291e4db66763be08143arepo sync        MenuHelper.gotoMode(mode, this);
423a72d73cbac59db43d413291e4db66763be08143arepo sync        finish();
424a72d73cbac59db43d413291e4db66763be08143arepo sync        return true;
425a72d73cbac59db43d413291e4db66763be08143arepo sync    }
426a72d73cbac59db43d413291e4db66763be08143arepo sync
427a72d73cbac59db43d413291e4db66763be08143arepo sync    public boolean onModeChanged(int mode) {
428a72d73cbac59db43d413291e4db66763be08143arepo sync        if (mode != ModePicker.MODE_PANORAMA) {
429a72d73cbac59db43d413291e4db66763be08143arepo sync            return switchToOtherMode(mode);
430a72d73cbac59db43d413291e4db66763be08143arepo sync        } else {
431a72d73cbac59db43d413291e4db66763be08143arepo sync            return true;
432a72d73cbac59db43d413291e4db66763be08143arepo sync        }
433a72d73cbac59db43d413291e4db66763be08143arepo sync    }
434a72d73cbac59db43d413291e4db66763be08143arepo sync
4352faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    @Override
436575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi    public void onMosaicSurfaceChanged() {
437575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi        runOnUiThread(new Runnable() {
438575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi            @Override
439575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi            public void run() {
440575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi                if (!mPausing) {
441575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi                    startCameraPreview();
442575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi                }
443575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi            }
444575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi        });
445575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi    }
446575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi
447575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi    @Override
4482faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    public void onMosaicSurfaceCreated(final int textureID) {
44936839102e03107e3fb121197036365a58ec2686eAngus Kong        runOnUiThread(new Runnable() {
45036839102e03107e3fb121197036365a58ec2686eAngus Kong            @Override
45136839102e03107e3fb121197036365a58ec2686eAngus Kong            public void run() {
4522faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                if (mSurfaceTexture != null) {
4532faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                    mSurfaceTexture.release();
4542faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                }
4552faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture = new SurfaceTexture(textureID);
4562faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                if (!mPausing) {
4572faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                    mSurfaceTexture.setOnFrameAvailableListener(PanoramaActivity.this);
4582faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                }
45936839102e03107e3fb121197036365a58ec2686eAngus Kong            }
46036839102e03107e3fb121197036365a58ec2686eAngus Kong        });
46136839102e03107e3fb121197036365a58ec2686eAngus Kong    }
46236839102e03107e3fb121197036365a58ec2686eAngus Kong
46341a2e9735136f372de95652d0828600282c8e967mbansal    public void runViewFinder() {
4642faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setWarping(false);
4652faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Call preprocess to render it to low-res and high-res RGB textures.
4662faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.preprocess(mTransformMatrix);
4672faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setReady();
4682faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.requestRender();
46941a2e9735136f372de95652d0828600282c8e967mbansal    }
47041a2e9735136f372de95652d0828600282c8e967mbansal
47141a2e9735136f372de95652d0828600282c8e967mbansal    public void runMosaicCapture() {
4722faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setWarping(true);
4732faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Call preprocess to render it to low-res and high-res RGB textures.
4742faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.preprocess(mTransformMatrix);
4752faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Lock the conditional variable to ensure the order of transferGPUtoCPU and
4762faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // mMosaicFrame.processFrame().
4772faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.lockPreviewReadyFlag();
47841a2e9735136f372de95652d0828600282c8e967mbansal        // Now, transfer the textures from GPU to CPU memory for processing
4792faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.transferGPUtoCPU();
48041a2e9735136f372de95652d0828600282c8e967mbansal        // Wait on the condition variable (will be opened when GPU->CPU transfer is done).
4812faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.waitUntilPreviewReady();
4820adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen        mMosaicFrameProcessor.processFrame();
48341a2e9735136f372de95652d0828600282c8e967mbansal    }
48441a2e9735136f372de95652d0828600282c8e967mbansal
485739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    public synchronized void onFrameAvailable(SurfaceTexture surface) {
4864d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong        /* This function may be called by some random thread,
48741a2e9735136f372de95652d0828600282c8e967mbansal         * so let's be safe and use synchronize. No OpenGL calls can be done here.
48841a2e9735136f372de95652d0828600282c8e967mbansal         */
4892faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Updating the texture should be done in the GL thread which mMosaicView is attached.
4902faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.queueEvent(new Runnable() {
4912faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            @Override
4922faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            public void run() {
4932faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture.updateTexImage();
4942faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture.getTransformMatrix(mTransformMatrix);
4952faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            }
4962faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        });
4972faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Update the transformation matrix for mosaic pre-process.
498a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        if (mCaptureState == CAPTURE_STATE_VIEWFINDER) {
49941a2e9735136f372de95652d0828600282c8e967mbansal            runViewFinder();
50041a2e9735136f372de95652d0828600282c8e967mbansal        } else {
50141a2e9735136f372de95652d0828600282c8e967mbansal            runMosaicCapture();
50241a2e9735136f372de95652d0828600282c8e967mbansal        }
50341a2e9735136f372de95652d0828600282c8e967mbansal    }
50441a2e9735136f372de95652d0828600282c8e967mbansal
5056108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    private void hideDirectionIndicators() {
5066108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mLeftIndicator.setVisibility(View.GONE);
5076108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mRightIndicator.setVisibility(View.GONE);
5086108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    }
5096108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong
5106108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    private void showDirectionIndicators(int direction) {
5116108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        switch (direction) {
5126108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong            case PanoProgressBar.DIRECTION_NONE:
5136108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mLeftIndicator.setVisibility(View.VISIBLE);
5146108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mRightIndicator.setVisibility(View.VISIBLE);
5156108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                break;
5166108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong            case PanoProgressBar.DIRECTION_LEFT:
5176108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mLeftIndicator.setVisibility(View.VISIBLE);
5186108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mRightIndicator.setVisibility(View.GONE);
5196108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                break;
5206108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong            case PanoProgressBar.DIRECTION_RIGHT:
5216108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mLeftIndicator.setVisibility(View.GONE);
5226108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mRightIndicator.setVisibility(View.VISIBLE);
5236108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                break;
5246108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        }
5256108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    }
5266108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong
527a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    public void startCapture() {
5288a2c41754655a3733175fce81fb7506ff7022959Angus Kong        // Reset values so we can do this again.
52913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        mCancelComputation = false;
5308a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mTimeTaken = System.currentTimeMillis();
531a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_MOSAIC;
532fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan_recording);
5338df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong        mCaptureIndicator.setVisibility(View.VISIBLE);
5346108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        showDirectionIndicators(PanoProgressBar.DIRECTION_NONE);
5358a2c41754655a3733175fce81fb7506ff7022959Angus Kong
536b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        // XML-style animations can not be used here. The Y position has to be calculated runtime.
537b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        float ystart = mThumbnailView.getY();
538b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        ValueAnimator va1 = ObjectAnimator.ofFloat(
539b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong                mThumbnailView, "y", ystart, -mThumbnailView.getHeight());
540b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        ValueAnimator va1Reverse = ObjectAnimator.ofFloat(
541b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong                mThumbnailView, "y", -mThumbnailView.getHeight(), ystart);
542b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        ystart = mModePicker.getY();
543b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        float height = mCaptureLayout.getHeight();
544b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        ValueAnimator va2 = ObjectAnimator.ofFloat(
545b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong                mModePicker, "y", ystart, height + 1);
546b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        ValueAnimator va2Reverse = ObjectAnimator.ofFloat(
547b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong                mModePicker, "y", height + 1, ystart);
548b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        LinearInterpolator li = new LinearInterpolator();
549b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerOut = new AnimatorSet();
550b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerOut.play(va1).with(va2);
551b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerOut.setDuration(500);
552b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerOut.setInterpolator(li);
553b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerIn = new AnimatorSet();
554b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerIn.play(va1Reverse).with(va2Reverse);
555b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerIn.setDuration(500);
556b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerIn.setInterpolator(li);
557b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong
558b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerOut.start();
559b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong
560c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mCompassValueXStart = mCompassValueXStartBuffer;
561c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mCompassValueYStart = mCompassValueYStartBuffer;
562c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mMinAngleX = 0;
563c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mMaxAngleX = 0;
564c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mMinAngleY = 0;
565c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mMaxAngleY = 0;
566c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mTimestamp = 0;
567c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
5688a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() {
5698a2c41754655a3733175fce81fb7506ff7022959Angus Kong            @Override
570c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            public void onProgress(boolean isFinished, float panningRateX, float panningRateY) {
571c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                if (isFinished
572c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                        || (mMaxAngleX - mMinAngleX >= DEFAULT_SWEEP_ANGLE)
573c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                        || (mMaxAngleY - mMinAngleY >= DEFAULT_SWEEP_ANGLE)) {
57427c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong                    stopCapture(false);
5758a2c41754655a3733175fce81fb7506ff7022959Angus Kong                } else {
576c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                    updateProgress(panningRateX);
5778a2c41754655a3733175fce81fb7506ff7022959Angus Kong                }
5788a2c41754655a3733175fce81fb7506ff7022959Angus Kong            }
5798a2c41754655a3733175fce81fb7506ff7022959Angus Kong        });
5808a2c41754655a3733175fce81fb7506ff7022959Angus Kong
581057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.reset();
582057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        // TODO: calculate the indicator width according to different devices to reflect the actual
583057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        // angle of view of the camera device.
584057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setIndicatorWidth(20);
585057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setMaxProgress(DEFAULT_SWEEP_ANGLE);
586057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setVisibility(View.VISIBLE);
5878a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
5888a2c41754655a3733175fce81fb7506ff7022959Angus Kong
58927c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong    private void stopCapture(boolean aborted) {
590a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_VIEWFINDER;
5918df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong        mCaptureIndicator.setVisibility(View.GONE);
5928b0e23544474480345937c0c0985429f61569761Angus Kong        hideTooFastIndication();
5936108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        hideDirectionIndicators();
59441a2e9735136f372de95652d0828600282c8e967mbansal
5958a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(null);
59636839102e03107e3fb121197036365a58ec2686eAngus Kong        stopCameraPreview();
59741a2e9735136f372de95652d0828600282c8e967mbansal
5982faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mSurfaceTexture.setOnFrameAvailableListener(null);
59941a2e9735136f372de95652d0828600282c8e967mbansal
60027c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        if (!aborted && !mThreadRunning) {
601215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong            showDialog(mPreparePreviewString);
602215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong            runBackgroundThread(new Thread() {
603142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                @Override
604142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                public void run() {
6057648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li                    MosaicJpeg jpeg = generateFinalMosaic(false);
606e1178a73fd5756771d25d0b8375452450f509e99mbansal
60713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    if (jpeg != null && jpeg.isValid) {
608e1178a73fd5756771d25d0b8375452450f509e99mbansal                        Bitmap bitmap = null;
60913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length);
610e1178a73fd5756771d25d0b8375452450f509e99mbansal                        mMainHandler.sendMessage(mMainHandler.obtainMessage(
611e1178a73fd5756771d25d0b8375452450f509e99mbansal                                MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap));
61213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    } else {
61313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        mMainHandler.sendMessage(mMainHandler.obtainMessage(
61413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                                MSG_RESET_TO_PREVIEW));
615ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    }
616142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                }
6175fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong            });
618142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
619b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong        mThumbnailViewAndModePickerIn.start();
6208a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
6218a2c41754655a3733175fce81fb7506ff7022959Angus Kong
6228b0e23544474480345937c0c0985429f61569761Angus Kong    private void showTooFastIndication() {
6238b0e23544474480345937c0c0985429f61569761Angus Kong        mTooFastPrompt.setVisibility(View.VISIBLE);
6248b0e23544474480345937c0c0985429f61569761Angus Kong        mFastIndicationBorder.setVisibility(View.VISIBLE);
625fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mPanoProgressBar.setIndicatorColor(mIndicatorColorFast);
6268b0e23544474480345937c0c0985429f61569761Angus Kong        mLeftIndicator.setEnabled(true);
6278b0e23544474480345937c0c0985429f61569761Angus Kong        mRightIndicator.setEnabled(true);
6288b0e23544474480345937c0c0985429f61569761Angus Kong    }
6298b0e23544474480345937c0c0985429f61569761Angus Kong
6308b0e23544474480345937c0c0985429f61569761Angus Kong    private void hideTooFastIndication() {
6318b0e23544474480345937c0c0985429f61569761Angus Kong        mTooFastPrompt.setVisibility(View.GONE);
6328b0e23544474480345937c0c0985429f61569761Angus Kong        mFastIndicationBorder.setVisibility(View.GONE);
633fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mPanoProgressBar.setIndicatorColor(mIndicatorColor);
6348b0e23544474480345937c0c0985429f61569761Angus Kong        mLeftIndicator.setEnabled(false);
6358b0e23544474480345937c0c0985429f61569761Angus Kong        mRightIndicator.setEnabled(false);
6368b0e23544474480345937c0c0985429f61569761Angus Kong    }
6378b0e23544474480345937c0c0985429f61569761Angus Kong
638c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private void updateProgress(float panningRate) {
6392faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setReady();
6402faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.requestRender();
641eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
64243b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // TODO: Now we just display warning message by the panning speed.
64343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // Since we only support horizontal panning, we should display a warning message
64443b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // in UI when there're significant vertical movements.
645c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        if (Math.abs(panningRate * mHorizontalViewAngle) > PANNING_SPEED_THRESHOLD) {
6468b0e23544474480345937c0c0985429f61569761Angus Kong            showTooFastIndication();
6478a2c41754655a3733175fce81fb7506ff7022959Angus Kong        } else {
6488b0e23544474480345937c0c0985429f61569761Angus Kong            hideTooFastIndication();
6498a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
6508a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
6518a2c41754655a3733175fce81fb7506ff7022959Angus Kong
652bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void createContentView() {
653bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setContentView(R.layout.panorama);
654bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
655a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_VIEWFINDER;
65641a2e9735136f372de95652d0828600282c8e967mbansal
657057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        Resources appRes = getResources();
658057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong
659a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mCaptureLayout = (View) findViewById(R.id.pano_capture_layout);
660215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mPanoProgressBar = (PanoProgressBar) findViewById(R.id.pano_pan_progress_bar);
661057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty));
662057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_done));
663fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mIndicatorColor = appRes.getColor(R.color.pano_progress_indication);
664fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mIndicatorColorFast = appRes.getColor(R.color.pano_progress_indication_fast);
665fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mPanoProgressBar.setIndicatorColor(mIndicatorColor);
6666108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mPanoProgressBar.setOnDirectionChangeListener(
6676108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                new PanoProgressBar.OnDirectionChangeListener () {
6686108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                    @Override
6696108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                    public void onDirectionChange(int direction) {
6706108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                        if (mCaptureState == CAPTURE_STATE_MOSAIC) {
6716108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                            showDirectionIndicators(direction);
6726108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                        }
6736108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                    }
6746108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                });
6756108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong
6766108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mLeftIndicator = (ImageView) findViewById(R.id.pano_pan_left_indicator);
6776108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mRightIndicator = (ImageView) findViewById(R.id.pano_pan_right_indicator);
6788b0e23544474480345937c0c0985429f61569761Angus Kong        mLeftIndicator.setEnabled(false);
6798b0e23544474480345937c0c0985429f61569761Angus Kong        mRightIndicator.setEnabled(false);
680fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong        mTooFastPrompt = (TextView) findViewById(R.id.pano_capture_too_fast_textview);
6818b0e23544474480345937c0c0985429f61569761Angus Kong        mFastIndicationBorder = (View) findViewById(R.id.pano_speed_indication_border);
682bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
683215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar = (PanoProgressBar) findViewById(R.id.pano_saving_progress_bar);
684215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setIndicatorWidth(0);
685215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setMaxProgress(100);
686215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty));
687215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_indication));
688215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong
6898df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong        mCaptureIndicator = (TextView) findViewById(R.id.pano_capture_indicator);
6908df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong
691a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        mThumbnailView = (RotateImageView) findViewById(R.id.thumbnail);
692a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong
6935af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mReviewLayout = (View) findViewById(R.id.pano_review_layout);
6945af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mReview = (ImageView) findViewById(R.id.pano_reviewarea);
6952faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer);
6962faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.getRenderer().setMosaicSurfaceCreateListener(this);
697eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
698a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker = (ModePicker) findViewById(R.id.mode_picker);
699a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setVisibility(View.VISIBLE);
700a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setOnModeChangeListener(this);
701a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA);
7027648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li
703fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton = (ShutterButton) findViewById(R.id.shutter_button);
704fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan);
705fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton.setOnShutterButtonListener(this);
706fcdf619d92701052621a96572d956d047e07cf24Angus Kong
7077648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        mPanoLayout = findViewById(R.id.pano_layout);
708bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
709bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
710fcdf619d92701052621a96572d956d047e07cf24Angus Kong    @Override
711fcdf619d92701052621a96572d956d047e07cf24Angus Kong    public void onShutterButtonClick(ShutterButton b) {
7122faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // If mSurfaceTexture == null then GL setup is not finished yet.
7132faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // No buttons can be pressed.
7142faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        if (mPausing || mThreadRunning || mSurfaceTexture == null) return;
715a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        // Since this button will stay on the screen when capturing, we need to check the state
716a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        // right now.
717fcdf619d92701052621a96572d956d047e07cf24Angus Kong        switch (mCaptureState) {
718fcdf619d92701052621a96572d956d047e07cf24Angus Kong            case CAPTURE_STATE_VIEWFINDER:
719fcdf619d92701052621a96572d956d047e07cf24Angus Kong                startCapture();
720fcdf619d92701052621a96572d956d047e07cf24Angus Kong                break;
721fcdf619d92701052621a96572d956d047e07cf24Angus Kong            case CAPTURE_STATE_MOSAIC:
72227c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong                stopCapture(false);
723a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        }
724739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    }
725739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong
726fcdf619d92701052621a96572d956d047e07cf24Angus Kong    @Override
727fcdf619d92701052621a96572d956d047e07cf24Angus Kong    public void onShutterButtonFocus(ShutterButton b, boolean pressed) {
728142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
729142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
730215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    public void reportProgress() {
731215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.reset();
732215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setRightIncreasing(true);
73350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        Thread t = new Thread() {
73450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            @Override
73550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            public void run() {
7366f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                while (mThreadRunning) {
737e1178a73fd5756771d25d0b8375452450f509e99mbansal                    final int progress = mMosaicFrameProcessor.reportProgress(
738215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                            true, mCancelComputation);
73950b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
7406f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                    try {
741215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                        synchronized (mWaitObject) {
742215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                            mWaitObject.wait(50);
743215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                        }
744215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                    } catch (InterruptedException e) {
7456f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                        throw new RuntimeException("Panorama reportProgress failed", e);
7466f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                    }
7476f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                    // Update the progress bar
74850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    runOnUiThread(new Runnable() {
74950b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                        public void run() {
750215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                            mSavingProgressBar.setProgress(progress);
75150b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                        }
75250b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    });
75350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                }
75450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            }
75550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        };
75650b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        t.start();
75750b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal    }
75850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
7599a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner    private void updateThumbnailButton() {
7609a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        // Update last image if URI is invalid and the storage is ready.
7619a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        ContentResolver contentResolver = getContentResolver();
7629a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        if ((mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), contentResolver))) {
7639a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner            mThumbnail = Thumbnail.getLastThumbnail(contentResolver);
7649a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        }
7659a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        if (mThumbnail != null) {
7669a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner            mThumbnailView.setBitmap(mThumbnail.getBitmap());
7679a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        } else {
7689a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner            mThumbnailView.setBitmap(null);
7699a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        }
7709a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner    }
7719a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner
772215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    public void saveHighResMosaic() {
773215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        runBackgroundThread(new Thread() {
774142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            @Override
775142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            public void run() {
7767648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li                MosaicJpeg jpeg = generateFinalMosaic(true);
777e1178a73fd5756771d25d0b8375452450f509e99mbansal
77813e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                if (jpeg == null) {  // Cancelled by user.
77913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    mMainHandler.sendEmptyMessage(MSG_RESET_TO_PREVIEW);
78013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                } else if (!jpeg.isValid) {  // Error when generating mosaic.
78113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR);
78222d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                } else {
78313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    int orientation = Exif.getOrientation(jpeg.data);
784ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong                    Uri uri = savePanorama(jpeg.data, jpeg.width, jpeg.height, orientation);
78513e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    if (uri != null) {
78613e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        // Create a thumbnail whose width is equal or bigger
78713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        // than the entire screen.
78813e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        int ratio = (int) Math.ceil((double) jpeg.width /
78913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                                mPanoLayout.getWidth());
79013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        int inSampleSize = Integer.highestOneBit(ratio);
79113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        mThumbnail = Thumbnail.createThumbnail(
79213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                                jpeg.data, orientation, inSampleSize, uri);
79322d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                    }
79413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    mMainHandler.sendMessage(
79513e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                            mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL));
796a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong                }
797142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            }
7985fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        });
799215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        reportProgress();
800215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    }
801215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong
802215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    private void showDialog(String str) {
803215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong          mProgressDialog = new ProgressDialog(this);
804215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong          mProgressDialog.setMessage(str);
805215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong          mProgressDialog.show();
8065fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    }
8075fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
808215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    private void runBackgroundThread(Thread thread) {
8095fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mThreadRunning = true;
8105fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        thread.start();
8115fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    }
8125fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
8135fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private void onBackgroundThreadFinished() {
8145fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mThreadRunning = false;
815c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        if (mProgressDialog != null) {
816215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong            mProgressDialog.dismiss();
817215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong            mProgressDialog = null;
818215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        }
819142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
820142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
821142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    @OnClickAttr
822215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    public void onCancelButtonClicked(View v) {
823215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        if (mPausing || mSurfaceTexture == null) return;
824215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mCancelComputation = true;
825215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        synchronized (mWaitObject) {
826215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong            mWaitObject.notify();
827215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        }
828142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
829142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
830a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    @OnClickAttr
831a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    public void onThumbnailClicked(View v) {
832a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        if (mPausing || mThreadRunning || mSurfaceTexture == null) return;
833a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        showSharePopup();
834a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    }
835a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong
836a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private void showSharePopup() {
837a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        if (mThumbnail == null) return;
838a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        Uri uri = mThumbnail.getUri();
839a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        if (mSharePopup == null || !uri.equals(mSharePopup.getUri())) {
840a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong            // The orientation compensation is set to 0 here because we only support landscape.
841757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li            mSharePopup = new SharePopup(this, uri, mThumbnail.getBitmap(), 0,
842977d06c6278cb7b131ed3c0960853d9168aacbddWu-cheng Li                    findViewById(R.id.frame_layout));
843a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        }
844a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        mSharePopup.showAtLocation(mThumbnailView, Gravity.NO_GRAVITY, 0, 0);
845a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    }
846a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong
84727c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong    private void reset() {
848a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_VIEWFINDER;
84941a2e9735136f372de95652d0828600282c8e967mbansal
85041a2e9735136f372de95652d0828600282c8e967mbansal        mReviewLayout.setVisibility(View.GONE);
851fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan);
852057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setVisibility(View.GONE);
85360fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mCaptureLayout.setVisibility(View.VISIBLE);
854142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.reset();
85541a2e9735136f372de95652d0828600282c8e967mbansal
8562faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mSurfaceTexture.setOnFrameAvailableListener(this);
85727c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong    }
85841a2e9735136f372de95652d0828600282c8e967mbansal
85927c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong    private void resetToPreview() {
86027c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        reset();
86136839102e03107e3fb121197036365a58ec2686eAngus Kong        if (!mPausing) startCameraPreview();
862142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
863142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
864142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void showFinalMosaic(Bitmap bitmap) {
865142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (bitmap != null) {
866142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mReview.setImageBitmap(bitmap);
867142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
868ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureLayout.setVisibility(View.GONE);
869ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mReviewLayout.setVisibility(View.VISIBLE);
870142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
871142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
872ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong    private Uri savePanorama(byte[] jpegData, int width, int height, int orientation) {
873ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (jpegData != null) {
874ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            String imagePath = PanoUtil.createName(
875ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    getResources().getString(R.string.pano_file_name_format), mTimeTaken);
876a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong            return Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null,
877ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong                    orientation, jpegData, width, height);
878142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
879a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        return null;
880142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
881142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
882142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void clearMosaicFrameProcessorIfNeeded() {
883142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (!mPausing || mThreadRunning) return;
884142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.clear();
885142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
886142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
887142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void initMosaicFrameProcessorIfNeeded() {
888142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mPausing || mThreadRunning) return;
889142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mMosaicFrameProcessor == null) {
890142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            // Start the activity for the first time.
891c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            mMosaicFrameProcessor = new MosaicFrameProcessor(
8920adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen                    mPreviewWidth, mPreviewHeight, getPreviewBufSize());
893142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
894142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.initialize();
895bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
896bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
897bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
898bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    protected void onPause() {
899bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onPause();
9004d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong
901142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = true;
90227c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        // Stop the capturing first.
90327c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        if (mCaptureState == CAPTURE_STATE_MOSAIC) {
90427c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong            stopCapture(true);
90527c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong            reset();
90627c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        }
90727c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        releaseCamera();
9082faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.onPause();
909142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        clearMosaicFrameProcessorIfNeeded();
910215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSensorManager.unregisterListener(mListener);
911c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mOrientationEventListener.disable();
91294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen        System.gc();
913bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
914bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
915bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
916bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    protected void onResume() {
917bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onResume();
918bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
919142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = false;
920c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mOrientationEventListener.enable();
921bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        /*
92294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * It is not necessary to get accelerometer events at a very high rate,
923c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong         * by using a game rate (SENSOR_DELAY_UI), we get an automatic
92494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * low-pass filter, which "extracts" the gravity component of the
92594f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * acceleration. As an added benefit, we use less power and CPU
92694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen         * resources.
927bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen         */
928bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI);
929215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong
930a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_VIEWFINDER;
931bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setupCamera();
932575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi
933142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        // Camera must be initialized before MosaicFrameProcessor is initialized. The preview size
934142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        // has to be decided by camera device.
935142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        initMosaicFrameProcessorIfNeeded();
9362faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.onResume();
937bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
938bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
939c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private void updateCompassValue() {
940917cd82d626aaa5ea48b301fe9c7bc7452a0177fAngus Kong        if (mCaptureState == CAPTURE_STATE_VIEWFINDER) return;
941c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        // By what angle has the camera moved since start of capture?
942c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mTraversedAngleX = (int) (mCompassValueX - mCompassValueXStart);
943c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mTraversedAngleY = (int) (mCompassValueY - mCompassValueYStart);
944c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mMinAngleX = Math.min(mMinAngleX, mTraversedAngleX);
945c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mMaxAngleX = Math.max(mMaxAngleX, mTraversedAngleX);
946c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mMinAngleY = Math.min(mMinAngleY, mTraversedAngleY);
947c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mMaxAngleY = Math.max(mMaxAngleY, mTraversedAngleY);
948c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
949c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        // Use orientation to identify if the user is panning to the right or the left.
950c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        switch (mDeviceOrientation) {
951c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            case 0:
952057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong                mPanoProgressBar.setProgress(-mTraversedAngleX);
953c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                break;
954c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            case 1:
955057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong                mPanoProgressBar.setProgress(mTraversedAngleY);
956c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                break;
957c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            case 2:
958057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong                mPanoProgressBar.setProgress(mTraversedAngleX);
959c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                break;
960c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            case 3:
961057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong                mPanoProgressBar.setProgress(-mTraversedAngleY);
962c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                break;
963c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        }
964057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.invalidate();
965c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    }
966bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
967c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private final SensorEventListener mListener = new SensorEventListener() {
968bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        public void onSensorChanged(SensorEvent event) {
969bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
970bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                if (mTimestamp != 0) {
971bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                    final float dT = (event.timestamp - mTimestamp) * NS2S;
972c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                    mCompassValueX += event.values[1] * dT * 180.0f / Math.PI;
973c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                    mCompassValueY += event.values[0] * dT * 180.0f / Math.PI;
974c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                    mCompassValueXStartBuffer = mCompassValueX;
975c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                    mCompassValueYStartBuffer = mCompassValueY;
976c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                    updateCompassValue();
977bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                }
978bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mTimestamp = event.timestamp;
979bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
980bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
981bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
982bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
983bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        @Override
984bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        public void onAccuracyChanged(Sensor sensor, int accuracy) {
985bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
986bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    };
987bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
9887648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li    public MosaicJpeg generateFinalMosaic(boolean highRes) {
98913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        if (mMosaicFrameProcessor.createMosaic(highRes) == Mosaic.MOSAIC_RET_CANCELLED) {
990e1178a73fd5756771d25d0b8375452450f509e99mbansal            return null;
99113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        }
992bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
993ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21();
994ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (imageData == null) {
995ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "getFinalMosaicNV21() returned null.");
99613e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            return new MosaicJpeg();
9978a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
9988a2c41754655a3733175fce81fb7506ff7022959Angus Kong
999ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int len = imageData.length - 8;
1000ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16)
1001ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF);
1002ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16)
1003ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF);
1004ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height);
10058a2c41754655a3733175fce81fb7506ff7022959Angus Kong
1006e46486104523760a4433f03e09ed615987d83b6cAngus Kong        if (width <= 0 || height <= 0) {
1007e46486104523760a4433f03e09ed615987d83b6cAngus Kong            // TODO: pop up a error meesage indicating that the final result is not generated.
1008e46486104523760a4433f03e09ed615987d83b6cAngus Kong            Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " +
1009e46486104523760a4433f03e09ed615987d83b6cAngus Kong                    height);
101013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            return new MosaicJpeg();
1011e46486104523760a4433f03e09ed615987d83b6cAngus Kong        }
1012e46486104523760a4433f03e09ed615987d83b6cAngus Kong
1013ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
1014ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        ByteArrayOutputStream out = new ByteArrayOutputStream();
1015ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out);
1016ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        try {
1017ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            out.close();
1018ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        } catch (Exception e) {
1019ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "Exception in storing final mosaic", e);
102013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            return new MosaicJpeg();
1021ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        }
10227648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        return new MosaicJpeg(out.toByteArray(), width, height);
1023bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
10248a2c41754655a3733175fce81fb7506ff7022959Angus Kong
102541a2e9735136f372de95652d0828600282c8e967mbansal    private void setPreviewTexture(SurfaceTexture surface) {
102698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
102741a2e9735136f372de95652d0828600282c8e967mbansal            mCameraDevice.setPreviewTexture(surface);
102898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
102998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
103041a2e9735136f372de95652d0828600282c8e967mbansal            throw new RuntimeException("setPreviewTexture failed", ex);
103198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
103298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
103398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
103436839102e03107e3fb121197036365a58ec2686eAngus Kong    private void startCameraPreview() {
103598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // If we're previewing already, stop the preview first (this will blank
103698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // the screen).
103736839102e03107e3fb121197036365a58ec2686eAngus Kong        if (mCameraState != PREVIEW_STOPPED) stopCameraPreview();
103898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
1039575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi        int orientation = Util.getDisplayOrientation(Util.getDisplayRotation(this),
1040575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi                CameraHolder.instance().getBackCameraId());
1041575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi        mCameraDevice.setDisplayOrientation(orientation);
1042575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi
10432faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        setPreviewTexture(mSurfaceTexture);
104498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
104598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
104698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "startPreview");
104798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.startPreview();
104898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
104998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
105098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            throw new RuntimeException("startPreview failed", ex);
105198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
105298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_ACTIVE;
105398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
105498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
105536839102e03107e3fb121197036365a58ec2686eAngus Kong    private void stopCameraPreview() {
105698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
105798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "stopPreview");
105898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.stopPreview();
105998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
106098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_STOPPED;
106198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
1062bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen}
1063