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