19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2011 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage com.android.camera.panorama; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.ActivityBase; 209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.CameraDisabledException; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.CameraHardwareException; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.CameraHolder; 239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.Exif; 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.MenuHelper; 256139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughesimport com.android.camera.ModePicker; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.OnClickAttr; 279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.R; 28becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chanimport com.android.camera.RotateDialogController; 299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.ShutterButton; 30becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chanimport com.android.camera.Storage; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.Thumbnail; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.Util; 336139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughesimport com.android.camera.ui.PopupManager; 344af85345e798c37ab026e93a1ae250d8bca4fc40Elliott Hughesimport com.android.camera.ui.Rotatable; 354af85345e798c37ab026e93a1ae250d8bca4fc40Elliott Hughesimport com.android.camera.ui.RotateImageView; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.ui.RotateLayout; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.camera.ui.SharePopup; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.AssetFileDescriptor; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.ActivityInfo; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Bitmap; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.BitmapFactory; 4699a64f4b1d2519b71558fdc62721686445865b60Jesse Wilsonimport android.graphics.ImageFormat; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.PixelFormat; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.Rect; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.SurfaceTexture; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.graphics.YuvImage; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.hardware.Camera.Parameters; 5284c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischerimport android.hardware.Camera.Size; 5384c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischerimport android.hardware.Sensor; 5484c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischerimport android.hardware.SensorManager; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.ExifInterface; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaActionSound; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ParcelFileDescriptor; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.PowerManager; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity; 65d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughesimport android.view.Menu; 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.MenuItem; 67d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughesimport android.view.OrientationEventListener; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 69d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughesimport android.view.ViewGroup; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Window; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.WindowManager; 72d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughesimport android.widget.ImageView; 739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 75d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughesimport java.io.ByteArrayOutputStream; 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.File; 77577ec9eb3a661de96a2cbe9ec918eda082fb7659Erikimport java.io.IOException; 78577ec9eb3a661de96a2cbe9ec918eda082fb7659Erikimport java.util.List; 79577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik 80577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik/** 81577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik * Activity to handle panorama capturing. 82577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik */ 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class PanoramaActivity extends ActivityBase implements 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ModePicker.OnModeChangeListener, SurfaceTexture.OnFrameAvailableListener, 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ShutterButton.OnShutterButtonListener, 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener { 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int DEFAULT_SWEEP_ANGLE = 160; 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; 90d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_LOW_RES_FINAL_MOSAIC_READY = 1; 92d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes private static final int MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL = 2; 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_GENERATE_FINAL_MOSAIC_ERROR = 3; 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_RESET_TO_PREVIEW = 4; 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_CLEAR_SCREEN_DELAY = 5; 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9784c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer private static final int SCREEN_DELAY = 2 * 60 * 1000; 9884c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer 99fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private static final String TAG = "PanoramaActivity"; 10084c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer private static final int PREVIEW_STOPPED = 0; 101d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes private static final int PREVIEW_ACTIVE = 1; 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CAPTURE_STATE_VIEWFINDER = 0; 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int CAPTURE_STATE_MOSAIC = 1; 1045669ce59aad19f17e1e89913e7483fb93b8aa0cfEric Fischer 1055669ce59aad19f17e1e89913e7483fb93b8aa0cfEric Fischer // Speed is in unit of deg/sec 106fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private static final float PANNING_SPEED_THRESHOLD = 20f; 1075669ce59aad19f17e1e89913e7483fb93b8aa0cfEric Fischer 108d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes // Ratio of nanosecond to second 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final float NS2S = 1.0f / 1000000000.0f; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mPausing; 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View mPanoLayout; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View mCaptureLayout; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View mReviewLayout; 11699a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson private ImageView mReview; 117fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private RotateLayout mCaptureIndicator; 1186139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes private PanoProgressBar mPanoProgressBar; 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PanoProgressBar mSavingProgressBar; 120fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private View mFastIndicationBorder; 1216139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes private View mLeftIndicator; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private View mRightIndicator; 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private MosaicRendererSurfaceView mMosaicView; 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextView mTooFastPrompt; 1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ShutterButton mShutterButton; 12699a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson private Object mWaitObject = new Object(); 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mPreparePreviewString; 129fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private String mDialogTitle; 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private String mDialogOkString; 131d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes private String mDialogPanoramaFailedString; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mIndicatorColor; 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mIndicatorColorFast; 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mCompassValueX; 13799a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson private float mCompassValueY; 1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mCompassValueXStart; 1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mCompassValueYStart; 140fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private float mCompassValueXStartBuffer; 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mCompassValueYStartBuffer; 142d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes private int mCompassThreshold; 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTraversedAngleX; 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mTraversedAngleY; 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private long mTimestamp; 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private RotateImageView mThumbnailView; 1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Thumbnail mThumbnail; 1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SharePopup mSharePopup; 1505bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer 1515bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer private int mPreviewWidth; 152fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private int mPreviewHeight; 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mCameraState; 154d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes private int mCaptureState; 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SensorManager mSensorManager; 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Sensor mSensor; 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PowerManager.WakeLock mPartialWakeLock; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ModePicker mModePicker; 1595bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer private MosaicFrameProcessor mMosaicFrameProcessor; 1605bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer private long mTimeTaken; 161fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private Handler mMainHandler; 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SurfaceTexture mSurfaceTexture; 163d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes private boolean mThreadRunning; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mCancelComputation; 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float[] mTransformMatrix; 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mHorizontalViewAngle; 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private float mVerticalViewAngle; 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Prefer FOCUS_MODE_INFINITY to FOCUS_MODE_CONTINUOUS_VIDEO because of 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // getting a better image quality by the former. 1715bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer private String mTargetFocusMode = Parameters.FOCUS_MODE_INFINITY; 1725bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer 173fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes private PanoOrientationEventListener mOrientationEventListener; 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The value could be 0, 90, 180, 270 for the 4 different orientations measured in clockwise 175d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes // respectively. 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mDeviceOrientation; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mDeviceOrientationAtCapture; 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mCameraOrientation; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mOrientationCompensation; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private RotateDialogController mRotateDialog; 1825bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer 1835bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer private MediaActionSound mCameraSound; 1845bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer 1855bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer private class MosaicJpeg { 1865bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer public MosaicJpeg(byte[] data, int width, int height) { 1875bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer this.data = data; 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.width = width; 189fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes this.height = height; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.isValid = true; 191d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes } 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19308153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes public MosaicJpeg() { 19408153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes this.data = null; 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project this.width = 0; 19608153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes this.height = 0; 19708153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes this.isValid = false; 19808153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes } 19908153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes 20008153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes public final byte[] data; 20108153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes public final int width; 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public final int height; 20308153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes public final boolean isValid; 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class PanoOrientationEventListener extends OrientationEventListener { 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public PanoOrientationEventListener(Context context) { 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context); 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 211fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes @Override 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onOrientationChanged(int orientation) { 213d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes // We keep the last known orientation. So if the user first orient 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the camera then point the camera to floor or sky, we still have 2154af85345e798c37ab026e93a1ae250d8bca4fc40Elliott Hughes // the correct orientation. 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (orientation == ORIENTATION_UNKNOWN) return; 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDeviceOrientation = Util.roundOrientation(orientation, mDeviceOrientation); 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // When the screen is unlocked, display rotation may change. Always 2195bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer // calculate the up-to-date orientationCompensation. 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int orientationCompensation = mDeviceOrientation 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Util.getDisplayRotation(PanoramaActivity.this); 2225bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer if (mOrientationCompensation != orientationCompensation) { 2235bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer mOrientationCompensation = orientationCompensation; 2245bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer setOrientationIndicator(mOrientationCompensation); 2255bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer } 2265bd644caf73e76750feef1a82b8817d32f5367fcEric Fischer } 227fbf37c79bdedbdd7b82ad7d5862dd82e3c068590Elliott Hughes } 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 229d3c01012d8d329e541214e8207272ab5cc9ca004Elliott Hughes private void setOrientationIndicator(int degree) { 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSharePopup != null) mSharePopup.setOrientation(degree); 23108153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes } 23208153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes 2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 23408153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes public boolean onCreateOptionsMenu(Menu menu) { 23508153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes super.onCreateOptionsMenu(menu); 23608153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes 23708153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes addBaseMenuItems(menu); 23808153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes return true; 23908153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes } 2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24108153ee01e6aa67061f628bc3fed66c6400dfd1cElliott Hughes @Override 2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onPrepareOptionsMenu(Menu menu) { 2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onPrepareOptionsMenu(menu); 2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Only show the menu when idle. 2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean idle = (mCaptureState == CAPTURE_STATE_VIEWFINDER && !mThreadRunning); 2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < menu.size(); i++) { 2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MenuItem item = menu.getItem(i); 2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project item.setVisible(idle); 2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project item.setEnabled(idle); 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void addBaseMenuItems(Menu menu) { 2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MenuHelper.addSwitchModeMenuItem(menu, ModePicker.MODE_CAMERA, new Runnable() { 2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switchToOtherMode(ModePicker.MODE_CAMERA); 2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MenuHelper.addSwitchModeMenuItem(menu, ModePicker.MODE_VIDEO, new Runnable() { 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switchToOtherMode(ModePicker.MODE_VIDEO); 2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onCreate(Bundle icicle) { 2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onCreate(icicle); 2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Window window = getWindow(); 2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Util.enterLightsOutMode(window); 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Util.initializeScreenBrightness(window, getContentResolver()); 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project createContentView(); 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 27999a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSensor == null) { 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Panorama"); 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mOrientationEventListener = new PanoOrientationEventListener(this); 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTransformMatrix = new float[16]; 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreparePreviewString = 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getResources().getString(R.string.pano_dialog_prepare_preview); 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDialogTitle = getResources().getString(R.string.pano_dialog_title); 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDialogOkString = getResources().getString(R.string.dialog_ok); 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDialogPanoramaFailedString = 29599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson getResources().getString(R.string.pano_dialog_panorama_failed); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCameraSound = new MediaActionSound(); 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMainHandler = new Handler() { 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleMessage(Message msg) { 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (msg.what) { 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_LOW_RES_FINAL_MOSAIC_READY: 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onBackgroundThreadFinished(); 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showFinalMosaic((Bitmap) msg.obj); 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project saveHighResMosaic(); 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL: 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onBackgroundThreadFinished(); 3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the activity is paused, save the thumbnail to the file here. 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If not, it will be saved in onPause. 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPausing) saveThumbnailToFile(); 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set the thumbnail bitmap here because mThumbnailView must be accessed 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // from the UI thread. 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateThumbnailButton(); 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Share popup may still have the reference to the old thumbnail. Clear it. 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSharePopup = null; 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetToPreview(); 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_GENERATE_FINAL_MOSAIC_ERROR: 3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onBackgroundThreadFinished(); 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPausing) { 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetToPreview(); 3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRotateDialog.showAlertDialog( 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDialogTitle, mDialogPanoramaFailedString, 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDialogOkString, new Runnable() { 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetToPreview(); 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }}, 3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, null); 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_RESET_TO_PREVIEW: 3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project onBackgroundThreadFinished(); 3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resetToPreview(); 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_CLEAR_SCREEN_DELAY: 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getWindow().clearFlags(WindowManager.LayoutParams. 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project FLAG_KEEP_SCREEN_ON); 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project clearMosaicFrameProcessorIfNeeded(); 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 3475acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes } 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setupCamera() throws CameraHardwareException, CameraDisabledException { 3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project openCamera(); 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Parameters parameters = mCameraDevice.getParameters(); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setupCaptureParams(parameters); 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project configureCamera(parameters); 3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void releaseCamera() { 35799a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson if (mCameraDevice != null) { 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCameraDevice.setPreviewCallbackWithBuffer(null); 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project CameraHolder.instance().release(); 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCameraDevice = null; 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCameraState = PREVIEW_STOPPED; 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void openCamera() throws CameraHardwareException, CameraDisabledException { 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int backCameraId = CameraHolder.instance().getBackCameraId(); 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCameraDevice = Util.openCamera(this, backCameraId); 3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCameraOrientation = Util.getCameraOrientation(backCameraId); 36999a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean needSmaller) { 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int pixelsDiff = DEFAULT_CAPTURE_PIXELS; 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hasFound = false; 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (Size size : supportedSizes) { 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int h = size.height; 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int w = size.width; 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we only want 4:3 format. 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int d = DEFAULT_CAPTURE_PIXELS - h * w; 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (needSmaller && d < 0) { // no bigger preview than 960x720. 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (need4To3 && (h * 4 != w * 3)) { 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project d = Math.abs(d); 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (d < pixelsDiff) { 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewWidth = w; 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPreviewHeight = h; 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pixelsDiff = d; 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hasFound = true; 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return hasFound; 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void setupCaptureParams(Parameters parameters) { 39899a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!findBestPreviewSize(supportedSizes, true, true)) { 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "No 4:3 ratio preview size supported."); 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!findBestPreviewSize(supportedSizes, false, true)) { 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project findBestPreviewSize(supportedSizes, false, false); 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth); 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parameters.setPreviewSize(mPreviewWidth, mPreviewHeight); 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project List<int[]> frameRates = parameters.getSupportedPreviewFpsRange(); 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int last = frameRates.size() - 1; 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX]; 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX]; 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parameters.setPreviewFpsRange(minFps, maxFps); 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.v(TAG, "preview fps: " + minFps + ", " + maxFps); 41599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson 4165acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes List<String> supportedFocusModes = parameters.getSupportedFocusModes(); 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (supportedFocusModes.indexOf(mTargetFocusMode) >= 0) { 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project parameters.setFocusMode(mTargetFocusMode); 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Use the default focus mode and log a message 4215acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes Log.w(TAG, "Cannot set the focus mode to " + mTargetFocusMode + 4225acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes " becuase the mode is not supported."); 4235acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes } 4245acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes 4255acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes parameters.setRecordingHint(false); 4265acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mHorizontalViewAngle = parameters.getHorizontalViewAngle(); 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVerticalViewAngle = parameters.getVerticalViewAngle(); 4295acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes } 4305acc6e521494f1ea21c793d0b56667dae107a1beElliott Hughes 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getPreviewBufSize() { 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PixelFormat pixelInfo = new PixelFormat(); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo); 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: remove this extra 32 byte after the driver bug is fixed. 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32; 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 43799a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson 438c3ff72f5bd5896ad2584e0cc0582cbd2ad8191f2Elliott Hughes private void configureCamera(Parameters parameters) { 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCameraDevice.setParameters(parameters); 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 441c3ff72f5bd5896ad2584e0cc0582cbd2ad8191f2Elliott Hughes 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean switchToOtherMode(int mode) { 443c3ff72f5bd5896ad2584e0cc0582cbd2ad8191f2Elliott Hughes if (isFinishing()) { 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 446c3ff72f5bd5896ad2584e0cc0582cbd2ad8191f2Elliott Hughes MenuHelper.gotoMode(mode, this); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project finish(); 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onModeChanged(int mode) { 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mode != ModePicker.MODE_PANORAMA) { 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return switchToOtherMode(mode); 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 45599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson return true; 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onMosaicSurfaceChanged() { 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project runOnUiThread(new Runnable() { 46225d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK @Override 46325d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK public void run() { 46425d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK // If panorama is generating low res or high res mosaic, it 46525d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK // means users exit and come back to panorama. Do not start the 46625d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK // preview. Preview will be started after final mosaic is 46725d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK // generated. 46825d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK if (!mPausing && !mThreadRunning) { 46925d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK startCameraPreview(); 47025d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK } 47125d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK } 47225d8b05fb77e8ee755aacd27c1c2d3b237537b7aJozef BABJAK }); 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onMosaicSurfaceCreated(final int textureID) { 47753f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey runOnUiThread(new Runnable() { 47853f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey @Override 47953f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey public void run() { 48053f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey if (mSurfaceTexture != null) { 48153f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey mSurfaceTexture.release(); 48253f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey } 48353f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey mSurfaceTexture = new SurfaceTexture(textureID); 48453f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey if (!mPausing) { 48553f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey mSurfaceTexture.setOnFrameAvailableListener(PanoramaActivity.this); 48653f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey } 48753f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey } 48853f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey }); 48953f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey } 49053f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey 49153f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey public void runViewFinder() { 49253f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey mMosaicView.setWarping(false); 49353f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey // Call preprocess to render it to low-res and high-res RGB textures. 49453f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey mMosaicView.preprocess(mTransformMatrix); 49553f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey mMosaicView.setReady(); 49653f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey mMosaicView.requestRender(); 49753f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey } 49853f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey 49953f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey public void runMosaicCapture() { 50053f6e8a9b95a1fe5229295ade4989339d577de08Jeff Sharkey mMosaicView.setWarping(true); 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Call preprocess to render it to low-res and high-res RGB textures. 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView.preprocess(mTransformMatrix); 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Lock the conditional variable to ensure the order of transferGPUtoCPU and 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // mMosaicFrame.processFrame(). 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView.lockPreviewReadyFlag(); 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now, transfer the textures from GPU to CPU memory for processing 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView.transferGPUtoCPU(); 50899a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson // Wait on the condition variable (will be opened when GPU->CPU transfer is done). 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView.waitUntilPreviewReady(); 5102eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes mMosaicFrameProcessor.processFrame(); 5112eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes } 5122eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes 51399a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson public synchronized void onFrameAvailable(SurfaceTexture surface) { 5142eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes /* This function may be called by some random thread, 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * so let's be safe and use synchronize. No OpenGL calls can be done here. 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Frames might still be available after the activity is paused. If we call onFrameAvailable 5182eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes // after pausing, the GL thread will crash. 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPausing) return; 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Updating the texture should be done in the GL thread which mMosaicView is attached. 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView.queueEvent(new Runnable() { 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check if the activity is paused here can speed up the onPause() process. 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPausing) return; 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceTexture.updateTexImage(); 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSurfaceTexture.getTransformMatrix(mTransformMatrix); 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Update the transformation matrix for mosaic pre-process. 5322eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes if (mCaptureState == CAPTURE_STATE_VIEWFINDER) { 5332eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes runViewFinder(); 5342eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes } else { 5352eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes runMosaicCapture(); 5362eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes } 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5382eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void hideDirectionIndicators() { 540315a7c0335fb54beced23b1703c10563ce02ee82Roozbeh Pournader mLeftIndicator.setVisibility(View.GONE); 5412eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes mRightIndicator.setVisibility(View.GONE); 5422eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes } 5432eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes 5442eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes private void showDirectionIndicators(int direction) { 5452eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes switch (direction) { 5462eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes case PanoProgressBar.DIRECTION_NONE: 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLeftIndicator.setVisibility(View.VISIBLE); 5482eda18485cefc5dbc946d7eb32486a7bd67bf8afElliott Hughes mRightIndicator.setVisibility(View.VISIBLE); 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case PanoProgressBar.DIRECTION_LEFT: 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLeftIndicator.setVisibility(View.VISIBLE); 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRightIndicator.setVisibility(View.GONE); 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case PanoProgressBar.DIRECTION_RIGHT: 55599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mLeftIndicator.setVisibility(View.GONE); 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRightIndicator.setVisibility(View.VISIBLE); 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void startCapture() { 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Reset values so we can do this again. 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCancelComputation = false; 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTimeTaken = System.currentTimeMillis(); 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCaptureState = CAPTURE_STATE_MOSAIC; 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan_recording); 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCaptureIndicator.setVisibility(View.VISIBLE); 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showDirectionIndicators(PanoProgressBar.DIRECTION_NONE); 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbnailView.setEnabled(false); 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCompassValueXStart = mCompassValueXStartBuffer; 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCompassValueYStart = mCompassValueYStartBuffer; 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTimestamp = 0; 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() { 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onProgress(boolean isFinished, float panningRateX, float panningRateY, 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float progressX, float progressY) { 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float accumulatedHorizontalAngle = progressX * mHorizontalViewAngle; 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float accumulatedVerticalAngle = progressY * mVerticalViewAngle; 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isFinished 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (Math.abs(accumulatedHorizontalAngle) >= DEFAULT_SWEEP_ANGLE) 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (Math.abs(accumulatedVerticalAngle) >= DEFAULT_SWEEP_ANGLE)) { 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project stopCapture(false); 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float panningRateXInDegree = panningRateX * mHorizontalViewAngle; 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float panningRateYInDegree = panningRateY * mVerticalViewAngle; 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateProgress(panningRateXInDegree, panningRateYInDegree, 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project accumulatedHorizontalAngle, accumulatedVerticalAngle); 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mModePicker != null) mModePicker.setEnabled(false); 59599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.reset(); 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: calculate the indicator width according to different devices to reflect the actual 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // angle of view of the camera device. 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.setIndicatorWidth(20); 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.setMaxProgress(DEFAULT_SWEEP_ANGLE); 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.setVisibility(View.VISIBLE); 60299a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mDeviceOrientationAtCapture = mDeviceOrientation; 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project keepScreenOn(); 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void stopCapture(boolean aborted) { 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCaptureState = CAPTURE_STATE_VIEWFINDER; 608becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan mCaptureIndicator.setVisibility(View.GONE); 609becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan hideTooFastIndication(); 610becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan hideDirectionIndicators(); 611becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan mThumbnailView.setEnabled(true); 612becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan 613becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan mMosaicFrameProcessor.setProgressListener(null); 614becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan stopCameraPreview(); 615becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan 616becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan mSurfaceTexture.setOnFrameAvailableListener(null); 617577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik 618becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan if (!aborted && !mThreadRunning) { 619becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan mRotateDialog.showWaitingDialog(mPreparePreviewString); 620becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan runBackgroundThread(new Thread() { 621becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan @Override 622577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik public void run() { 623becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan MosaicJpeg jpeg = generateFinalMosaic(false); 624becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan 625becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan if (jpeg != null && jpeg.isValid) { 626becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan Bitmap bitmap = null; 627becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length); 628becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan mMainHandler.sendMessage(mMainHandler.obtainMessage( 629becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap)); 630becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan } else { 631becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan mMainHandler.sendMessage(mMainHandler.obtainMessage( 632becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan MSG_RESET_TO_PREVIEW)); 633577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik } 634577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik } 635577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik }); 636577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik } 637577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik // do we have to wait for the thread to complete before enabling this? 638577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik if (mModePicker != null) mModePicker.setEnabled(true); 639577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik keepScreenOnAwhile(); 640577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik } 641577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik 642577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik private void showTooFastIndication() { 643577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mTooFastPrompt.setVisibility(View.VISIBLE); 644577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mFastIndicationBorder.setVisibility(View.VISIBLE); 645577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mPanoProgressBar.setIndicatorColor(mIndicatorColorFast); 646577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mLeftIndicator.setEnabled(true); 647577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mRightIndicator.setEnabled(true); 648577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik } 649577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik 650577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik private void hideTooFastIndication() { 651577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mTooFastPrompt.setVisibility(View.GONE); 652577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mFastIndicationBorder.setVisibility(View.GONE); 653577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mPanoProgressBar.setIndicatorColor(mIndicatorColor); 654577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mLeftIndicator.setEnabled(false); 655577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik mRightIndicator.setEnabled(false); 65699a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateProgress(float panningRateXInDegree, float panningRateYInDegree, 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project float progressHorizontalAngle, float progressVerticalAngle) { 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView.setReady(); 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView.requestRender(); 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Now we just display warning message by the panning speed. 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Since we only support horizontal panning, we should display a warning message 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in UI when there're significant vertical movements. 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((Math.abs(panningRateXInDegree) > PANNING_SPEED_THRESHOLD) 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project || (Math.abs(panningRateYInDegree) > PANNING_SPEED_THRESHOLD)) { 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showTooFastIndication(); 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hideTooFastIndication(); 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int angleInMajorDirection = 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (Math.abs(progressHorizontalAngle) > Math.abs(progressVerticalAngle)) 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ? (int) progressHorizontalAngle 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project : (int) progressVerticalAngle; 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.setProgress((angleInMajorDirection)); 67799a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void createContentView() { 68099a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson setContentView(R.layout.panorama); 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCaptureState = CAPTURE_STATE_VIEWFINDER; 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Resources appRes = getResources(); 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCaptureLayout = (View) findViewById(R.id.pano_capture_layout); 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar = (PanoProgressBar) findViewById(R.id.pano_pan_progress_bar); 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_done)); 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIndicatorColor = appRes.getColor(R.color.pano_progress_indication); 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mIndicatorColorFast = appRes.getColor(R.color.pano_progress_indication_fast); 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.setIndicatorColor(mIndicatorColor); 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPanoProgressBar.setOnDirectionChangeListener( 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new PanoProgressBar.OnDirectionChangeListener () { 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onDirectionChange(int direction) { 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mCaptureState == CAPTURE_STATE_MOSAIC) { 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project showDirectionIndicators(direction); 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 70199a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson }); 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLeftIndicator = (ImageView) findViewById(R.id.pano_pan_left_indicator); 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRightIndicator = (ImageView) findViewById(R.id.pano_pan_right_indicator); 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLeftIndicator.setEnabled(false); 70699a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mRightIndicator.setEnabled(false); 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTooFastPrompt = (TextView) findViewById(R.id.pano_capture_too_fast_textview); 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mFastIndicationBorder = (View) findViewById(R.id.pano_speed_indication_border); 70999a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSavingProgressBar = (PanoProgressBar) findViewById(R.id.pano_saving_progress_bar); 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSavingProgressBar.setIndicatorWidth(0); 7126139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes mSavingProgressBar.setMaxProgress(100); 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSavingProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); 7146139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes mSavingProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_indication)); 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCaptureIndicator = (RotateLayout) findViewById(R.id.pano_capture_indicator); 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbnailView = (RotateImageView) findViewById(R.id.thumbnail); 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbnailView.enableFilter(false); 72099a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mReviewLayout = (View) findViewById(R.id.pano_review_layout); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mReview = (ImageView) findViewById(R.id.pano_reviewarea); 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer); 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMosaicView.getRenderer().setMosaicSurfaceCreateListener(this); 72599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mModePicker = (ModePicker) findViewById(R.id.mode_picker); 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mModePicker.setVisibility(View.VISIBLE); 72884c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer mModePicker.setOnModeChangeListener(this); 72984c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA); 73084c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer 73199a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mShutterButton = (ShutterButton) findViewById(R.id.shutter_button); 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan); 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mShutterButton.setOnShutterButtonListener(this); 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 73599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mPanoLayout = findViewById(R.id.pano_layout); 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRotateDialog = new RotateDialogController(this, R.layout.rotate_dialog); 73884c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer 73984c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) { 74084c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer Rotatable[] rotateLayout = { 74199a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson (Rotatable) findViewById(R.id.pano_pan_progress_bar_layout), 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (Rotatable) findViewById(R.id.pano_capture_too_fast_textview_layout), 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (Rotatable) findViewById(R.id.pano_review_saving_indication_layout), 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (Rotatable) findViewById(R.id.pano_saving_progress_bar_layout), 74599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson (Rotatable) findViewById(R.id.pano_review_cancel_button_layout), 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project (Rotatable) findViewById(R.id.pano_rotate_reviewarea), 74784c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer (Rotatable) mRotateDialog, 74884c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer (Rotatable) mCaptureIndicator, 74984c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer (Rotatable) mModePicker, 75084c863d9af1270a2ccd2ccd2b8c1a753826dfe6dEric Fischer (Rotatable) mThumbnailView}; 75199a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson for (Rotatable r : rotateLayout) { 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project r.setOrientation(270); 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 75899a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson public void onShutterButtonClick() { 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If mSurfaceTexture == null then GL setup is not finished yet. 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // No buttons can be pressed. 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPausing || mThreadRunning || mSurfaceTexture == null) return; 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Since this button will stay on the screen when capturing, we need to check the state 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // right now. 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (mCaptureState) { 76599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson case CAPTURE_STATE_VIEWFINDER: 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCameraSound.play(MediaActionSound.START_VIDEO_RECORDING); 767577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik startCapture(); 768577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik break; 769577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik case CAPTURE_STATE_MOSAIC: 77099a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mCameraSound.play(MediaActionSound.STOP_VIDEO_RECORDING); 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project stopCapture(false); 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 77699a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson public void onShutterButtonFocus(boolean pressed) { 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void reportProgress() { 78099a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mSavingProgressBar.reset(); 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSavingProgressBar.setRightIncreasing(true); 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Thread t = new Thread() { 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 78499a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson public void run() { 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (mThreadRunning) { 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final int progress = mMosaicFrameProcessor.reportProgress( 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project true, mCancelComputation); 78899a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mWaitObject) { 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWaitObject.wait(50); 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 79399a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } catch (InterruptedException e) { 79499a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson throw new RuntimeException("Panorama reportProgress failed", e); 79599a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 79699a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson // Update the progress bar 79799a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson runOnUiThread(new Runnable() { 79899a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson public void run() { 79999a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mSavingProgressBar.setProgress(progress); 80099a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 80199a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson }); 80299a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 80399a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 80499a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson }; 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project t.start(); 806becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan } 807becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan 808becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan private void initThumbnailButton() { 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Load the thumbnail from the disk. 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mThumbnail == null) { 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbnail = Thumbnail.loadFrom(new File(getFilesDir(), Thumbnail.LAST_THUMB_FILENAME)); 812577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik } 813577ec9eb3a661de96a2cbe9ec918eda082fb7659Erik updateThumbnailButton(); 81499a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 815becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateThumbnailButton() { 817becfc9de9e18ef216c2b537cd2829f1d2d55404fMichael Chan // Update last image if URI is invalid and the storage is ready. 81812285f3d9f756226c13ef93054b87e0d487e1409Elliott Hughes ContentResolver contentResolver = getContentResolver(); 819f9818d33f94686ee9c80697ec79ef557a7b77176Elliott Hughes if ((mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), contentResolver))) { 820f9818d33f94686ee9c80697ec79ef557a7b77176Elliott Hughes mThumbnail = Thumbnail.getLastThumbnail(contentResolver); 82112285f3d9f756226c13ef93054b87e0d487e1409Elliott Hughes } 822f9818d33f94686ee9c80697ec79ef557a7b77176Elliott Hughes if (mThumbnail != null) { 82312285f3d9f756226c13ef93054b87e0d487e1409Elliott Hughes mThumbnailView.setBitmap(mThumbnail.getBitmap()); 82412285f3d9f756226c13ef93054b87e0d487e1409Elliott Hughes } else { 82512285f3d9f756226c13ef93054b87e0d487e1409Elliott Hughes mThumbnailView.setBitmap(null); 8266139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes } 8276139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes } 8286139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes 8296139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes private void saveThumbnailToFile() { 8306139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes if (mThumbnail != null && !mThumbnail.fromFile()) { 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbnail.saveTo(new File(getFilesDir(), Thumbnail.LAST_THUMB_FILENAME)); 8326139e64cd6f86c4e3983de976cb0aa976b0d313cElliott Hughes } 8339a2ada418b0a53cb10e009398116ff8cd914d71eSungmin Choi } 8349a2ada418b0a53cb10e009398116ff8cd914d71eSungmin Choi 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void saveHighResMosaic() { 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project runBackgroundThread(new Thread() { 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPartialWakeLock.acquire(); 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MosaicJpeg jpeg; 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jpeg = generateFinalMosaic(true); 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } finally { 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mPartialWakeLock.release(); 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (jpeg == null) { // Cancelled by user. 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMainHandler.sendEmptyMessage(MSG_RESET_TO_PREVIEW); 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (!jpeg.isValid) { // Error when generating mosaic. 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR); 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The panorama image returned from the library is orientated based on the 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // natural orientation of a camera. We need to set an orientation for the image 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in its EXIF header, so the image can be displayed correctly. 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The orientation is calculated from compensating the 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // device orientation at capture and the camera orientation respective to 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the natural orientation of the device. 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int orientation = (mDeviceOrientationAtCapture + mCameraOrientation) % 360; 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Uri uri = savePanorama(jpeg.data, jpeg.width, jpeg.height, orientation); 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uri != null) { 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Create a thumbnail whose width or height is equal or bigger 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // than the screen's width or height. 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int widthRatio = (int) Math.ceil((double) jpeg.width 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project / mPanoLayout.getWidth()); 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int heightRatio = (int) Math.ceil((double) jpeg.height 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project / mPanoLayout.getHeight()); 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int inSampleSize = Integer.highestOneBit( 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Math.max(widthRatio, heightRatio)); 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThumbnail = Thumbnail.createThumbnail( 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project jpeg.data, orientation, inSampleSize, uri); 87199a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson Util.broadcastNewPicture(PanoramaActivity.this, uri); 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMainHandler.sendMessage( 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW_WITH_THUMBNAIL)); 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }); 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project reportProgress(); 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void runBackgroundThread(Thread thread) { 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThreadRunning = true; 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project thread.start(); 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 88699a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson private void onBackgroundThreadFinished() { 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mThreadRunning = false; 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mRotateDialog.dismissDialog(); 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 89199a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson private void cancelHighResComputation() { 89299a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson mCancelComputation = true; 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mWaitObject) { 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mWaitObject.notify(); 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8986a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques @OnClickAttr 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onCancelButtonClicked(View v) { 900ca3363775e03e0f90bdf111d3e5c54b3ab16df57Steve Pomeroy if (mPausing || mSurfaceTexture == null) return; 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project cancelHighResComputation(); 9026a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques } 9036a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques 9046a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques @OnClickAttr 9056a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques public void onThumbnailClicked(View v) { 9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mPausing || mThreadRunning || mSurfaceTexture == null) return; 9076a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques showSharePopup(); 9086a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques } 9096a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void showSharePopup() { 9116a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques if (mThumbnail == null) return; 9126a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques Uri uri = mThumbnail.getUri(); 9136a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques if (mSharePopup == null || !uri.equals(mSharePopup.getUri())) { 9146a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques // The orientation compensation is set to 0 here because we only support landscape. 9156a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mSharePopup = new SharePopup(this, uri, mThumbnail.getBitmap(), 9166a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mOrientationCompensation, 9176a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques findViewById(R.id.frame_layout)); 9186a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques } 9196a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mSharePopup.showAtLocation(mThumbnailView, Gravity.NO_GRAVITY, 0, 0); 9206a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques } 9216a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques 9226a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques private void reset() { 9236a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mCaptureState = CAPTURE_STATE_VIEWFINDER; 9246a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques 9256a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mReviewLayout.setVisibility(View.GONE); 9266a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mShutterButton.setBackgroundResource(R.drawable.btn_shutter_pan); 9276a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mPanoProgressBar.setVisibility(View.GONE); 9286a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mCaptureLayout.setVisibility(View.VISIBLE); 9296a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mMosaicFrameProcessor.reset(); 9306a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques 9316a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques mSurfaceTexture.setOnFrameAvailableListener(this); 9326a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques } 9336a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques 9346a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques private void resetToPreview() { 9356a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques reset(); 9366a84af0949b341593b4b25ed9bb365bd60ff1254David Sobreira Marques if (!mPausing) startCameraPreview(); 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void showFinalMosaic(Bitmap bitmap) { 94099a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson if (bitmap != null) { 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mReview.setImageBitmap(bitmap); 94299a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson } 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mCaptureLayout.setVisibility(View.GONE); 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mReviewLayout.setVisibility(View.VISIBLE); 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Uri savePanorama(byte[] jpegData, int width, int height, int orientation) { 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (jpegData != null) { 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String filename = PanoUtil.createName( 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getResources().getString(R.string.pano_file_name_format), mTimeTaken); 95199a64f4b1d2519b71558fdc62721686445865b60Jesse Wilson Uri uri = Storage.addImage(getContentResolver(), filename, mTimeTaken, null, 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project orientation, jpegData, width, height); 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (uri != null && orientation != 0) { 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String filepath = Storage.generateFilepath(filename); 955 try { 956 // Save the orientation in EXIF. 957 ExifInterface exif = new ExifInterface(filepath); 958 exif.setAttribute(ExifInterface.TAG_ORIENTATION, 959 getExifOrientation(orientation)); 960 exif.saveAttributes(); 961 } catch (IOException e) { 962 Log.e(TAG, "cannot set exif data: " + filepath); 963 } 964 } 965 return uri; 966 } 967 return null; 968 } 969 970 private static String getExifOrientation(int orientation) { 971 switch (orientation) { 972 case 0: 973 return String.valueOf(ExifInterface.ORIENTATION_NORMAL); 974 case 90: 975 return String.valueOf(ExifInterface.ORIENTATION_ROTATE_90); 976 case 180: 977 return String.valueOf(ExifInterface.ORIENTATION_ROTATE_180); 978 case 270: 979 return String.valueOf(ExifInterface.ORIENTATION_ROTATE_270); 980 default: 981 throw new AssertionError("invalid: " + orientation); 982 } 983 } 984 985 private void clearMosaicFrameProcessorIfNeeded() { 986 if (!mPausing || mThreadRunning) return; 987 mMosaicFrameProcessor.clear(); 988 } 989 990 private void initMosaicFrameProcessorIfNeeded() { 991 if (mPausing || mThreadRunning) return; 992 if (mMosaicFrameProcessor == null) { 993 // Start the activity for the first time. 994 mMosaicFrameProcessor = new MosaicFrameProcessor( 995 mPreviewWidth, mPreviewHeight, getPreviewBufSize()); 996 } 997 mMosaicFrameProcessor.initialize(); 998 } 999 1000 @Override 1001 protected void onPause() { 1002 super.onPause(); 1003 1004 mPausing = true; 1005 // Stop the capturing first. 1006 if (mCaptureState == CAPTURE_STATE_MOSAIC) { 1007 stopCapture(true); 1008 reset(); 1009 } 1010 if (mSharePopup != null) mSharePopup.dismiss(); 1011 1012 saveThumbnailToFile(); 1013 1014 releaseCamera(); 1015 mMosaicView.onPause(); 1016 clearMosaicFrameProcessorIfNeeded(); 1017 mOrientationEventListener.disable(); 1018 resetScreenOn(); 1019 mCameraSound.release(); 1020 System.gc(); 1021 } 1022 1023 @Override 1024 protected void doOnResume() { 1025 mPausing = false; 1026 mOrientationEventListener.enable(); 1027 1028 mCaptureState = CAPTURE_STATE_VIEWFINDER; 1029 try { 1030 setupCamera(); 1031 1032 // Camera must be initialized before MosaicFrameProcessor is initialized. 1033 // The preview size has to be decided by camera device. 1034 initMosaicFrameProcessorIfNeeded(); 1035 mMosaicView.onResume(); 1036 1037 initThumbnailButton(); 1038 keepScreenOnAwhile(); 1039 } catch (CameraHardwareException e) { 1040 Util.showErrorAndFinish(this, R.string.cannot_connect_camera); 1041 return; 1042 } catch (CameraDisabledException e) { 1043 Util.showErrorAndFinish(this, R.string.camera_disabled); 1044 return; 1045 } 1046 // Dismiss open menu if exists. 1047 PopupManager.getInstance(this).notifyShowPopup(null); 1048 } 1049 1050 /** 1051 * Generate the final mosaic image. 1052 * 1053 * @param highRes flag to indicate whether we want to get a high-res version. 1054 * @return a MosaicJpeg with its isValid flag set to true if successful; null if the generation 1055 * process is cancelled; and a MosaicJpeg with its isValid flag set to false if there 1056 * is an error in generating the final mosaic. 1057 */ 1058 public MosaicJpeg generateFinalMosaic(boolean highRes) { 1059 int mosaicReturnCode = mMosaicFrameProcessor.createMosaic(highRes); 1060 if (mosaicReturnCode == Mosaic.MOSAIC_RET_CANCELLED) { 1061 return null; 1062 } else if (mosaicReturnCode == Mosaic.MOSAIC_RET_ERROR) { 1063 return new MosaicJpeg(); 1064 } 1065 1066 byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21(); 1067 if (imageData == null) { 1068 Log.e(TAG, "getFinalMosaicNV21() returned null."); 1069 return new MosaicJpeg(); 1070 } 1071 1072 int len = imageData.length - 8; 1073 int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16) 1074 + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF); 1075 int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16) 1076 + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF); 1077 Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height); 1078 1079 if (width <= 0 || height <= 0) { 1080 // TODO: pop up a error meesage indicating that the final result is not generated. 1081 Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " + 1082 height); 1083 return new MosaicJpeg(); 1084 } 1085 1086 YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null); 1087 ByteArrayOutputStream out = new ByteArrayOutputStream(); 1088 yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out); 1089 try { 1090 out.close(); 1091 } catch (Exception e) { 1092 Log.e(TAG, "Exception in storing final mosaic", e); 1093 return new MosaicJpeg(); 1094 } 1095 return new MosaicJpeg(out.toByteArray(), width, height); 1096 } 1097 1098 private void setPreviewTexture(SurfaceTexture surface) { 1099 try { 1100 mCameraDevice.setPreviewTexture(surface); 1101 } catch (Throwable ex) { 1102 releaseCamera(); 1103 throw new RuntimeException("setPreviewTexture failed", ex); 1104 } 1105 } 1106 1107 private void startCameraPreview() { 1108 // If we're previewing already, stop the preview first (this will blank 1109 // the screen). 1110 if (mCameraState != PREVIEW_STOPPED) stopCameraPreview(); 1111 1112 // Set the display orientation to 0, so that the underlying mosaic library 1113 // can always get undistorted mPreviewWidth x mPreviewHeight image data 1114 // from SurfaceTexture. 1115 mCameraDevice.setDisplayOrientation(0); 1116 1117 setPreviewTexture(mSurfaceTexture); 1118 1119 try { 1120 Log.v(TAG, "startPreview"); 1121 mCameraDevice.startPreview(); 1122 } catch (Throwable ex) { 1123 releaseCamera(); 1124 throw new RuntimeException("startPreview failed", ex); 1125 } 1126 mCameraState = PREVIEW_ACTIVE; 1127 } 1128 1129 private void stopCameraPreview() { 1130 if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { 1131 Log.v(TAG, "stopPreview"); 1132 mCameraDevice.stopPreview(); 1133 } 1134 mCameraState = PREVIEW_STOPPED; 1135 } 1136 1137 @Override 1138 public void onUserInteraction() { 1139 super.onUserInteraction(); 1140 if (mCaptureState != CAPTURE_STATE_MOSAIC) keepScreenOnAwhile(); 1141 } 1142 1143 @Override 1144 public void onBackPressed() { 1145 // If panorama is generating low res or high res mosaic, ignore back 1146 // key. So the activity will not be destroyed. 1147 if (mThreadRunning) return; 1148 super.onBackPressed(); 1149 } 1150 1151 private void resetScreenOn() { 1152 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); 1153 getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1154 } 1155 1156 private void keepScreenOnAwhile() { 1157 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); 1158 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1159 mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_DELAY, SCREEN_DELAY); 1160 } 1161 1162 private void keepScreenOn() { 1163 mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); 1164 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1165 } 1166} 1167