PanoramaActivity.java revision 6108e0ed3a6b03deed2a8586d98607a6756637b1
1bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen/* 2bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Copyright (C) 2011 The Android Open Source Project 3bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * 4bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Licensed under the Apache License, Version 2.0 (the "License"); 5bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * you may not use this file except in compliance with the License. 6bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * You may obtain a copy of the License at 7bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * 8bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * http://www.apache.org/licenses/LICENSE-2.0 9bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * 10bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Unless required by applicable law or agreed to in writing, software 11bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * distributed under the License is distributed on an "AS IS" BASIS, 12bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * See the License for the specific language governing permissions and 14bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * limitations under the License. 15bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen */ 16bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 17bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenpackage com.android.camera.panorama; 18bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 19d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraDisabledException; 20d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraHardwareException; 21d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraHolder; 22a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.Exif; 23d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.MenuHelper; 24d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.ModePicker; 25a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.OnClickAttr; 26d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.R; 27fcdf619d92701052621a96572d956d047e07cf24Angus Kongimport com.android.camera.ShutterButton; 28d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Storage; 29a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.Thumbnail; 30d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Util; 31a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.ui.RotateImageView; 32a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kongimport com.android.camera.ui.SharePopup; 33d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Li 342f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kongimport android.animation.Animator; 352f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kongimport android.animation.AnimatorInflater; 36b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kongimport android.animation.AnimatorSet; 372f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kongimport android.animation.ObjectAnimator; 38b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kongimport android.animation.ValueAnimator; 39bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.app.Activity; 4022d4b7fbace56c03092eb088a4df98e04a6681afAngus Kongimport android.app.AlertDialog; 415fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kongimport android.app.ProgressDialog; 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; 65c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kongimport android.view.OrientationEventListener; 66bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.View; 67bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.WindowManager; 68b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kongimport android.view.animation.LinearInterpolator; 69bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.widget.ImageView; 702f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kongimport android.widget.RelativeLayout; 71fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kongimport android.widget.TextView; 72bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 73ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport java.io.ByteArrayOutputStream; 74bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport java.util.List; 75bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 76a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong/** 77a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong * Activity to handle panorama capturing. 78a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong */ 7998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chenpublic class PanoramaActivity extends Activity implements 80fcdf619d92701052621a96572d956d047e07cf24Angus Kong ModePicker.OnModeChangeListener, SurfaceTexture.OnFrameAvailableListener, 81fcdf619d92701052621a96572d956d047e07cf24Angus Kong ShutterButton.OnShutterButtonListener, 8236839102e03107e3fb121197036365a58ec2686eAngus Kong MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener { 83ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong public static final int DEFAULT_SWEEP_ANGLE = 160; 84bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; 85bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; 86bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 872f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong private static final int MSG_LOW_RES_FINAL_MOSAIC_READY = 1; 88a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong private static final int MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL = 2; 8922d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong private static final int MSG_GENERATE_FINAL_MOSAIC_ERROR = 3; 9022d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong private static final int MSG_DISMISS_ALERT_DIALOG_AND_RESET_TO_PREVIEW = 4; 9113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong private static final int MSG_RESET_TO_PREVIEW = 5; 9294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 93ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private static final String TAG = "PanoramaActivity"; 9498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private static final int PREVIEW_STOPPED = 0; 9598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private static final int PREVIEW_ACTIVE = 1; 96a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong private static final int CAPTURE_STATE_VIEWFINDER = 0; 97a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong private static final int CAPTURE_STATE_MOSAIC = 1; 9841a2e9735136f372de95652d0828600282c8e967mbansal 9943b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // Speed is in unit of deg/sec 100e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen private static final float PANNING_SPEED_THRESHOLD = 20f; 10143b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen 102a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong // Ratio of nanosecond to second 103a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private static final float NS2S = 1.0f / 1000000000.0f; 104142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 105142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private boolean mPausing; 106142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 1077648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li private View mPanoLayout; 108a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private View mCaptureLayout; 109a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private View mReviewLayout; 110bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private ImageView mReview; 1118df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong private TextView mCaptureIndicator; 112057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong private PanoProgressBar mPanoProgressBar; 113215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong private PanoProgressBar mSavingProgressBar; 1146108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong private View mLeftIndicator; 1156108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong private View mRightIndicator; 1162faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong private MosaicRendererSurfaceView mMosaicView; 117fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong private TextView mTooFastPrompt; 118fcdf619d92701052621a96572d956d047e07cf24Angus Kong private ShutterButton mShutterButton; 119215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong private Object mWaitObject = new Object(); 120142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 1215fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong private String mPreparePreviewString; 1222f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong private AlertDialog mAlertDialog; 123215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong private ProgressDialog mProgressDialog; 12422d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong private String mDialogTitle; 12522d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong private String mDialogOk; 1262f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong 127c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private float mCompassValueX; 128c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private float mCompassValueY; 129c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private float mCompassValueXStart; 130c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private float mCompassValueYStart; 131c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private float mCompassValueXStartBuffer; 132c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private float mCompassValueYStartBuffer; 133c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private int mCompassThreshold; 134c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private int mTraversedAngleX; 135c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private int mTraversedAngleY; 136c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private long mTimestamp; 137c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong // Control variables for the terminate condition. 138c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private int mMinAngleX; 139c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private int mMaxAngleX; 140c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private int mMinAngleY; 141c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private int mMaxAngleY; 142c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong 143a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong private RotateImageView mThumbnailView; 144a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong private Thumbnail mThumbnail; 145a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong private SharePopup mSharePopup; 146a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong 147b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong private AnimatorSet mThumbnailViewAndModePickerOut; 148b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong private AnimatorSet mThumbnailViewAndModePickerIn; 149b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong 150bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private int mPreviewWidth; 151bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private int mPreviewHeight; 1528a2c41754655a3733175fce81fb7506ff7022959Angus Kong private Camera mCameraDevice; 15398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private int mCameraState; 15441a2e9735136f372de95652d0828600282c8e967mbansal private int mCaptureState; 155bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private SensorManager mSensorManager; 156bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private Sensor mSensor; 157a72d73cbac59db43d413291e4db66763be08143arepo sync private ModePicker mModePicker; 1588a2c41754655a3733175fce81fb7506ff7022959Angus Kong private MosaicFrameProcessor mMosaicFrameProcessor; 1598a2c41754655a3733175fce81fb7506ff7022959Angus Kong private long mTimeTaken; 160ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private Handler mMainHandler; 1612faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong private SurfaceTexture mSurfaceTexture; 162142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private boolean mThreadRunning; 163e1178a73fd5756771d25d0b8375452450f509e99mbansal private boolean mCancelComputation; 1642faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong private float[] mTransformMatrix; 16543b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen private float mHorizontalViewAngle; 166c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong 167c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private PanoOrientationEventListener mOrientationEventListener; 168c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong // The value could be 0, 1, 2, 3 for the 4 different orientations measured in clockwise 169c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong // respectively. 170c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private int mDeviceOrientation; 171142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 1727648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li private class MosaicJpeg { 1737648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li public MosaicJpeg(byte[] data, int width, int height) { 1747648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li this.data = data; 1757648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li this.width = width; 1767648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li this.height = height; 17713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong this.isValid = true; 17813e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong } 17913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong 18013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong public MosaicJpeg() { 18113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong this.data = null; 18213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong this.width = 0; 18313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong this.height = 0; 18413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong this.isValid = false; 1857648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li } 1867648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li 1877648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li public final byte[] data; 1887648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li public final int width; 1897648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li public final int height; 19013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong public final boolean isValid; 1917648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li } 1927648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li 193c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private class PanoOrientationEventListener extends OrientationEventListener { 194c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong public PanoOrientationEventListener(Context context) { 195c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong super(context); 196c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong } 197c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong 198c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong @Override 199c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong public void onOrientationChanged(int orientation) { 200c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong // Default to the last known orientation. 201c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong if (orientation == ORIENTATION_UNKNOWN) return; 202c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mDeviceOrientation = ((orientation + 45) / 90) % 4; 203c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong } 204c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong } 205c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong 206bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 207bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onCreate(Bundle icicle) { 208bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen super.onCreate(icicle); 209bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 210bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, 211bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 212e0861e7473d042bdd9c935f3bdf50ae220891b6cWu-cheng Li Util.enterLightsOutMode(getWindow()); 213bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 214bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen createContentView(); 215bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 216bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 217bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 218bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (mSensor == null) { 219bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); 220bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 2218a2c41754655a3733175fce81fb7506ff7022959Angus Kong 222c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mOrientationEventListener = new PanoOrientationEventListener(this); 223c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong 2242faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mTransformMatrix = new float[16]; 2252faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong 2265fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong mPreparePreviewString = 2275fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong getResources().getString(R.string.pano_dialog_prepare_preview); 22822d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong mDialogTitle = getResources().getString(R.string.pano_dialog_title); 22922d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong mDialogOk = getResources().getString(R.string.dialog_ok); 2305fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong 231ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong mMainHandler = new Handler() { 232ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong @Override 233ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong public void handleMessage(Message msg) { 234ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong switch (msg.what) { 2352f9ed6f52580b8fecb77ec3ca123a804eea89f8cAngus Kong case MSG_LOW_RES_FINAL_MOSAIC_READY: 2365fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong onBackgroundThreadFinished(); 237142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong showFinalMosaic((Bitmap) msg.obj); 238215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong saveHighResMosaic(); 239142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong break; 240a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong case MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL: 2415fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong onBackgroundThreadFinished(); 242a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong // Set the thumbnail bitmap here because mThumbnailView must be accessed 243a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong // from the UI thread. 244a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong if (mThumbnail != null) { 245a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong mThumbnailView.setBitmap(mThumbnail.getBitmap()); 246a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong } 247142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong resetToPreview(); 248142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong break; 24922d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong case MSG_GENERATE_FINAL_MOSAIC_ERROR: 25022d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong onBackgroundThreadFinished(); 25122d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong mAlertDialog = (new AlertDialog.Builder(PanoramaActivity.this)) 25222d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong .setTitle(mDialogTitle) 25322d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong .setMessage(R.string.pano_dialog_panorama_failed) 25422d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong .create(); 25522d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong mAlertDialog.setButton(DialogInterface.BUTTON_POSITIVE, mDialogOk, 25622d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong obtainMessage(MSG_DISMISS_ALERT_DIALOG_AND_RESET_TO_PREVIEW)); 25722d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong mAlertDialog.show(); 25822d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong break; 25922d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong case MSG_DISMISS_ALERT_DIALOG_AND_RESET_TO_PREVIEW: 26022d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong mAlertDialog.dismiss(); 26122d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong mAlertDialog = null; 26222d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong resetToPreview(); 26322d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong break; 26413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong case MSG_RESET_TO_PREVIEW: 265e1178a73fd5756771d25d0b8375452450f509e99mbansal onBackgroundThreadFinished(); 266e1178a73fd5756771d25d0b8375452450f509e99mbansal resetToPreview(); 267ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 268142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong clearMosaicFrameProcessorIfNeeded(); 269ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 270ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong }; 271bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 272bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 273bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void setupCamera() { 274bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen openCamera(); 275bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Parameters parameters = mCameraDevice.getParameters(); 276bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen setupCaptureParams(parameters); 277bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen configureCamera(parameters); 278bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 279bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 280ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private void releaseCamera() { 281ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong if (mCameraDevice != null) { 282142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mCameraDevice.setPreviewCallbackWithBuffer(null); 283ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong CameraHolder.instance().release(); 284ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong mCameraDevice = null; 28598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_STOPPED; 286ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 287ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 288ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong 289bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void openCamera() { 290bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen try { 291bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId()); 292bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } catch (CameraHardwareException e) { 293bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Util.showErrorAndFinish(this, R.string.cannot_connect_camera); 294bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return; 295bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } catch (CameraDisabledException e) { 296bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Util.showErrorAndFinish(this, R.string.camera_disabled); 297bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return; 298bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 299bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 300bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 301bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, 302bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen boolean needSmaller) { 303bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int pixelsDiff = DEFAULT_CAPTURE_PIXELS; 304bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen boolean hasFound = false; 3058a2c41754655a3733175fce81fb7506ff7022959Angus Kong for (Size size : supportedSizes) { 306bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int h = size.height; 307bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int w = size.width; 308bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen // we only want 4:3 format. 309bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int d = DEFAULT_CAPTURE_PIXELS - h * w; 31094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen if (needSmaller && d < 0) { // no bigger preview than 960x720. 311bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen continue; 312bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 313bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (need4To3 && (h * 4 != w * 3)) { 314bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen continue; 315bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 316bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen d = Math.abs(d); 317bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (d < pixelsDiff) { 318bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mPreviewWidth = w; 319bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mPreviewHeight = h; 320bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen pixelsDiff = d; 321bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen hasFound = true; 322bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 323bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 324bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return hasFound; 325bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 326bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 327bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void setupCaptureParams(Parameters parameters) { 328bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); 329bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (!findBestPreviewSize(supportedSizes, true, true)) { 330bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.w(TAG, "No 4:3 ratio preview size supported."); 331bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (!findBestPreviewSize(supportedSizes, false, true)) { 332bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); 333bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen findBestPreviewSize(supportedSizes, false, false); 334bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 335bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 336bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth); 337bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen parameters.setPreviewSize(mPreviewWidth, mPreviewHeight); 338bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 339bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen List<int[]> frameRates = parameters.getSupportedPreviewFpsRange(); 340bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int last = frameRates.size() - 1; 341bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX]; 342bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX]; 343bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen parameters.setPreviewFpsRange(minFps, maxFps); 344bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.v(TAG, "preview fps: " + minFps + ", " + maxFps); 3453ab4f0912da83f7f5f8266a57a606d521c1649e3Wu-cheng Li 34693ad273a53e7d2975a67d7d1f8a157f845e41cf2Wu-cheng Li parameters.setRecordingHint(false); 34743b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen 348c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mHorizontalViewAngle = ((mDeviceOrientation % 2) == 0) ? 349c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong parameters.getHorizontalViewAngle() : parameters.getVerticalViewAngle(); 350bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 351bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 352bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public int getPreviewBufSize() { 353bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen PixelFormat pixelInfo = new PixelFormat(); 354bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo); 355bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen // TODO: remove this extra 32 byte after the driver bug is fixed. 356bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32; 357bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 358bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 359bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void configureCamera(Parameters parameters) { 360bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCameraDevice.setParameters(parameters); 361bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 3624b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li int orientation = Util.getDisplayOrientation(Util.getDisplayRotation(this), 3634b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li CameraHolder.instance().getBackCameraId()); 3644b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li mCameraDevice.setDisplayOrientation(orientation); 365bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 366bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 367a72d73cbac59db43d413291e4db66763be08143arepo sync private boolean switchToOtherMode(int mode) { 368a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong if (isFinishing()) { 36994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen return false; 370a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong } 371a72d73cbac59db43d413291e4db66763be08143arepo sync MenuHelper.gotoMode(mode, this); 372a72d73cbac59db43d413291e4db66763be08143arepo sync finish(); 373a72d73cbac59db43d413291e4db66763be08143arepo sync return true; 374a72d73cbac59db43d413291e4db66763be08143arepo sync } 375a72d73cbac59db43d413291e4db66763be08143arepo sync 376a72d73cbac59db43d413291e4db66763be08143arepo sync public boolean onModeChanged(int mode) { 377a72d73cbac59db43d413291e4db66763be08143arepo sync if (mode != ModePicker.MODE_PANORAMA) { 378a72d73cbac59db43d413291e4db66763be08143arepo sync return switchToOtherMode(mode); 379a72d73cbac59db43d413291e4db66763be08143arepo sync } else { 380a72d73cbac59db43d413291e4db66763be08143arepo sync return true; 381a72d73cbac59db43d413291e4db66763be08143arepo sync } 382a72d73cbac59db43d413291e4db66763be08143arepo sync } 383a72d73cbac59db43d413291e4db66763be08143arepo sync 3842faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong @Override 3852faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong public void onMosaicSurfaceCreated(final int textureID) { 38636839102e03107e3fb121197036365a58ec2686eAngus Kong runOnUiThread(new Runnable() { 38736839102e03107e3fb121197036365a58ec2686eAngus Kong @Override 38836839102e03107e3fb121197036365a58ec2686eAngus Kong public void run() { 3892faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong if (mSurfaceTexture != null) { 3902faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mSurfaceTexture.release(); 3912faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong } 3922faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mSurfaceTexture = new SurfaceTexture(textureID); 3932faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong if (!mPausing) { 3942faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mSurfaceTexture.setOnFrameAvailableListener(PanoramaActivity.this); 3952faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong startCameraPreview(); 3962faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong } 39736839102e03107e3fb121197036365a58ec2686eAngus Kong } 39836839102e03107e3fb121197036365a58ec2686eAngus Kong }); 39936839102e03107e3fb121197036365a58ec2686eAngus Kong } 40036839102e03107e3fb121197036365a58ec2686eAngus Kong 40141a2e9735136f372de95652d0828600282c8e967mbansal public void runViewFinder() { 4022faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.setWarping(false); 4032faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong // Call preprocess to render it to low-res and high-res RGB textures. 4042faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.preprocess(mTransformMatrix); 4052faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.setReady(); 4062faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.requestRender(); 40741a2e9735136f372de95652d0828600282c8e967mbansal } 40841a2e9735136f372de95652d0828600282c8e967mbansal 40941a2e9735136f372de95652d0828600282c8e967mbansal public void runMosaicCapture() { 4102faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.setWarping(true); 4112faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong // Call preprocess to render it to low-res and high-res RGB textures. 4122faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.preprocess(mTransformMatrix); 4132faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong // Lock the conditional variable to ensure the order of transferGPUtoCPU and 4142faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong // mMosaicFrame.processFrame(). 4152faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.lockPreviewReadyFlag(); 41641a2e9735136f372de95652d0828600282c8e967mbansal // Now, transfer the textures from GPU to CPU memory for processing 4172faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.transferGPUtoCPU(); 41841a2e9735136f372de95652d0828600282c8e967mbansal // Wait on the condition variable (will be opened when GPU->CPU transfer is done). 4192faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.waitUntilPreviewReady(); 4200adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mMosaicFrameProcessor.processFrame(); 42141a2e9735136f372de95652d0828600282c8e967mbansal } 42241a2e9735136f372de95652d0828600282c8e967mbansal 423739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong public synchronized void onFrameAvailable(SurfaceTexture surface) { 4244d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong /* This function may be called by some random thread, 42541a2e9735136f372de95652d0828600282c8e967mbansal * so let's be safe and use synchronize. No OpenGL calls can be done here. 42641a2e9735136f372de95652d0828600282c8e967mbansal */ 4272faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong // Updating the texture should be done in the GL thread which mMosaicView is attached. 4282faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.queueEvent(new Runnable() { 4292faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong @Override 4302faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong public void run() { 4312faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mSurfaceTexture.updateTexImage(); 4322faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mSurfaceTexture.getTransformMatrix(mTransformMatrix); 4332faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong } 4342faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong }); 4352faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong // Update the transformation matrix for mosaic pre-process. 436a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong if (mCaptureState == CAPTURE_STATE_VIEWFINDER) { 43741a2e9735136f372de95652d0828600282c8e967mbansal runViewFinder(); 43841a2e9735136f372de95652d0828600282c8e967mbansal } else { 43941a2e9735136f372de95652d0828600282c8e967mbansal runMosaicCapture(); 44041a2e9735136f372de95652d0828600282c8e967mbansal } 44141a2e9735136f372de95652d0828600282c8e967mbansal } 44241a2e9735136f372de95652d0828600282c8e967mbansal 4436108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong private void hideDirectionIndicators() { 4446108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mLeftIndicator.setVisibility(View.GONE); 4456108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mRightIndicator.setVisibility(View.GONE); 4466108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong } 4476108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong 4486108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong private void showDirectionIndicators(int direction) { 4496108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong switch (direction) { 4506108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong case PanoProgressBar.DIRECTION_NONE: 4516108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mLeftIndicator.setVisibility(View.VISIBLE); 4526108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mRightIndicator.setVisibility(View.VISIBLE); 4536108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong break; 4546108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong case PanoProgressBar.DIRECTION_LEFT: 4556108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mLeftIndicator.setVisibility(View.VISIBLE); 4566108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mRightIndicator.setVisibility(View.GONE); 4576108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong break; 4586108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong case PanoProgressBar.DIRECTION_RIGHT: 4596108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mLeftIndicator.setVisibility(View.GONE); 4606108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mRightIndicator.setVisibility(View.VISIBLE); 4616108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong break; 4626108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong } 4636108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong } 4646108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong 465a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong public void startCapture() { 4668a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Reset values so we can do this again. 46713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong mCancelComputation = false; 4688a2c41754655a3733175fce81fb7506ff7022959Angus Kong mTimeTaken = System.currentTimeMillis(); 469a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong mCaptureState = CAPTURE_STATE_MOSAIC; 470fcdf619d92701052621a96572d956d047e07cf24Angus Kong mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan_recording); 4718df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong mCaptureIndicator.setVisibility(View.VISIBLE); 4726108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong showDirectionIndicators(PanoProgressBar.DIRECTION_NONE); 4738a2c41754655a3733175fce81fb7506ff7022959Angus Kong 474b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong // XML-style animations can not be used here. The Y position has to be calculated runtime. 475b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong float ystart = mThumbnailView.getY(); 476b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong ValueAnimator va1 = ObjectAnimator.ofFloat( 477b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailView, "y", ystart, -mThumbnailView.getHeight()); 478b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong ValueAnimator va1Reverse = ObjectAnimator.ofFloat( 479b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailView, "y", -mThumbnailView.getHeight(), ystart); 480b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong ystart = mModePicker.getY(); 481b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong float height = mCaptureLayout.getHeight(); 482b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong ValueAnimator va2 = ObjectAnimator.ofFloat( 483b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mModePicker, "y", ystart, height + 1); 484b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong ValueAnimator va2Reverse = ObjectAnimator.ofFloat( 485b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mModePicker, "y", height + 1, ystart); 486b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong LinearInterpolator li = new LinearInterpolator(); 487b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerOut = new AnimatorSet(); 488b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerOut.play(va1).with(va2); 489b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerOut.setDuration(500); 490b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerOut.setInterpolator(li); 491b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerIn = new AnimatorSet(); 492b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerIn.play(va1Reverse).with(va2Reverse); 493b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerIn.setDuration(500); 494b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerIn.setInterpolator(li); 495b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong 496b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerOut.start(); 497b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong 498c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mCompassValueXStart = mCompassValueXStartBuffer; 499c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mCompassValueYStart = mCompassValueYStartBuffer; 500c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMinAngleX = 0; 501c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMaxAngleX = 0; 502c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMinAngleY = 0; 503c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMaxAngleY = 0; 504c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mTimestamp = 0; 505c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong 5068a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() { 5078a2c41754655a3733175fce81fb7506ff7022959Angus Kong @Override 508c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong public void onProgress(boolean isFinished, float panningRateX, float panningRateY) { 509c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong if (isFinished 510c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong || (mMaxAngleX - mMinAngleX >= DEFAULT_SWEEP_ANGLE) 511c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong || (mMaxAngleY - mMinAngleY >= DEFAULT_SWEEP_ANGLE)) { 512a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong stopCapture(); 5138a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 514c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong updateProgress(panningRateX); 5158a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 5168a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 5178a2c41754655a3733175fce81fb7506ff7022959Angus Kong }); 5188a2c41754655a3733175fce81fb7506ff7022959Angus Kong 519057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.reset(); 520057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong // TODO: calculate the indicator width according to different devices to reflect the actual 521057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong // angle of view of the camera device. 522057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setIndicatorWidth(20); 523057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setMaxProgress(DEFAULT_SWEEP_ANGLE); 524057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setVisibility(View.VISIBLE); 5258a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 5268a2c41754655a3733175fce81fb7506ff7022959Angus Kong 527a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private void stopCapture() { 528a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong mCaptureState = CAPTURE_STATE_VIEWFINDER; 5290c9caf77ab90b173fbe2719ec6a78e588964ac33Wei-Ta Chen mTooFastPrompt.setVisibility(View.GONE); 5308df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong mCaptureIndicator.setVisibility(View.GONE); 5316108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong hideDirectionIndicators(); 53241a2e9735136f372de95652d0828600282c8e967mbansal 5338a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.setProgressListener(null); 53436839102e03107e3fb121197036365a58ec2686eAngus Kong stopCameraPreview(); 53541a2e9735136f372de95652d0828600282c8e967mbansal 5362faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mSurfaceTexture.setOnFrameAvailableListener(null); 53741a2e9735136f372de95652d0828600282c8e967mbansal 538142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (!mThreadRunning) { 539215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong showDialog(mPreparePreviewString); 540215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong runBackgroundThread(new Thread() { 541142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @Override 542142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void run() { 5437648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li MosaicJpeg jpeg = generateFinalMosaic(false); 544e1178a73fd5756771d25d0b8375452450f509e99mbansal 54513e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong if (jpeg != null && jpeg.isValid) { 546e1178a73fd5756771d25d0b8375452450f509e99mbansal Bitmap bitmap = null; 54713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length); 548e1178a73fd5756771d25d0b8375452450f509e99mbansal mMainHandler.sendMessage(mMainHandler.obtainMessage( 549e1178a73fd5756771d25d0b8375452450f509e99mbansal MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap)); 55013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong } else { 55113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong mMainHandler.sendMessage(mMainHandler.obtainMessage( 55213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong MSG_RESET_TO_PREVIEW)); 553ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } 554142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 5555fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong }); 556142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 557b3b80f6550f6a827e15b23abd780457cb26eebdfAngus Kong mThumbnailViewAndModePickerIn.start(); 5588a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 5598a2c41754655a3733175fce81fb7506ff7022959Angus Kong 560c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private void updateProgress(float panningRate) { 5612faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.setReady(); 5622faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.requestRender(); 563eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal 56443b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // TODO: Now we just display warning message by the panning speed. 56543b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // Since we only support horizontal panning, we should display a warning message 56643b0b2ccd5949ee8fc377c37e7e2b82a26c88ca8Wei-Ta Chen // in UI when there're significant vertical movements. 567c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong if (Math.abs(panningRate * mHorizontalViewAngle) > PANNING_SPEED_THRESHOLD) { 568fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong // TODO: draw speed indication according to the UI spec. 569fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong mTooFastPrompt.setVisibility(View.VISIBLE); 570e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTooFastPrompt.invalidate(); 5718a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 572fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong mTooFastPrompt.setVisibility(View.GONE); 573e47b5624a1aa3cc7bd9763852bed4ac3215a77b2Wei-Ta Chen mTooFastPrompt.invalidate(); 5748a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 5758a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 5768a2c41754655a3733175fce81fb7506ff7022959Angus Kong 577bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void createContentView() { 578bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen setContentView(R.layout.panorama); 579bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 580a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong mCaptureState = CAPTURE_STATE_VIEWFINDER; 58141a2e9735136f372de95652d0828600282c8e967mbansal 582057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong Resources appRes = getResources(); 583057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong 584a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong mCaptureLayout = (View) findViewById(R.id.pano_capture_layout); 585215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mPanoProgressBar = (PanoProgressBar) findViewById(R.id.pano_pan_progress_bar); 586057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); 587057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_done)); 588057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setIndicatorColor(appRes.getColor(R.color.pano_progress_indication)); 5896108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mPanoProgressBar.setOnDirectionChangeListener( 5906108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong new PanoProgressBar.OnDirectionChangeListener () { 5916108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong @Override 5926108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong public void onDirectionChange(int direction) { 5936108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong if (mCaptureState == CAPTURE_STATE_MOSAIC) { 5946108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong showDirectionIndicators(direction); 5956108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong } 5966108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong } 5976108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong }); 5986108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong 5996108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mLeftIndicator = (ImageView) findViewById(R.id.pano_pan_left_indicator); 6006108e0ed3a6b03deed2a8586d98607a6756637b1Angus Kong mRightIndicator = (ImageView) findViewById(R.id.pano_pan_right_indicator); 601fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong mTooFastPrompt = (TextView) findViewById(R.id.pano_capture_too_fast_textview); 602bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 603215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSavingProgressBar = (PanoProgressBar) findViewById(R.id.pano_saving_progress_bar); 604215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSavingProgressBar.setIndicatorWidth(0); 605215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSavingProgressBar.setMaxProgress(100); 606215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSavingProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); 607215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSavingProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_indication)); 608215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong 6098df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong mCaptureIndicator = (TextView) findViewById(R.id.pano_capture_indicator); 6108df38bbe67338a1f5dc58996bd8866f4c1fe264dAngus Kong 611a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong mThumbnailView = (RotateImageView) findViewById(R.id.thumbnail); 612a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong 6135af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mReviewLayout = (View) findViewById(R.id.pano_review_layout); 6145af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mReview = (ImageView) findViewById(R.id.pano_reviewarea); 6152faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer); 6162faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.getRenderer().setMosaicSurfaceCreateListener(this); 617eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal 618a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker = (ModePicker) findViewById(R.id.mode_picker); 619a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setVisibility(View.VISIBLE); 620a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setOnModeChangeListener(this); 621a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA); 6227648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li 623fcdf619d92701052621a96572d956d047e07cf24Angus Kong mShutterButton = (ShutterButton) findViewById(R.id.shutter_button); 624fcdf619d92701052621a96572d956d047e07cf24Angus Kong mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan); 625fcdf619d92701052621a96572d956d047e07cf24Angus Kong mShutterButton.setOnShutterButtonListener(this); 626fcdf619d92701052621a96572d956d047e07cf24Angus Kong 6277648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li mPanoLayout = findViewById(R.id.pano_layout); 628bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 629bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 630fcdf619d92701052621a96572d956d047e07cf24Angus Kong @Override 631fcdf619d92701052621a96572d956d047e07cf24Angus Kong public void onShutterButtonClick(ShutterButton b) { 6322faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong // If mSurfaceTexture == null then GL setup is not finished yet. 6332faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong // No buttons can be pressed. 6342faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong if (mPausing || mThreadRunning || mSurfaceTexture == null) return; 635a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong // Since this button will stay on the screen when capturing, we need to check the state 636a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong // right now. 637fcdf619d92701052621a96572d956d047e07cf24Angus Kong switch (mCaptureState) { 638fcdf619d92701052621a96572d956d047e07cf24Angus Kong case CAPTURE_STATE_VIEWFINDER: 639fcdf619d92701052621a96572d956d047e07cf24Angus Kong startCapture(); 640fcdf619d92701052621a96572d956d047e07cf24Angus Kong break; 641fcdf619d92701052621a96572d956d047e07cf24Angus Kong case CAPTURE_STATE_MOSAIC: 642fcdf619d92701052621a96572d956d047e07cf24Angus Kong stopCapture(); 643a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong } 644739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong } 645739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong 646fcdf619d92701052621a96572d956d047e07cf24Angus Kong @Override 647fcdf619d92701052621a96572d956d047e07cf24Angus Kong public void onShutterButtonFocus(ShutterButton b, boolean pressed) { 648142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 649142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 650215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong public void reportProgress() { 651215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSavingProgressBar.reset(); 652215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSavingProgressBar.setRightIncreasing(true); 65350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal Thread t = new Thread() { 65450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal @Override 65550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal public void run() { 6566f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong while (mThreadRunning) { 657e1178a73fd5756771d25d0b8375452450f509e99mbansal final int progress = mMosaicFrameProcessor.reportProgress( 658215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong true, mCancelComputation); 65950b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal 6606f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong try { 661215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong synchronized (mWaitObject) { 662215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mWaitObject.wait(50); 663215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong } 664215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong } catch (InterruptedException e) { 6656f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong throw new RuntimeException("Panorama reportProgress failed", e); 6666f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong } 6676f6ea6ab6dad370d2cc378be91a2649ae44b2c94Angus Kong // Update the progress bar 66850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal runOnUiThread(new Runnable() { 66950b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal public void run() { 670215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSavingProgressBar.setProgress(progress); 67150b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal } 67250b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal }); 67350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal } 67450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal } 67550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal }; 67650b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal t.start(); 67750b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal } 67850b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal 679215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong public void saveHighResMosaic() { 680215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong runBackgroundThread(new Thread() { 681142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @Override 682142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void run() { 6837648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li MosaicJpeg jpeg = generateFinalMosaic(true); 684e1178a73fd5756771d25d0b8375452450f509e99mbansal 68513e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong if (jpeg == null) { // Cancelled by user. 68613e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong mMainHandler.sendEmptyMessage(MSG_RESET_TO_PREVIEW); 68713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong } else if (!jpeg.isValid) { // Error when generating mosaic. 68813e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR); 68922d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong } else { 69013e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong int orientation = Exif.getOrientation(jpeg.data); 69113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong Uri uri = savePanorama(jpeg.data, orientation); 69213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong if (uri != null) { 69313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong // Create a thumbnail whose width is equal or bigger 69413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong // than the entire screen. 69513e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong int ratio = (int) Math.ceil((double) jpeg.width / 69613e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong mPanoLayout.getWidth()); 69713e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong int inSampleSize = Integer.highestOneBit(ratio); 69813e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong mThumbnail = Thumbnail.createThumbnail( 69913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong jpeg.data, orientation, inSampleSize, uri); 70022d4b7fbace56c03092eb088a4df98e04a6681afAngus Kong } 70113e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong mMainHandler.sendMessage( 70213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL)); 703a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong } 704142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 7055fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong }); 706215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong reportProgress(); 707215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong } 708215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong 709215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong private void showDialog(String str) { 710215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mProgressDialog = new ProgressDialog(this); 711215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mProgressDialog.setMessage(str); 712215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mProgressDialog.show(); 7135fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong } 7145fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong 715215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong private void runBackgroundThread(Thread thread) { 7165fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong mThreadRunning = true; 7175fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong thread.start(); 7185fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong } 7195fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong 7205fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong private void onBackgroundThreadFinished() { 7215fde6d5259fccaed4bc517697a4930d3b69ae860Angus Kong mThreadRunning = false; 722215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong if (mProgressDialog != null ) { 723215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mProgressDialog.dismiss(); 724215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mProgressDialog = null; 725215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong } 726142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 727142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 728142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @OnClickAttr 729215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong public void onCancelButtonClicked(View v) { 730215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong if (mPausing || mSurfaceTexture == null) return; 731215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mCancelComputation = true; 732215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong synchronized (mWaitObject) { 733215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mWaitObject.notify(); 734215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong } 735142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 736142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 737a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong @OnClickAttr 738a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong public void onThumbnailClicked(View v) { 739a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong if (mPausing || mThreadRunning || mSurfaceTexture == null) return; 740a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong showSharePopup(); 741a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong } 742a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong 743a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong private void showSharePopup() { 744a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong if (mThumbnail == null) return; 745a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong Uri uri = mThumbnail.getUri(); 746a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong if (mSharePopup == null || !uri.equals(mSharePopup.getUri())) { 747a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong // The orientation compensation is set to 0 here because we only support landscape. 7484591c5ecbaade585c3094be353d27b14f0592494Wu-cheng Li // Panorama picture is long. Use pano_layout so the share popup can be full-screen. 749757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li mSharePopup = new SharePopup(this, uri, mThumbnail.getBitmap(), 0, 750757b67951f40850b1ac3102dc0b6fe8977615a4aWu-cheng Li findViewById(R.id.pano_layout)); 751a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong } 752a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong mSharePopup.showAtLocation(mThumbnailView, Gravity.NO_GRAVITY, 0, 0); 753a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong } 754a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong 755142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void resetToPreview() { 756a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong mCaptureState = CAPTURE_STATE_VIEWFINDER; 75741a2e9735136f372de95652d0828600282c8e967mbansal 75841a2e9735136f372de95652d0828600282c8e967mbansal mReviewLayout.setVisibility(View.GONE); 759fcdf619d92701052621a96572d956d047e07cf24Angus Kong mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan); 760057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setVisibility(View.GONE); 76160fc534ec8f68d95a486984cb396a2da0e200518Angus Kong mCaptureLayout.setVisibility(View.VISIBLE); 762142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.reset(); 76341a2e9735136f372de95652d0828600282c8e967mbansal 7642faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mSurfaceTexture.setOnFrameAvailableListener(this); 76541a2e9735136f372de95652d0828600282c8e967mbansal 76636839102e03107e3fb121197036365a58ec2686eAngus Kong if (!mPausing) startCameraPreview(); 767142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 768142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 769142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void showFinalMosaic(Bitmap bitmap) { 770142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (bitmap != null) { 771142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mReview.setImageBitmap(bitmap); 772142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 773ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mCaptureLayout.setVisibility(View.GONE); 774ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mReviewLayout.setVisibility(View.VISIBLE); 775142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 776142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 777a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong private Uri savePanorama(byte[] jpegData, int orientation) { 778ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong if (jpegData != null) { 779ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong String imagePath = PanoUtil.createName( 780ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong getResources().getString(R.string.pano_file_name_format), mTimeTaken); 781a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong return Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null, 782a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong orientation, jpegData); 783142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 784a907c122ccec649c6cedf3a45b1c426a5fca932eAngus Kong return null; 785142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 786142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 787142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void clearMosaicFrameProcessorIfNeeded() { 788142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (!mPausing || mThreadRunning) return; 789142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.clear(); 790142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 791142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 792142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void initMosaicFrameProcessorIfNeeded() { 793142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (mPausing || mThreadRunning) return; 794142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (mMosaicFrameProcessor == null) { 795142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // Start the activity for the first time. 796c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMosaicFrameProcessor = new MosaicFrameProcessor( 7970adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mPreviewWidth, mPreviewHeight, getPreviewBufSize()); 798142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 799142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.initialize(); 800bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 801bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 802bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 803bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen protected void onPause() { 804bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen super.onPause(); 8054d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong 806bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen releaseCamera(); 807142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mPausing = true; 8082faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.onPause(); 809142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong clearMosaicFrameProcessorIfNeeded(); 810215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong mSensorManager.unregisterListener(mListener); 811c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mOrientationEventListener.disable(); 81294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen System.gc(); 813bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 814bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 815bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 816bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen protected void onResume() { 817bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen super.onResume(); 818bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 819142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mPausing = false; 820c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mOrientationEventListener.enable(); 821bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen /* 82294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * It is not necessary to get accelerometer events at a very high rate, 823c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong * by using a game rate (SENSOR_DELAY_UI), we get an automatic 82494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * low-pass filter, which "extracts" the gravity component of the 82594f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * acceleration. As an added benefit, we use less power and CPU 82694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * resources. 827bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen */ 828bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI); 829215f7ecf1fcc861986397fdf6724602d4775ab2cAngus Kong 830a466abbd54caa8100a1ef6584a5b0db78224a125Angus Kong mCaptureState = CAPTURE_STATE_VIEWFINDER; 831bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen setupCamera(); 8324d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong if (mSurfaceTexture != null) { 8334d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong mSurfaceTexture.setOnFrameAvailableListener(this); 8344d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong startCameraPreview(); 8354d1c2846e24a7f7f6c8ff59e01ca36a000344944Angus Kong } 836142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // Camera must be initialized before MosaicFrameProcessor is initialized. The preview size 837142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // has to be decided by camera device. 838142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong initMosaicFrameProcessorIfNeeded(); 8392faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong mMosaicView.onResume(); 840bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 841bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 842c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private void updateCompassValue() { 843917cd82d626aaa5ea48b301fe9c7bc7452a0177fAngus Kong if (mCaptureState == CAPTURE_STATE_VIEWFINDER) return; 844c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong // By what angle has the camera moved since start of capture? 845c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mTraversedAngleX = (int) (mCompassValueX - mCompassValueXStart); 846c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mTraversedAngleY = (int) (mCompassValueY - mCompassValueYStart); 847c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMinAngleX = Math.min(mMinAngleX, mTraversedAngleX); 848c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMaxAngleX = Math.max(mMaxAngleX, mTraversedAngleX); 849c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMinAngleY = Math.min(mMinAngleY, mTraversedAngleY); 850c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mMaxAngleY = Math.max(mMaxAngleY, mTraversedAngleY); 851c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong 852c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong // Use orientation to identify if the user is panning to the right or the left. 853c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong switch (mDeviceOrientation) { 854c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong case 0: 855057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setProgress(-mTraversedAngleX); 856c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong break; 857c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong case 1: 858057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setProgress(mTraversedAngleY); 859c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong break; 860c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong case 2: 861057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setProgress(mTraversedAngleX); 862c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong break; 863c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong case 3: 864057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.setProgress(-mTraversedAngleY); 865c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong break; 866c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong } 867057040c0e19834d98719143c2627a9f0df3e4c35Angus Kong mPanoProgressBar.invalidate(); 868c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong } 869bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 870c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong private final SensorEventListener mListener = new SensorEventListener() { 871bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onSensorChanged(SensorEvent event) { 872bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { 873bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (mTimestamp != 0) { 874bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen final float dT = (event.timestamp - mTimestamp) * NS2S; 875c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mCompassValueX += event.values[1] * dT * 180.0f / Math.PI; 876c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mCompassValueY += event.values[0] * dT * 180.0f / Math.PI; 877c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mCompassValueXStartBuffer = mCompassValueX; 878c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong mCompassValueYStartBuffer = mCompassValueY; 879c89a0eb7b1f0cd5cd45de8fd08ff051f6f74f382Angus Kong updateCompassValue(); 880bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 881bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mTimestamp = event.timestamp; 882bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 883bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 884bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 885bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 886bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 887bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onAccuracyChanged(Sensor sensor, int accuracy) { 888bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 889bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen }; 890bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 8917648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li public MosaicJpeg generateFinalMosaic(boolean highRes) { 89213e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong if (mMosaicFrameProcessor.createMosaic(highRes) == Mosaic.MOSAIC_RET_CANCELLED) { 893e1178a73fd5756771d25d0b8375452450f509e99mbansal return null; 89413e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong } 895bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 896ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21(); 897ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong if (imageData == null) { 898ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.e(TAG, "getFinalMosaicNV21() returned null."); 89913e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong return new MosaicJpeg(); 9008a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 9018a2c41754655a3733175fce81fb7506ff7022959Angus Kong 902ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int len = imageData.length - 8; 903ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16) 904ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF); 905ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16) 906ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF); 907ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height); 9088a2c41754655a3733175fce81fb7506ff7022959Angus Kong 909e46486104523760a4433f03e09ed615987d83b6cAngus Kong if (width <= 0 || height <= 0) { 910e46486104523760a4433f03e09ed615987d83b6cAngus Kong // TODO: pop up a error meesage indicating that the final result is not generated. 911e46486104523760a4433f03e09ed615987d83b6cAngus Kong Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " + 912e46486104523760a4433f03e09ed615987d83b6cAngus Kong height); 91313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong return new MosaicJpeg(); 914e46486104523760a4433f03e09ed615987d83b6cAngus Kong } 915e46486104523760a4433f03e09ed615987d83b6cAngus Kong 916ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null); 917ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong ByteArrayOutputStream out = new ByteArrayOutputStream(); 918ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out); 919ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong try { 920ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong out.close(); 921ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } catch (Exception e) { 922ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.e(TAG, "Exception in storing final mosaic", e); 92313e2b964e821f6ee40cf5715b6baec19c7fd09b8Angus Kong return new MosaicJpeg(); 924ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } 9257648319f0416b86ae13b97eeba0466581ace1a48Wu-cheng Li return new MosaicJpeg(out.toByteArray(), width, height); 926bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 9278a2c41754655a3733175fce81fb7506ff7022959Angus Kong 92841a2e9735136f372de95652d0828600282c8e967mbansal private void setPreviewTexture(SurfaceTexture surface) { 92998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen try { 93041a2e9735136f372de95652d0828600282c8e967mbansal mCameraDevice.setPreviewTexture(surface); 93198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } catch (Throwable ex) { 93298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen releaseCamera(); 93341a2e9735136f372de95652d0828600282c8e967mbansal throw new RuntimeException("setPreviewTexture failed", ex); 93498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 93598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 93698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 93736839102e03107e3fb121197036365a58ec2686eAngus Kong private void startCameraPreview() { 93898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen // If we're previewing already, stop the preview first (this will blank 93998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen // the screen). 94036839102e03107e3fb121197036365a58ec2686eAngus Kong if (mCameraState != PREVIEW_STOPPED) stopCameraPreview(); 94198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 9422faf16a90a6a6d18e40faf45ced217b913b214b6Angus Kong setPreviewTexture(mSurfaceTexture); 94398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 94498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen try { 94598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen Log.v(TAG, "startPreview"); 94698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraDevice.startPreview(); 94798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } catch (Throwable ex) { 94898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen releaseCamera(); 94998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen throw new RuntimeException("startPreview failed", ex); 95098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 95198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_ACTIVE; 95298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 95398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 95436839102e03107e3fb121197036365a58ec2686eAngus Kong private void stopCameraPreview() { 95598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { 95698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen Log.v(TAG, "stopPreview"); 95798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraDevice.stopPreview(); 95898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 95998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_STOPPED; 96098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 961bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen} 962