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;
28ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kongimport com.android.camera.RotateDialogController;
29fcdf619d92701052621a96572d956d047e07cf24Angus Kongimport com.android.camera.ShutterButton;
30d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Storage;
31a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.Thumbnail;
32d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Util;
33749d056cd82ebfe6e613596d9e22dd355aeeec41Chung-yih Wangimport com.android.camera.ui.PopupManager;
34d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wangimport com.android.camera.ui.Rotatable;
35a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.ui.RotateImageView;
36d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wangimport com.android.camera.ui.RotateLayout;
37a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.ui.SharePopup;
38d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Li
399a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagnerimport android.content.ContentResolver;
40bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.content.Context;
41174b8b7fc4d55e8c63eb3ed0b71f1519a13e345dAngus Kongimport android.content.res.AssetFileDescriptor;
42d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wangimport android.content.pm.ActivityInfo;
43057040c0e19834d98719143c2627a9f0df3e4c35Angus Kongimport android.content.res.Resources;
44142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.Bitmap;
45142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.BitmapFactory;
468a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.ImageFormat;
47bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.graphics.PixelFormat;
488a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.Rect;
4941a2e9735136f372de95652d0828600282c8e967mbansalimport android.graphics.SurfaceTexture;
508a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.YuvImage;
516f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kongimport android.hardware.Camera.Parameters;
526f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kongimport android.hardware.Camera.Size;
53bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.Sensor;
54bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorManager;
55e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chenimport android.media.ExifInterface;
561461b5333aab31faee65272d64c2ac7f9809d4d0Eino-Ville Talvalaimport android.media.MediaActionSound;
57a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport android.net.Uri;
58bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.os.Bundle;
598a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.os.Handler;
60ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport android.os.Message;
61174b8b7fc4d55e8c63eb3ed0b71f1519a13e345dAngus Kongimport android.os.ParcelFileDescriptor;
6262bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kongimport android.os.PowerManager;
63bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.util.Log;
64a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport android.view.Gravity;
65c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kongimport android.view.Menu;
661413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Liimport android.view.MenuItem;
67c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kongimport android.view.OrientationEventListener;
68bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.View;
69d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wangimport android.view.ViewGroup;
70a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chenimport android.view.Window;
71bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.WindowManager;
72bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.widget.ImageView;
73fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kongimport android.widget.TextView;
74bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
75ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport java.io.ByteArrayOutputStream;
769a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagnerimport java.io.File;
77e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chenimport java.io.IOException;
78bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport java.util.List;
79bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
80a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong/**
81a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong * Activity to handle panorama capturing.
82a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong */
835f6e354a6e2a77aa935fcefeb33a9baa67d48aafChung-yih Wangpublic class PanoramaActivity extends ActivityBase implements
84fcdf619d92701052621a96572d956d047e07cf24Angus Kong        ModePicker.OnModeChangeListener, SurfaceTexture.OnFrameAvailableListener,
85fcdf619d92701052621a96572d956d047e07cf24Angus Kong        ShutterButton.OnShutterButtonListener,
8636839102e03107e3fb121197036365a58ec2686eAngus Kong        MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener {
87ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong    public static final int DEFAULT_SWEEP_ANGLE = 160;
88bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL;
89bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720;
90bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
912f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong    private static final int MSG_LOW_RES_FINAL_MOSAIC_READY = 1;
92a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private static final int MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL = 2;
9322d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong    private static final int MSG_GENERATE_FINAL_MOSAIC_ERROR = 3;
9459a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong    private static final int MSG_RESET_TO_PREVIEW = 4;
95bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    private static final int MSG_CLEAR_SCREEN_DELAY = 5;
96bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang
97bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    private static final int SCREEN_DELAY = 2 * 60 * 1000;
9894f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen
99ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private static final String TAG = "PanoramaActivity";
10098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_STOPPED = 0;
10198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private static final int PREVIEW_ACTIVE = 1;
102a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong    private static final int CAPTURE_STATE_VIEWFINDER = 0;
103a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong    private static final int CAPTURE_STATE_MOSAIC = 1;
10441a2e9735136f372de95652d0828600282c8e967mbansal
10543b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    // Speed is in unit of deg/sec
106e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen    private static final float PANNING_SPEED_THRESHOLD = 20f;
10743b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen
108a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    // Ratio of nanosecond to second
109a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private static final float NS2S = 1.0f / 1000000000.0f;
110142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
111142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mPausing;
112142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
1137648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li    private View mPanoLayout;
114a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mCaptureLayout;
115a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    private View mReviewLayout;
116bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private ImageView mReview;
117d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang    private RotateLayout mCaptureIndicator;
118057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong    private PanoProgressBar mPanoProgressBar;
119215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    private PanoProgressBar mSavingProgressBar;
1208b0e23544474480345937c0c0985429f61569761Angus Kong    private View mFastIndicationBorder;
1216108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    private View mLeftIndicator;
1226108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    private View mRightIndicator;
1232faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private MosaicRendererSurfaceView mMosaicView;
124fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong    private TextView mTooFastPrompt;
125fcdf619d92701052621a96572d956d047e07cf24Angus Kong    private ShutterButton mShutterButton;
126215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    private Object mWaitObject = new Object();
127142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
1285fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private String mPreparePreviewString;
12922d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong    private String mDialogTitle;
130d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang    private String mDialogOkString;
131d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang    private String mDialogPanoramaFailedString;
1322f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong
133fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong    private int mIndicatorColor;
134fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong    private int mIndicatorColorFast;
135fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong
136c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueX;
137c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueY;
138c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueXStart;
139c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueYStart;
140c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueXStartBuffer;
141c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private float mCompassValueYStartBuffer;
142c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mCompassThreshold;
143c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mTraversedAngleX;
144c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mTraversedAngleY;
145c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private long mTimestamp;
146c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
147a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private RotateImageView mThumbnailView;
148a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private Thumbnail mThumbnail;
149a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private SharePopup mSharePopup;
150a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong
151bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewWidth;
152bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private int mPreviewHeight;
15398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    private int mCameraState;
15441a2e9735136f372de95652d0828600282c8e967mbansal    private int mCaptureState;
155bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private SensorManager mSensorManager;
156bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private Sensor mSensor;
15762bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong    private PowerManager.WakeLock mPartialWakeLock;
158a72d73cbac59db43d413291e4db66763be08143arepo sync    private ModePicker mModePicker;
1598a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private MosaicFrameProcessor mMosaicFrameProcessor;
1608a2c41754655a3733175fce81fb7506ff7022959Angus Kong    private long mTimeTaken;
161ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private Handler mMainHandler;
1622faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private SurfaceTexture mSurfaceTexture;
163142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private boolean mThreadRunning;
164e1178a73fd5756771d25d0b8375452450f509e99mbansal    private boolean mCancelComputation;
1652faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    private float[] mTransformMatrix;
16643b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen    private float mHorizontalViewAngle;
1672d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen    private float mVerticalViewAngle;
168c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
169d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen    // Prefer FOCUS_MODE_INFINITY to FOCUS_MODE_CONTINUOUS_VIDEO because of
170d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen    // getting a better image quality by the former.
171d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen    private String mTargetFocusMode = Parameters.FOCUS_MODE_INFINITY;
172d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen
173c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private PanoOrientationEventListener mOrientationEventListener;
17422400adc90877480c3229d0ee86df9a6736c66cdAngus Kong    // The value could be 0, 90, 180, 270 for the 4 different orientations measured in clockwise
175c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    // respectively.
176c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private int mDeviceOrientation;
177e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen    private int mDeviceOrientationAtCapture;
178e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen    private int mCameraOrientation;
1795201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner    private int mOrientationCompensation;
180142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
181ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong    private RotateDialogController mRotateDialog;
182ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong
1831461b5333aab31faee65272d64c2ac7f9809d4d0Eino-Ville Talvala    private MediaActionSound mCameraSound;
18490089f9eddde732725c43dcad07f4567ed8cb776Wu-cheng Li
1857648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li    private class MosaicJpeg {
1867648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        public MosaicJpeg(byte[] data, int width, int height) {
1877648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li            this.data = data;
1887648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li            this.width = width;
1897648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li            this.height = height;
19013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.isValid = true;
19113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        }
19213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong
19313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        public MosaicJpeg() {
19413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.data = null;
19513e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.width = 0;
19613e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.height = 0;
19713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            this.isValid = false;
1987648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        }
1997648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li
2007648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        public final byte[] data;
2017648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        public final int width;
2027648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        public final int height;
20313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        public final boolean isValid;
2047648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li    }
2057648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li
206c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    private class PanoOrientationEventListener extends OrientationEventListener {
207c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        public PanoOrientationEventListener(Context context) {
208c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            super(context);
209c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        }
210c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
211c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        @Override
212c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        public void onOrientationChanged(int orientation) {
2135201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            // We keep the last known orientation. So if the user first orient
2145201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            // the camera then point the camera to floor or sky, we still have
2155201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            // the correct orientation.
216c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            if (orientation == ORIENTATION_UNKNOWN) return;
217131cf9886c4f34431598be0b1f5b7aaa915277ccEino-Ville Talvala            mDeviceOrientation = Util.roundOrientation(orientation, mDeviceOrientation);
2185201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            // When the screen is unlocked, display rotation may change. Always
2195201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            // calculate the up-to-date orientationCompensation.
2205201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            int orientationCompensation = mDeviceOrientation
2215201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner                    + Util.getDisplayRotation(PanoramaActivity.this);
2225201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            if (mOrientationCompensation != orientationCompensation) {
2235201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner                mOrientationCompensation = orientationCompensation;
2245201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner                setOrientationIndicator(mOrientationCompensation);
2255201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            }
226c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        }
227c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong    }
228c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
2295201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner    private void setOrientationIndicator(int degree) {
2305201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner        if (mSharePopup != null) mSharePopup.setOrientation(degree);
2315201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner    }
2325201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner
233bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
234c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    public boolean onCreateOptionsMenu(Menu menu) {
235c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        super.onCreateOptionsMenu(menu);
236c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong
237c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        addBaseMenuItems(menu);
238c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        return true;
239c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    }
240c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong
2411413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li    @Override
2421413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li    public boolean onPrepareOptionsMenu(Menu menu) {
2431413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li        super.onPrepareOptionsMenu(menu);
2441413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li        // Only show the menu when idle.
2451413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li        boolean idle = (mCaptureState == CAPTURE_STATE_VIEWFINDER && !mThreadRunning);
2461413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li        for (int i = 0; i < menu.size(); i++) {
2471413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li            MenuItem item = menu.getItem(i);
2481413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li            item.setVisible(idle);
2491413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li            item.setEnabled(idle);
2501413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li        }
2511413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li
2521413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li        return true;
2531413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li    }
2541413860cab487d4dfeaf9856e553665dadc5ef1cWu-cheng Li
255c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    private void addBaseMenuItems(Menu menu) {
256c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        MenuHelper.addSwitchModeMenuItem(menu, ModePicker.MODE_CAMERA, new Runnable() {
257c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong            public void run() {
258c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong                switchToOtherMode(ModePicker.MODE_CAMERA);
259c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong            }
260c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        });
261c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        MenuHelper.addSwitchModeMenuItem(menu, ModePicker.MODE_VIDEO, new Runnable() {
262c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong            public void run() {
263c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong                switchToOtherMode(ModePicker.MODE_VIDEO);
264c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong            }
265c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong        });
266c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    }
267c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong
268c159dfe54fbc0f055a1d760f1614db4a8bcec94cAngus Kong    @Override
269bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public void onCreate(Bundle icicle) {
270bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onCreate(icicle);
271bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
272a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        Window window = getWindow();
273a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        Util.enterLightsOutMode(window);
274a959d05b52ac4b27dcdfe3d3a4e72220cf69d47aWei-Ta Chen        Util.initializeScreenBrightness(window, getContentResolver());
275bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
276bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        createContentView();
277bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
278bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
279bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
280bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (mSensor == null) {
281bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
282bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
28362bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
28462bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Panorama");
2858a2c41754655a3733175fce81fb7506ff7022959Angus Kong
286c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mOrientationEventListener = new PanoOrientationEventListener(this);
287c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
2882faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mTransformMatrix = new float[16];
2892faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong
2905fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mPreparePreviewString =
2915fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                getResources().getString(R.string.pano_dialog_prepare_preview);
29222d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong        mDialogTitle = getResources().getString(R.string.pano_dialog_title);
293d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang        mDialogOkString = getResources().getString(R.string.dialog_ok);
294d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang        mDialogPanoramaFailedString =
295d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang                getResources().getString(R.string.pano_dialog_panorama_failed);
2961461b5333aab31faee65272d64c2ac7f9809d4d0Eino-Ville Talvala        mCameraSound = new MediaActionSound();
2975fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
298ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        mMainHandler = new Handler() {
299ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            @Override
300ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            public void handleMessage(Message msg) {
301ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                switch (msg.what) {
3022f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong                    case MSG_LOW_RES_FINAL_MOSAIC_READY:
3035fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                        onBackgroundThreadFinished();
304142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        showFinalMosaic((Bitmap) msg.obj);
305215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                        saveHighResMosaic();
306142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
307a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong                    case MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL:
3085fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong                        onBackgroundThreadFinished();
30962bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                        // If the activity is paused, save the thumbnail to the file here.
31062bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                        // If not, it will be saved in onPause.
31162bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                        if (mPausing) saveThumbnailToFile();
312a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong                        // Set the thumbnail bitmap here because mThumbnailView must be accessed
313a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong                        // from the UI thread.
3149a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner                        updateThumbnailButton();
3159a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner
316db288b8686e5bcecef620176b934b00eb0742597Wu-cheng Li                        // Share popup may still have the reference to the old thumbnail. Clear it.
317db288b8686e5bcecef620176b934b00eb0742597Wu-cheng Li                        mSharePopup = null;
318142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        resetToPreview();
319142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                        break;
32022d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                    case MSG_GENERATE_FINAL_MOSAIC_ERROR:
32122d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                        onBackgroundThreadFinished();
3223eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                        if (mPausing) {
3233eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                            resetToPreview();
3243eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                        } else {
325ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong                            mRotateDialog.showAlertDialog(
326ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong                                    mDialogTitle, mDialogPanoramaFailedString,
327ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong                                    mDialogOkString, new Runnable() {
328ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong                                        @Override
329ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong                                        public void run() {
330ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong                                            resetToPreview();
331ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong                                        }},
332ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong                                    null, null);
3333eaaa3f1fc7b3079e0edc66ed61d5e48b7cc44ccAngus Kong                        }
33422d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                        break;
33513e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    case MSG_RESET_TO_PREVIEW:
336e1178a73fd5756771d25d0b8375452450f509e99mbansal                        onBackgroundThreadFinished();
337e1178a73fd5756771d25d0b8375452450f509e99mbansal                        resetToPreview();
338bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang                        break;
339bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang                    case MSG_CLEAR_SCREEN_DELAY:
340bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang                        getWindow().clearFlags(WindowManager.LayoutParams.
341bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang                                FLAG_KEEP_SCREEN_ON);
342bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang                        break;
343ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong                }
344142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                clearMosaicFrameProcessorIfNeeded();
345ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            }
346ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        };
347d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang    }
34859a140990af1ba6d2c9aa627047a02e50c8dd0e1Angus Kong
34980583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang    private void setupCamera() throws CameraHardwareException, CameraDisabledException {
350bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        openCamera();
351bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Parameters parameters = mCameraDevice.getParameters();
352bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setupCaptureParams(parameters);
353bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        configureCamera(parameters);
354bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
355bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
356ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    private void releaseCamera() {
357ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        if (mCameraDevice != null) {
358142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mCameraDevice.setPreviewCallbackWithBuffer(null);
359ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            CameraHolder.instance().release();
360ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong            mCameraDevice = null;
36198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraState = PREVIEW_STOPPED;
362ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong        }
363ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong    }
364ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong
36580583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang    private void openCamera() throws CameraHardwareException, CameraDisabledException {
36680583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang        int backCameraId = CameraHolder.instance().getBackCameraId();
36780583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang        mCameraDevice = Util.openCamera(this, backCameraId);
36880583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang        mCameraOrientation = Util.getCameraOrientation(backCameraId);
369bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
370bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
371bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3,
372bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            boolean needSmaller) {
373bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int pixelsDiff = DEFAULT_CAPTURE_PIXELS;
374bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        boolean hasFound = false;
3758a2c41754655a3733175fce81fb7506ff7022959Angus Kong        for (Size size : supportedSizes) {
376bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int h = size.height;
377bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int w = size.width;
378bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            // we only want 4:3 format.
379bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            int d = DEFAULT_CAPTURE_PIXELS - h * w;
38094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            if (needSmaller && d < 0) { // no bigger preview than 960x720.
381bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
382bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
383bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (need4To3 && (h * 4 != w * 3)) {
384bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                continue;
385bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
386bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            d = Math.abs(d);
387bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (d < pixelsDiff) {
388bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewWidth = w;
389bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                mPreviewHeight = h;
390bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                pixelsDiff = d;
391bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                hasFound = true;
392bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
393bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
394bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return hasFound;
395bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
396bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
397bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void setupCaptureParams(Parameters parameters) {
398bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<Size> supportedSizes = parameters.getSupportedPreviewSizes();
399bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        if (!findBestPreviewSize(supportedSizes, true, true)) {
400bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            Log.w(TAG, "No 4:3 ratio preview size supported.");
401bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            if (!findBestPreviewSize(supportedSizes, false, true)) {
402bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                Log.w(TAG, "Can't find a supported preview size smaller than 960x720.");
403bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen                findBestPreviewSize(supportedSizes, false, false);
404bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen            }
405bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        }
406bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth);
407bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewSize(mPreviewWidth, mPreviewHeight);
408bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
409bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        List<int[]> frameRates = parameters.getSupportedPreviewFpsRange();
410bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int last = frameRates.size() - 1;
411bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX];
412bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX];
413bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        parameters.setPreviewFpsRange(minFps, maxFps);
414bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        Log.v(TAG, "preview fps: " + minFps + ", " + maxFps);
4153ab4f0912da83f7f5f8266a57a606d521c1649e3Wu-cheng Li
416d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen        List<String> supportedFocusModes = parameters.getSupportedFocusModes();
417d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen        if (supportedFocusModes.indexOf(mTargetFocusMode) >= 0) {
418d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen            parameters.setFocusMode(mTargetFocusMode);
419d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen        } else {
420d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen            // Use the default focus mode and log a message
421d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen            Log.w(TAG, "Cannot set the focus mode to " + mTargetFocusMode +
422d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen                  " becuase the mode is not supported.");
423d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen        }
424d3105c578427ac7507ca32ff1de4a92962de2357Wei-Ta Chen
42593ad273a53e7d2975a67d7d1f8a157f845e41cf2Wu-cheng Li        parameters.setRecordingHint(false);
42643b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen
4272d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen        mHorizontalViewAngle = parameters.getHorizontalViewAngle();
4282d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen        mVerticalViewAngle =  parameters.getVerticalViewAngle();
429bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
430bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
431bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    public int getPreviewBufSize() {
432bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat pixelInfo = new PixelFormat();
433bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo);
434bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        // TODO: remove this extra 32 byte after the driver bug is fixed.
435bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32;
436bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
437bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
438bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void configureCamera(Parameters parameters) {
439bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        mCameraDevice.setParameters(parameters);
440bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
441bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
442a72d73cbac59db43d413291e4db66763be08143arepo sync    private boolean switchToOtherMode(int mode) {
443a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        if (isFinishing()) {
44494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen            return false;
445a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        }
446a72d73cbac59db43d413291e4db66763be08143arepo sync        MenuHelper.gotoMode(mode, this);
447a72d73cbac59db43d413291e4db66763be08143arepo sync        finish();
448a72d73cbac59db43d413291e4db66763be08143arepo sync        return true;
449a72d73cbac59db43d413291e4db66763be08143arepo sync    }
450a72d73cbac59db43d413291e4db66763be08143arepo sync
451a72d73cbac59db43d413291e4db66763be08143arepo sync    public boolean onModeChanged(int mode) {
452a72d73cbac59db43d413291e4db66763be08143arepo sync        if (mode != ModePicker.MODE_PANORAMA) {
453a72d73cbac59db43d413291e4db66763be08143arepo sync            return switchToOtherMode(mode);
454a72d73cbac59db43d413291e4db66763be08143arepo sync        } else {
455a72d73cbac59db43d413291e4db66763be08143arepo sync            return true;
456a72d73cbac59db43d413291e4db66763be08143arepo sync        }
457a72d73cbac59db43d413291e4db66763be08143arepo sync    }
458a72d73cbac59db43d413291e4db66763be08143arepo sync
4592faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    @Override
460575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi    public void onMosaicSurfaceChanged() {
461575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi        runOnUiThread(new Runnable() {
462575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi            @Override
463575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi            public void run() {
46462bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                // If panorama is generating low res or high res mosaic, it
46562bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                // means users exit and come back to panorama. Do not start the
46662bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                // preview. Preview will be started after final mosaic is
46762bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                // generated.
46862bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                if (!mPausing && !mThreadRunning) {
469575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi                    startCameraPreview();
470575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi                }
471575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi            }
472575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi        });
473575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi    }
474575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi
475575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi    @Override
4762faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong    public void onMosaicSurfaceCreated(final int textureID) {
47736839102e03107e3fb121197036365a58ec2686eAngus Kong        runOnUiThread(new Runnable() {
47836839102e03107e3fb121197036365a58ec2686eAngus Kong            @Override
47936839102e03107e3fb121197036365a58ec2686eAngus Kong            public void run() {
4802faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                if (mSurfaceTexture != null) {
4812faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                    mSurfaceTexture.release();
4822faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                }
4832faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture = new SurfaceTexture(textureID);
4842faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                if (!mPausing) {
4852faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                    mSurfaceTexture.setOnFrameAvailableListener(PanoramaActivity.this);
4862faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                }
48736839102e03107e3fb121197036365a58ec2686eAngus Kong            }
48836839102e03107e3fb121197036365a58ec2686eAngus Kong        });
48936839102e03107e3fb121197036365a58ec2686eAngus Kong    }
49036839102e03107e3fb121197036365a58ec2686eAngus Kong
49141a2e9735136f372de95652d0828600282c8e967mbansal    public void runViewFinder() {
4922faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setWarping(false);
4932faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Call preprocess to render it to low-res and high-res RGB textures.
4942faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.preprocess(mTransformMatrix);
4952faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setReady();
4962faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.requestRender();
49741a2e9735136f372de95652d0828600282c8e967mbansal    }
49841a2e9735136f372de95652d0828600282c8e967mbansal
49941a2e9735136f372de95652d0828600282c8e967mbansal    public void runMosaicCapture() {
5002faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setWarping(true);
5012faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Call preprocess to render it to low-res and high-res RGB textures.
5022faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.preprocess(mTransformMatrix);
5032faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Lock the conditional variable to ensure the order of transferGPUtoCPU and
5042faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // mMosaicFrame.processFrame().
5052faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.lockPreviewReadyFlag();
50641a2e9735136f372de95652d0828600282c8e967mbansal        // Now, transfer the textures from GPU to CPU memory for processing
5072faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.transferGPUtoCPU();
50841a2e9735136f372de95652d0828600282c8e967mbansal        // Wait on the condition variable (will be opened when GPU->CPU transfer is done).
5092faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.waitUntilPreviewReady();
5100adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen        mMosaicFrameProcessor.processFrame();
51141a2e9735136f372de95652d0828600282c8e967mbansal    }
51241a2e9735136f372de95652d0828600282c8e967mbansal
513739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    public synchronized void onFrameAvailable(SurfaceTexture surface) {
5144d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong        /* This function may be called by some random thread,
51541a2e9735136f372de95652d0828600282c8e967mbansal         * so let's be safe and use synchronize. No OpenGL calls can be done here.
51641a2e9735136f372de95652d0828600282c8e967mbansal         */
5170cefcea01849364be6955a1b3f7e7d1639010abcAngus Kong        // Frames might still be available after the activity is paused. If we call onFrameAvailable
5180cefcea01849364be6955a1b3f7e7d1639010abcAngus Kong        // after pausing, the GL thread will crash.
5190cefcea01849364be6955a1b3f7e7d1639010abcAngus Kong        if (mPausing) return;
5200cefcea01849364be6955a1b3f7e7d1639010abcAngus Kong
5212faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Updating the texture should be done in the GL thread which mMosaicView is attached.
5222faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.queueEvent(new Runnable() {
5232faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            @Override
5242faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            public void run() {
5250cefcea01849364be6955a1b3f7e7d1639010abcAngus Kong                // Check if the activity is paused here can speed up the onPause() process.
5260cefcea01849364be6955a1b3f7e7d1639010abcAngus Kong                if (mPausing) return;
5272faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture.updateTexImage();
5282faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong                mSurfaceTexture.getTransformMatrix(mTransformMatrix);
5292faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong            }
5302faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        });
5312faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // Update the transformation matrix for mosaic pre-process.
532a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        if (mCaptureState == CAPTURE_STATE_VIEWFINDER) {
53341a2e9735136f372de95652d0828600282c8e967mbansal            runViewFinder();
53441a2e9735136f372de95652d0828600282c8e967mbansal        } else {
53541a2e9735136f372de95652d0828600282c8e967mbansal            runMosaicCapture();
53641a2e9735136f372de95652d0828600282c8e967mbansal        }
53741a2e9735136f372de95652d0828600282c8e967mbansal    }
53841a2e9735136f372de95652d0828600282c8e967mbansal
5396108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    private void hideDirectionIndicators() {
5406108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mLeftIndicator.setVisibility(View.GONE);
5416108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mRightIndicator.setVisibility(View.GONE);
5426108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    }
5436108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong
5446108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    private void showDirectionIndicators(int direction) {
5456108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        switch (direction) {
5466108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong            case PanoProgressBar.DIRECTION_NONE:
5476108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mLeftIndicator.setVisibility(View.VISIBLE);
5486108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mRightIndicator.setVisibility(View.VISIBLE);
5496108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                break;
5506108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong            case PanoProgressBar.DIRECTION_LEFT:
5516108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mLeftIndicator.setVisibility(View.VISIBLE);
5526108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mRightIndicator.setVisibility(View.GONE);
5536108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                break;
5546108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong            case PanoProgressBar.DIRECTION_RIGHT:
5556108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mLeftIndicator.setVisibility(View.GONE);
5566108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                mRightIndicator.setVisibility(View.VISIBLE);
5576108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                break;
5586108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        }
5596108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong    }
5606108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong
561a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong    public void startCapture() {
5628a2c41754655a3733175fce81fb7506ff7022959Angus Kong        // Reset values so we can do this again.
56313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        mCancelComputation = false;
5648a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mTimeTaken = System.currentTimeMillis();
565a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_MOSAIC;
566fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan_recording);
5678df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong        mCaptureIndicator.setVisibility(View.VISIBLE);
5686108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        showDirectionIndicators(PanoProgressBar.DIRECTION_NONE);
5694a3026b84fa4fd403317b30b6a9db61125fecfa2heech.park        mThumbnailView.setEnabled(false);
5708a2c41754655a3733175fce81fb7506ff7022959Angus Kong
571c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mCompassValueXStart = mCompassValueXStartBuffer;
572c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mCompassValueYStart = mCompassValueYStartBuffer;
573c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mTimestamp = 0;
574c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong
5758a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() {
5768a2c41754655a3733175fce81fb7506ff7022959Angus Kong            @Override
577d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong            public void onProgress(boolean isFinished, float panningRateX, float panningRateY,
578d991766dc3bcc03a02c6648e2cfd54ee4f8cbd9eAngus Kong                    float progressX, float progressY) {
5792d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                float accumulatedHorizontalAngle = progressX * mHorizontalViewAngle;
5802d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                float accumulatedVerticalAngle = progressY * mVerticalViewAngle;
581c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong                if (isFinished
5822d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                        || (Math.abs(accumulatedHorizontalAngle) >= DEFAULT_SWEEP_ANGLE)
5832d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                        || (Math.abs(accumulatedVerticalAngle) >= DEFAULT_SWEEP_ANGLE)) {
58427c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong                    stopCapture(false);
5858a2c41754655a3733175fce81fb7506ff7022959Angus Kong                } else {
5862d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                    float panningRateXInDegree = panningRateX * mHorizontalViewAngle;
5872d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                    float panningRateYInDegree = panningRateY * mVerticalViewAngle;
5882d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                    updateProgress(panningRateXInDegree, panningRateYInDegree,
5892d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                            accumulatedHorizontalAngle, accumulatedVerticalAngle);
5908a2c41754655a3733175fce81fb7506ff7022959Angus Kong                }
5918a2c41754655a3733175fce81fb7506ff7022959Angus Kong            }
5928a2c41754655a3733175fce81fb7506ff7022959Angus Kong        });
5938a2c41754655a3733175fce81fb7506ff7022959Angus Kong
5942512c685868eadb274f5be8cd71068078b1f5dddMark Wagner        if (mModePicker != null) mModePicker.setEnabled(false);
5952512c685868eadb274f5be8cd71068078b1f5dddMark Wagner
596057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.reset();
597057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        // TODO: calculate the indicator width according to different devices to reflect the actual
598057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        // angle of view of the camera device.
599057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setIndicatorWidth(20);
600057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setMaxProgress(DEFAULT_SWEEP_ANGLE);
601057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setVisibility(View.VISIBLE);
602e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen        mDeviceOrientationAtCapture = mDeviceOrientation;
603bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        keepScreenOn();
6048a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
6058a2c41754655a3733175fce81fb7506ff7022959Angus Kong
60627c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong    private void stopCapture(boolean aborted) {
607a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_VIEWFINDER;
6088df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong        mCaptureIndicator.setVisibility(View.GONE);
6098b0e23544474480345937c0c0985429f61569761Angus Kong        hideTooFastIndication();
6106108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        hideDirectionIndicators();
6114a3026b84fa4fd403317b30b6a9db61125fecfa2heech.park        mThumbnailView.setEnabled(true);
61241a2e9735136f372de95652d0828600282c8e967mbansal
6138a2c41754655a3733175fce81fb7506ff7022959Angus Kong        mMosaicFrameProcessor.setProgressListener(null);
61436839102e03107e3fb121197036365a58ec2686eAngus Kong        stopCameraPreview();
61541a2e9735136f372de95652d0828600282c8e967mbansal
6162faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mSurfaceTexture.setOnFrameAvailableListener(null);
61741a2e9735136f372de95652d0828600282c8e967mbansal
61827c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        if (!aborted && !mThreadRunning) {
619ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong            mRotateDialog.showWaitingDialog(mPreparePreviewString);
620215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong            runBackgroundThread(new Thread() {
621142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                @Override
622142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                public void run() {
6237648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li                    MosaicJpeg jpeg = generateFinalMosaic(false);
624e1178a73fd5756771d25d0b8375452450f509e99mbansal
62513e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    if (jpeg != null && jpeg.isValid) {
626e1178a73fd5756771d25d0b8375452450f509e99mbansal                        Bitmap bitmap = null;
62713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length);
628e1178a73fd5756771d25d0b8375452450f509e99mbansal                        mMainHandler.sendMessage(mMainHandler.obtainMessage(
629e1178a73fd5756771d25d0b8375452450f509e99mbansal                                MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap));
63013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    } else {
63113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        mMainHandler.sendMessage(mMainHandler.obtainMessage(
63213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                                MSG_RESET_TO_PREVIEW));
633ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    }
634142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong                }
6355fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong            });
636142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
6372512c685868eadb274f5be8cd71068078b1f5dddMark Wagner        // do we have to wait for the thread to complete before enabling this?
6382512c685868eadb274f5be8cd71068078b1f5dddMark Wagner        if (mModePicker != null) mModePicker.setEnabled(true);
639bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        keepScreenOnAwhile();
6408a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
6418a2c41754655a3733175fce81fb7506ff7022959Angus Kong
6428b0e23544474480345937c0c0985429f61569761Angus Kong    private void showTooFastIndication() {
6438b0e23544474480345937c0c0985429f61569761Angus Kong        mTooFastPrompt.setVisibility(View.VISIBLE);
6448b0e23544474480345937c0c0985429f61569761Angus Kong        mFastIndicationBorder.setVisibility(View.VISIBLE);
645fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mPanoProgressBar.setIndicatorColor(mIndicatorColorFast);
6468b0e23544474480345937c0c0985429f61569761Angus Kong        mLeftIndicator.setEnabled(true);
6478b0e23544474480345937c0c0985429f61569761Angus Kong        mRightIndicator.setEnabled(true);
6488b0e23544474480345937c0c0985429f61569761Angus Kong    }
6498b0e23544474480345937c0c0985429f61569761Angus Kong
6508b0e23544474480345937c0c0985429f61569761Angus Kong    private void hideTooFastIndication() {
6518b0e23544474480345937c0c0985429f61569761Angus Kong        mTooFastPrompt.setVisibility(View.GONE);
6528b0e23544474480345937c0c0985429f61569761Angus Kong        mFastIndicationBorder.setVisibility(View.GONE);
653fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mPanoProgressBar.setIndicatorColor(mIndicatorColor);
6548b0e23544474480345937c0c0985429f61569761Angus Kong        mLeftIndicator.setEnabled(false);
6558b0e23544474480345937c0c0985429f61569761Angus Kong        mRightIndicator.setEnabled(false);
6568b0e23544474480345937c0c0985429f61569761Angus Kong    }
6578b0e23544474480345937c0c0985429f61569761Angus Kong
6582d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen    private void updateProgress(float panningRateXInDegree, float panningRateYInDegree,
6592d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen            float progressHorizontalAngle, float progressVerticalAngle) {
6602faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.setReady();
6612faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.requestRender();
662eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
66343b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // TODO: Now we just display warning message by the panning speed.
66443b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // Since we only support horizontal panning, we should display a warning message
66543b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen        // in UI when there're significant vertical movements.
6662d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen        if ((Math.abs(panningRateXInDegree) > PANNING_SPEED_THRESHOLD)
6672d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen            || (Math.abs(panningRateYInDegree) > PANNING_SPEED_THRESHOLD)) {
6688b0e23544474480345937c0c0985429f61569761Angus Kong            showTooFastIndication();
6698a2c41754655a3733175fce81fb7506ff7022959Angus Kong        } else {
6708b0e23544474480345937c0c0985429f61569761Angus Kong            hideTooFastIndication();
6718a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
6722d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen        int angleInMajorDirection =
6732d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                (Math.abs(progressHorizontalAngle) > Math.abs(progressVerticalAngle))
6742d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                ? (int) progressHorizontalAngle
6752d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen                : (int) progressVerticalAngle;
6762d3391e6be57aeeb7e713f25a484445660b101e3Wei-Ta Chen        mPanoProgressBar.setProgress((angleInMajorDirection));
6778a2c41754655a3733175fce81fb7506ff7022959Angus Kong    }
6788a2c41754655a3733175fce81fb7506ff7022959Angus Kong
679bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    private void createContentView() {
680bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        setContentView(R.layout.panorama);
681bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
682a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_VIEWFINDER;
68341a2e9735136f372de95652d0828600282c8e967mbansal
684057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        Resources appRes = getResources();
685057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong
686a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong        mCaptureLayout = (View) findViewById(R.id.pano_capture_layout);
687215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mPanoProgressBar = (PanoProgressBar) findViewById(R.id.pano_pan_progress_bar);
688057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty));
689057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_done));
690fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mIndicatorColor = appRes.getColor(R.color.pano_progress_indication);
691fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mIndicatorColorFast = appRes.getColor(R.color.pano_progress_indication_fast);
692fa959aede9b1fe9d510108e883a2f16cf28c9033Angus Kong        mPanoProgressBar.setIndicatorColor(mIndicatorColor);
6936108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mPanoProgressBar.setOnDirectionChangeListener(
6946108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                new PanoProgressBar.OnDirectionChangeListener () {
6956108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                    @Override
6966108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                    public void onDirectionChange(int direction) {
6976108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                        if (mCaptureState == CAPTURE_STATE_MOSAIC) {
6986108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                            showDirectionIndicators(direction);
6996108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                        }
7006108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                    }
7016108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong                });
7026108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong
7036108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mLeftIndicator = (ImageView) findViewById(R.id.pano_pan_left_indicator);
7046108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong        mRightIndicator = (ImageView) findViewById(R.id.pano_pan_right_indicator);
7058b0e23544474480345937c0c0985429f61569761Angus Kong        mLeftIndicator.setEnabled(false);
7068b0e23544474480345937c0c0985429f61569761Angus Kong        mRightIndicator.setEnabled(false);
707fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong        mTooFastPrompt = (TextView) findViewById(R.id.pano_capture_too_fast_textview);
7088b0e23544474480345937c0c0985429f61569761Angus Kong        mFastIndicationBorder = (View) findViewById(R.id.pano_speed_indication_border);
709bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
710215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar = (PanoProgressBar) findViewById(R.id.pano_saving_progress_bar);
711215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setIndicatorWidth(0);
712215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setMaxProgress(100);
713215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty));
714215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_indication));
715215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong
716d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang        mCaptureIndicator = (RotateLayout) findViewById(R.id.pano_capture_indicator);
7178df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong
718a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        mThumbnailView = (RotateImageView) findViewById(R.id.thumbnail);
7194a3026b84fa4fd403317b30b6a9db61125fecfa2heech.park        mThumbnailView.enableFilter(false);
720a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong
7215af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mReviewLayout = (View) findViewById(R.id.pano_review_layout);
7225af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen        mReview = (ImageView) findViewById(R.id.pano_reviewarea);
7232faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer);
7242faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.getRenderer().setMosaicSurfaceCreateListener(this);
725eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal
726a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker = (ModePicker) findViewById(R.id.mode_picker);
727a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setVisibility(View.VISIBLE);
728a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setOnModeChangeListener(this);
729a72d73cbac59db43d413291e4db66763be08143arepo sync        mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA);
7307648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li
731fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton = (ShutterButton) findViewById(R.id.shutter_button);
732fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan);
733fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton.setOnShutterButtonListener(this);
734fcdf619d92701052621a96572d956d047e07cf24Angus Kong
7357648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        mPanoLayout = findViewById(R.id.pano_layout);
736d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang
737ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong        mRotateDialog = new RotateDialogController(this, R.layout.rotate_dialog);
738d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang
739d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang        if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
740d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang            Rotatable[] rotateLayout = {
741d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang                    (Rotatable) findViewById(R.id.pano_pan_progress_bar_layout),
742d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang                    (Rotatable) findViewById(R.id.pano_capture_too_fast_textview_layout),
743d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang                    (Rotatable) findViewById(R.id.pano_review_saving_indication_layout),
744d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang                    (Rotatable) findViewById(R.id.pano_saving_progress_bar_layout),
745d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang                    (Rotatable) findViewById(R.id.pano_review_cancel_button_layout),
746562db5a0ec57f65cf4014ce3f7dad0f9324bb2f1Angus Kong                    (Rotatable) findViewById(R.id.pano_rotate_reviewarea),
747d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang                    (Rotatable) mRotateDialog,
7483a3fd8f6cf7c939cacbd3da09e80d3df074a00e4Angus Kong                    (Rotatable) mCaptureIndicator,
7493a3fd8f6cf7c939cacbd3da09e80d3df074a00e4Angus Kong                    (Rotatable) mModePicker,
7503a3fd8f6cf7c939cacbd3da09e80d3df074a00e4Angus Kong                    (Rotatable) mThumbnailView};
751d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang            for (Rotatable r : rotateLayout) {
752d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang                r.setOrientation(270);
753d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang            }
754d33109730e0ab81230f84e2bd35599e8e24fc4baChung-yih Wang        }
755bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
756bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
757fcdf619d92701052621a96572d956d047e07cf24Angus Kong    @Override
7581bca5eaaa3c6d3fd36df572546715e4e515cf9e6Wu-cheng Li    public void onShutterButtonClick() {
7592faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // If mSurfaceTexture == null then GL setup is not finished yet.
7602faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        // No buttons can be pressed.
7612faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        if (mPausing || mThreadRunning || mSurfaceTexture == null) return;
762a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        // Since this button will stay on the screen when capturing, we need to check the state
763a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        // right now.
764fcdf619d92701052621a96572d956d047e07cf24Angus Kong        switch (mCaptureState) {
765fcdf619d92701052621a96572d956d047e07cf24Angus Kong            case CAPTURE_STATE_VIEWFINDER:
7661461b5333aab31faee65272d64c2ac7f9809d4d0Eino-Ville Talvala                mCameraSound.play(MediaActionSound.START_VIDEO_RECORDING);
767fcdf619d92701052621a96572d956d047e07cf24Angus Kong                startCapture();
768fcdf619d92701052621a96572d956d047e07cf24Angus Kong                break;
769fcdf619d92701052621a96572d956d047e07cf24Angus Kong            case CAPTURE_STATE_MOSAIC:
7701461b5333aab31faee65272d64c2ac7f9809d4d0Eino-Ville Talvala                mCameraSound.play(MediaActionSound.STOP_VIDEO_RECORDING);
77127c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong                stopCapture(false);
772a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        }
773739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong    }
774739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong
775fcdf619d92701052621a96572d956d047e07cf24Angus Kong    @Override
7761bca5eaaa3c6d3fd36df572546715e4e515cf9e6Wu-cheng Li    public void onShutterButtonFocus(boolean pressed) {
777142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
778142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
779215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    public void reportProgress() {
780215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.reset();
781215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mSavingProgressBar.setRightIncreasing(true);
78250b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        Thread t = new Thread() {
78350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            @Override
78450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            public void run() {
7856f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                while (mThreadRunning) {
786e1178a73fd5756771d25d0b8375452450f509e99mbansal                    final int progress = mMosaicFrameProcessor.reportProgress(
787215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                            true, mCancelComputation);
78850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
7896f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                    try {
790215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                        synchronized (mWaitObject) {
791215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                            mWaitObject.wait(50);
792215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                        }
793215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                    } catch (InterruptedException e) {
7946f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                        throw new RuntimeException("Panorama reportProgress failed", e);
7956f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                    }
7966f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong                    // Update the progress bar
79750b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    runOnUiThread(new Runnable() {
79850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                        public void run() {
799215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong                            mSavingProgressBar.setProgress(progress);
80050b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                        }
80150b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                    });
80250b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal                }
80350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal            }
80450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        };
80550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        t.start();
80650b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal    }
80750b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
80882dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner    private void initThumbnailButton() {
80982dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner        // Load the thumbnail from the disk.
81082dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner        if (mThumbnail == null) {
81182dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner            mThumbnail = Thumbnail.loadFrom(new File(getFilesDir(), Thumbnail.LAST_THUMB_FILENAME));
81282dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner        }
81382dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner        updateThumbnailButton();
81482dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner    }
81582dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner
8169a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner    private void updateThumbnailButton() {
8179a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        // Update last image if URI is invalid and the storage is ready.
8189a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        ContentResolver contentResolver = getContentResolver();
8199a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        if ((mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), contentResolver))) {
8209a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner            mThumbnail = Thumbnail.getLastThumbnail(contentResolver);
8219a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        }
8229a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        if (mThumbnail != null) {
8239a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner            mThumbnailView.setBitmap(mThumbnail.getBitmap());
8249a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        } else {
8259a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner            mThumbnailView.setBitmap(null);
8269a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner        }
8279a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner    }
8289a7cba43937e7c74ebd9778bca40afc89145e3e1Mark Wagner
82962bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong    private void saveThumbnailToFile() {
83062bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        if (mThumbnail != null && !mThumbnail.fromFile()) {
83162bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong            mThumbnail.saveTo(new File(getFilesDir(), Thumbnail.LAST_THUMB_FILENAME));
83262bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        }
83362bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong    }
83462bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong
835215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    public void saveHighResMosaic() {
836215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        runBackgroundThread(new Thread() {
837142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            @Override
838142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            public void run() {
83962bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                mPartialWakeLock.acquire();
84062bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                MosaicJpeg jpeg;
84162bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                try {
84262bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                    jpeg = generateFinalMosaic(true);
84362bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                } finally {
84462bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                    mPartialWakeLock.release();
84562bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong                }
846e1178a73fd5756771d25d0b8375452450f509e99mbansal
84713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                if (jpeg == null) {  // Cancelled by user.
84813e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    mMainHandler.sendEmptyMessage(MSG_RESET_TO_PREVIEW);
84913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                } else if (!jpeg.isValid) {  // Error when generating mosaic.
85013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR);
85122d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                } else {
852e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    // The panorama image returned from the library is orientated based on the
853e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    // natural orientation of a camera. We need to set an orientation for the image
854e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    // in its EXIF header, so the image can be displayed correctly.
855e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    // The orientation is calculated from compensating the
856e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    // device orientation at capture and the camera orientation respective to
857e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    // the natural orientation of the device.
858e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    int orientation = (mDeviceOrientationAtCapture + mCameraOrientation) % 360;
859ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong                    Uri uri = savePanorama(jpeg.data, jpeg.width, jpeg.height, orientation);
86013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    if (uri != null) {
86166188959498860c8b43ab7b9119c7b5c890c83dcWei-Ta Chen                        // Create a thumbnail whose width or height is equal or bigger
86266188959498860c8b43ab7b9119c7b5c890c83dcWei-Ta Chen                        // than the screen's width or height.
86366188959498860c8b43ab7b9119c7b5c890c83dcWei-Ta Chen                        int widthRatio = (int) Math.ceil((double) jpeg.width
86466188959498860c8b43ab7b9119c7b5c890c83dcWei-Ta Chen                                / mPanoLayout.getWidth());
86566188959498860c8b43ab7b9119c7b5c890c83dcWei-Ta Chen                        int heightRatio = (int) Math.ceil((double) jpeg.height
86666188959498860c8b43ab7b9119c7b5c890c83dcWei-Ta Chen                                / mPanoLayout.getHeight());
86766188959498860c8b43ab7b9119c7b5c890c83dcWei-Ta Chen                        int inSampleSize = Integer.highestOneBit(
86866188959498860c8b43ab7b9119c7b5c890c83dcWei-Ta Chen                                Math.max(widthRatio, heightRatio));
86913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                        mThumbnail = Thumbnail.createThumbnail(
87013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                                jpeg.data, orientation, inSampleSize, uri);
871d22fff61ae44ea5213aeb91f400bfe1456411d25Angus Kong                        Util.broadcastNewPicture(PanoramaActivity.this, uri);
87222d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong                    }
87313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                    mMainHandler.sendMessage(
87413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong                            mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL));
875a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong                }
876142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            }
8775fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        });
878215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        reportProgress();
879215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    }
880215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong
881215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong    private void runBackgroundThread(Thread thread) {
8825fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mThreadRunning = true;
8835fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        thread.start();
8845fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    }
8855fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong
8865fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong    private void onBackgroundThreadFinished() {
8875fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong        mThreadRunning = false;
888ae557ecc220f9d491e8c65b1c895827fbedcdafeAngus Kong        mRotateDialog.dismissDialog();
889142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
890142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
891ef011a1e479f8e801318eba2dccb50fac1590d3cAngus Kong    private void cancelHighResComputation() {
892215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        mCancelComputation = true;
893215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        synchronized (mWaitObject) {
894215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong            mWaitObject.notify();
895215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong        }
896142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
897142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
898a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    @OnClickAttr
899ef011a1e479f8e801318eba2dccb50fac1590d3cAngus Kong    public void onCancelButtonClicked(View v) {
900ef011a1e479f8e801318eba2dccb50fac1590d3cAngus Kong        if (mPausing || mSurfaceTexture == null) return;
901ef011a1e479f8e801318eba2dccb50fac1590d3cAngus Kong        cancelHighResComputation();
902ef011a1e479f8e801318eba2dccb50fac1590d3cAngus Kong    }
903ef011a1e479f8e801318eba2dccb50fac1590d3cAngus Kong
904ef011a1e479f8e801318eba2dccb50fac1590d3cAngus Kong    @OnClickAttr
905a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    public void onThumbnailClicked(View v) {
906a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        if (mPausing || mThreadRunning || mSurfaceTexture == null) return;
907a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        showSharePopup();
908a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    }
909a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong
910a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    private void showSharePopup() {
911a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        if (mThumbnail == null) return;
912a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        Uri uri = mThumbnail.getUri();
913a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        if (mSharePopup == null || !uri.equals(mSharePopup.getUri())) {
914a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong            // The orientation compensation is set to 0 here because we only support landscape.
9155201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner            mSharePopup = new SharePopup(this, uri, mThumbnail.getBitmap(),
9165201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner                    mOrientationCompensation,
917977d06c6278cb7b131ed3c0960853d9168aacbddWu-cheng Li                    findViewById(R.id.frame_layout));
918a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        }
919a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        mSharePopup.showAtLocation(mThumbnailView, Gravity.NO_GRAVITY, 0, 0);
920a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong    }
921a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong
92227c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong    private void reset() {
923a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_VIEWFINDER;
92441a2e9735136f372de95652d0828600282c8e967mbansal
92541a2e9735136f372de95652d0828600282c8e967mbansal        mReviewLayout.setVisibility(View.GONE);
926fcdf619d92701052621a96572d956d047e07cf24Angus Kong        mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan);
927057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong        mPanoProgressBar.setVisibility(View.GONE);
92860fc534ec8f68d95a486984cb396a2da0e200518Angus Kong        mCaptureLayout.setVisibility(View.VISIBLE);
929142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.reset();
93041a2e9735136f372de95652d0828600282c8e967mbansal
9312faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mSurfaceTexture.setOnFrameAvailableListener(this);
93227c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong    }
93341a2e9735136f372de95652d0828600282c8e967mbansal
93427c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong    private void resetToPreview() {
93527c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        reset();
93636839102e03107e3fb121197036365a58ec2686eAngus Kong        if (!mPausing) startCameraPreview();
937142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
938142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
939142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void showFinalMosaic(Bitmap bitmap) {
940142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (bitmap != null) {
941142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            mReview.setImageBitmap(bitmap);
942142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
943ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mCaptureLayout.setVisibility(View.GONE);
944ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        mReviewLayout.setVisibility(View.VISIBLE);
945142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
946142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
947ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong    private Uri savePanorama(byte[] jpegData, int width, int height, int orientation) {
948ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (jpegData != null) {
949e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            String filename = PanoUtil.createName(
950ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                    getResources().getString(R.string.pano_file_name_format), mTimeTaken);
951e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            Uri uri = Storage.addImage(getContentResolver(), filename, mTimeTaken, null,
952ea312297ff6132bbafed99b90a72e4858b888fa4Angus Kong                    orientation, jpegData, width, height);
953e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            if (uri != null && orientation != 0) {
954e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                String filepath = Storage.generateFilepath(filename);
955e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                try {
956e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    // Save the orientation in EXIF.
957e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    ExifInterface exif = new ExifInterface(filepath);
958e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    exif.setAttribute(ExifInterface.TAG_ORIENTATION,
959e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                            getExifOrientation(orientation));
960e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    exif.saveAttributes();
961e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                } catch (IOException e) {
962e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                    Log.e(TAG, "cannot set exif data: " + filepath);
963e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                }
964e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            }
965e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            return uri;
966142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
967a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong        return null;
968142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
969142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
970e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen    private static String getExifOrientation(int orientation) {
971e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen        switch (orientation) {
972e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            case 0:
973e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                return String.valueOf(ExifInterface.ORIENTATION_NORMAL);
974e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            case 90:
975e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                return String.valueOf(ExifInterface.ORIENTATION_ROTATE_90);
976e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            case 180:
977e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                return String.valueOf(ExifInterface.ORIENTATION_ROTATE_180);
978e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            case 270:
979e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                return String.valueOf(ExifInterface.ORIENTATION_ROTATE_270);
980e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen            default:
981e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen                throw new AssertionError("invalid: " + orientation);
982e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen        }
983e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen    }
984e0bbb93f6a598206ecd6e09150d51eae64bd3507Wei-Ta Chen
985142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void clearMosaicFrameProcessorIfNeeded() {
986142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (!mPausing || mThreadRunning) return;
987142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.clear();
988142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    }
989142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong
990142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong    private void initMosaicFrameProcessorIfNeeded() {
991142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mPausing || mThreadRunning) return;
992142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        if (mMosaicFrameProcessor == null) {
993142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong            // Start the activity for the first time.
994c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong            mMosaicFrameProcessor = new MosaicFrameProcessor(
9950adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen                    mPreviewWidth, mPreviewHeight, getPreviewBufSize());
996142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        }
997142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mMosaicFrameProcessor.initialize();
998bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
999bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
1000bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
1001bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    protected void onPause() {
1002bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen        super.onPause();
10034d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong
1004142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = true;
100527c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        // Stop the capturing first.
100627c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        if (mCaptureState == CAPTURE_STATE_MOSAIC) {
100727c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong            stopCapture(true);
100827c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong            reset();
100927c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        }
10108b084a607d0b207272d5c87fecbb5d33cbef1b4fMark Wagner        if (mSharePopup != null) mSharePopup.dismiss();
10115201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner
101262bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        saveThumbnailToFile();
10135201b1e0051877d8e8ed0ef5b461ffcac534eb5cMark Wagner
101427c7ab8a5d3dd50a62be80900abe6890c7182956Angus Kong        releaseCamera();
10152faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        mMosaicView.onPause();
1016142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        clearMosaicFrameProcessorIfNeeded();
1017c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mOrientationEventListener.disable();
1018bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        resetScreenOn();
101990089f9eddde732725c43dcad07f4567ed8cb776Wu-cheng Li        mCameraSound.release();
102094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen        System.gc();
1021bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
1022bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
1023bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    @Override
10247d9eadd0c6c38b3761b7e8d3fa3658d194810d60Jim Miller    protected void doOnResume() {
1025142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong        mPausing = false;
1026c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong        mOrientationEventListener.enable();
1027215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong
1028a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong        mCaptureState = CAPTURE_STATE_VIEWFINDER;
102980583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang        try {
103080583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            setupCamera();
1031575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi
103280583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            // Camera must be initialized before MosaicFrameProcessor is initialized.
103380583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            // The preview size has to be decided by camera device.
103480583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            initMosaicFrameProcessorIfNeeded();
103580583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            mMosaicView.onResume();
103682dd2a3b7ba88a3ea051d2b3960310891a243dadMark Wagner
103780583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            initThumbnailButton();
103880583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            keepScreenOnAwhile();
103980583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang        } catch (CameraHardwareException e) {
104080583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            Util.showErrorAndFinish(this, R.string.cannot_connect_camera);
1041749d056cd82ebfe6e613596d9e22dd355aeeec41Chung-yih Wang            return;
104280583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang        } catch (CameraDisabledException e) {
104380583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang            Util.showErrorAndFinish(this, R.string.camera_disabled);
1044749d056cd82ebfe6e613596d9e22dd355aeeec41Chung-yih Wang            return;
104580583a299a9c8964cf09e482380c3bda0670ad6fChih-yu Huang        }
1046749d056cd82ebfe6e613596d9e22dd355aeeec41Chung-yih Wang        // Dismiss open menu if exists.
1047749d056cd82ebfe6e613596d9e22dd355aeeec41Chung-yih Wang        PopupManager.getInstance(this).notifyShowPopup(null);
1048bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
1049bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
10500a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen    /**
10510a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen     * Generate the final mosaic image.
10520a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen     *
10530a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen     * @param highRes flag to indicate whether we want to get a high-res version.
10540a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen     * @return a MosaicJpeg with its isValid flag set to true if successful; null if the generation
10550a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen     *         process is cancelled; and a MosaicJpeg with its isValid flag set to false if there
10560a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen     *         is an error in generating the final mosaic.
10570a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen     */
10587648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li    public MosaicJpeg generateFinalMosaic(boolean highRes) {
10590a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen        int mosaicReturnCode = mMosaicFrameProcessor.createMosaic(highRes);
10600a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen        if (mosaicReturnCode == Mosaic.MOSAIC_RET_CANCELLED) {
1061e1178a73fd5756771d25d0b8375452450f509e99mbansal            return null;
10620a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen        } else if (mosaicReturnCode == Mosaic.MOSAIC_RET_ERROR) {
10630a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen            return new MosaicJpeg();
106413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong        }
1065bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen
1066ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21();
1067ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        if (imageData == null) {
1068ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "getFinalMosaicNV21() returned null.");
106913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            return new MosaicJpeg();
10708a2c41754655a3733175fce81fb7506ff7022959Angus Kong        }
10718a2c41754655a3733175fce81fb7506ff7022959Angus Kong
1072ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int len = imageData.length - 8;
1073ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16)
1074ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF);
1075ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16)
1076ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong                + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF);
1077ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height);
10788a2c41754655a3733175fce81fb7506ff7022959Angus Kong
1079e46486104523760a4433f03e09ed615987d83b6cAngus Kong        if (width <= 0 || height <= 0) {
1080e46486104523760a4433f03e09ed615987d83b6cAngus Kong            // TODO: pop up a error meesage indicating that the final result is not generated.
1081e46486104523760a4433f03e09ed615987d83b6cAngus Kong            Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " +
1082e46486104523760a4433f03e09ed615987d83b6cAngus Kong                    height);
108313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            return new MosaicJpeg();
1084e46486104523760a4433f03e09ed615987d83b6cAngus Kong        }
1085e46486104523760a4433f03e09ed615987d83b6cAngus Kong
1086ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null);
1087ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        ByteArrayOutputStream out = new ByteArrayOutputStream();
1088ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out);
1089ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        try {
1090ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            out.close();
1091ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        } catch (Exception e) {
1092ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong            Log.e(TAG, "Exception in storing final mosaic", e);
109313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong            return new MosaicJpeg();
1094ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong        }
10957648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li        return new MosaicJpeg(out.toByteArray(), width, height);
1096bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen    }
10978a2c41754655a3733175fce81fb7506ff7022959Angus Kong
109841a2e9735136f372de95652d0828600282c8e967mbansal    private void setPreviewTexture(SurfaceTexture surface) {
109998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
110041a2e9735136f372de95652d0828600282c8e967mbansal            mCameraDevice.setPreviewTexture(surface);
110198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
110298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
110341a2e9735136f372de95652d0828600282c8e967mbansal            throw new RuntimeException("setPreviewTexture failed", ex);
110498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
110598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
110698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
110736839102e03107e3fb121197036365a58ec2686eAngus Kong    private void startCameraPreview() {
110898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // If we're previewing already, stop the preview first (this will blank
110998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        // the screen).
111036839102e03107e3fb121197036365a58ec2686eAngus Kong        if (mCameraState != PREVIEW_STOPPED) stopCameraPreview();
111198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
1112d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // Set the display orientation to 0, so that the underlying mosaic library
1113d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // can always get undistorted mPreviewWidth x mPreviewHeight image data
1114d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        // from SurfaceTexture.
1115d32aa042a7d7fdb52cd8cec571e7c648f837eaffWei-Ta Chen        mCameraDevice.setDisplayOrientation(0);
1116575b49275691f5b539fe2c6dfde1741645dc3e93Raji Reddy Kandi
11172faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong        setPreviewTexture(mSurfaceTexture);
111898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
111998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        try {
112098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "startPreview");
112198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.startPreview();
112298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        } catch (Throwable ex) {
112398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            releaseCamera();
112498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            throw new RuntimeException("startPreview failed", ex);
112598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
112698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_ACTIVE;
112798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
112898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen
112936839102e03107e3fb121197036365a58ec2686eAngus Kong    private void stopCameraPreview() {
113098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) {
113198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            Log.v(TAG, "stopPreview");
113298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen            mCameraDevice.stopPreview();
113398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        }
113498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen        mCameraState = PREVIEW_STOPPED;
113598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen    }
1136bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang
1137bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    @Override
1138bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    public void onUserInteraction() {
1139bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        super.onUserInteraction();
1140bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        if (mCaptureState != CAPTURE_STATE_MOSAIC) keepScreenOnAwhile();
1141bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    }
1142bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang
114362bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong    @Override
114462bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong    public void onBackPressed() {
114562bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        // If panorama is generating low res or high res mosaic, ignore back
114662bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        // key. So the activity will not be destroyed.
114762bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        if (mThreadRunning) return;
114862bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong        super.onBackPressed();
114962bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong    }
115062bbca8320c3861fa9b18a7eab26a42116bef9dfAngus Kong
1151bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    private void resetScreenOn() {
1152bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY);
1153bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1154bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    }
1155bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang
1156bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    private void keepScreenOnAwhile() {
1157bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY);
1158bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1159bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_DELAY, SCREEN_DELAY);
1160bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    }
1161bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang
1162bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    private void keepScreenOn() {
1163bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY);
1164bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
1165bc85294715ce88c8378af3b77f7a0d27d7ceeabaChih-Chung Chang    }
1166bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen}
1167