1ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb/* 2ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * Copyright (C) 2011 The Android Open Source Project 3ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * 4ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * Licensed under the Apache License, Version 2.0 (the "License"); 5ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * you may not use this file except in compliance with the License. 6ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * You may obtain a copy of the License at 7ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * 8ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * http://www.apache.org/licenses/LICENSE-2.0 9ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * 10ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * Unless required by applicable law or agreed to in writing, software 11ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * distributed under the License is distributed on an "AS IS" BASIS, 12ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * See the License for the specific language governing permissions and 14ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * limitations under the License. 15ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb */ 16ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 17ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbpackage com.android.camera; 18ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 19ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.annotation.TargetApi; 20ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.content.ContentResolver; 21ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.content.Context; 22ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.content.Intent; 23ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.content.res.Configuration; 24ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.content.res.Resources; 25ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.graphics.Bitmap; 26ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.graphics.BitmapFactory; 27dc56e543d39b366c3e360c7752d7ac94141c3885John Reckimport android.graphics.Canvas; 28ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.graphics.ImageFormat; 29fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Liimport android.graphics.Matrix; 30ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.graphics.PixelFormat; 31ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.graphics.Rect; 32ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.graphics.SurfaceTexture; 33ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.graphics.YuvImage; 34dc56e543d39b366c3e360c7752d7ac94141c3885John Reckimport android.graphics.drawable.BitmapDrawable; 35ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.graphics.drawable.Drawable; 36ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.hardware.Camera.Parameters; 37ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.hardware.Camera.Size; 38ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.media.ExifInterface; 39ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.net.Uri; 40ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.os.AsyncTask; 41ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.os.Handler; 42ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.os.Message; 43ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.os.PowerManager; 44ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.util.Log; 45ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.view.KeyEvent; 46ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.view.LayoutInflater; 47ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.view.MotionEvent; 48ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.view.OrientationEventListener; 49ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.view.View; 50ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.view.View.OnClickListener; 51ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.view.ViewGroup; 52ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.view.WindowManager; 53ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.widget.ImageView; 54ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.widget.LinearLayout; 55ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport android.widget.TextView; 56ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 57ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport com.android.camera.CameraManager.CameraProxy; 58ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport com.android.camera.ui.LayoutChangeNotifier; 59ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport com.android.camera.ui.LayoutNotifyView; 60ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport com.android.camera.ui.PopupManager; 61ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport com.android.camera.ui.Rotatable; 62ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport com.android.camera.ui.RotateLayout; 63ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport com.android.gallery3d.common.ApiHelper; 64ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport com.android.gallery3d.ui.GLRootView; 65ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 66ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport java.io.ByteArrayOutputStream; 6720523f6b162324ac642358b8802fc12a664aa73eWu-cheng Liimport java.io.File; 68ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport java.io.IOException; 69ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport java.text.DateFormat; 70ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport java.text.SimpleDateFormat; 71ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport java.util.List; 72ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbimport java.util.TimeZone; 73ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 74ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb/** 75ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * Activity to handle panorama capturing. 76ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb */ 77ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb@TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) // uses SurfaceTexture 78ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolbpublic class PanoramaModule implements CameraModule, 79ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb SurfaceTexture.OnFrameAvailableListener, 80ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb ShutterButton.OnShutterButtonListener, 81ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb LayoutChangeNotifier.Listener { 82ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 83ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public static final int DEFAULT_SWEEP_ANGLE = 160; 84ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; 85ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; 86ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 87ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final int MSG_LOW_RES_FINAL_MOSAIC_READY = 1; 881acc316227cf39a5c5eead6b307b8b3a76f5e284Wu-cheng Li private static final int MSG_GENERATE_FINAL_MOSAIC_ERROR = 2; 891acc316227cf39a5c5eead6b307b8b3a76f5e284Wu-cheng Li private static final int MSG_RESET_TO_PREVIEW = 3; 901acc316227cf39a5c5eead6b307b8b3a76f5e284Wu-cheng Li private static final int MSG_CLEAR_SCREEN_DELAY = 4; 91ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 92ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final int SCREEN_DELAY = 2 * 60 * 1000; 93ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 94ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final String TAG = "CAM PanoModule"; 95ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final int PREVIEW_STOPPED = 0; 96ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final int PREVIEW_ACTIVE = 1; 97ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final int CAPTURE_STATE_VIEWFINDER = 0; 98ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final int CAPTURE_STATE_MOSAIC = 1; 99ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 100ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd"; 101ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final String GPS_TIME_FORMAT_STR = "kk/1,mm/1,ss/1"; 102ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static final String DATETIME_FORMAT_STR = "yyyy:MM:dd kk:mm:ss"; 103ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 104b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li // The unit of speed is degrees per frame. 105b7e4d024214b85e8570ad0d8ce03472887364beeWu-cheng Li private static final float PANNING_SPEED_THRESHOLD = 2.5f; 106ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 107ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private ContentResolver mContentResolver; 108ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 109ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private GLRootView mGLRootView; 110ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private ViewGroup mPanoLayout; 111ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private LinearLayout mCaptureLayout; 112ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private View mReviewLayout; 113ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private ImageView mReview; 114445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li private View mCaptureIndicator; 115ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private PanoProgressBar mPanoProgressBar; 116ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private PanoProgressBar mSavingProgressBar; 117fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li private Matrix mProgressDirectionMatrix = new Matrix(); 118fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li private float[] mProgressAngle = new float[2]; 119ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private LayoutNotifyView mPreviewArea; 120ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private View mLeftIndicator; 121ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private View mRightIndicator; 122ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private MosaicPreviewRenderer mMosaicPreviewRenderer; 123ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private TextView mTooFastPrompt; 124ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private ShutterButton mShutterButton; 125ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private Object mWaitObject = new Object(); 126ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 127ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private DateFormat mGPSDateStampFormat; 128ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private DateFormat mGPSTimeStampFormat; 129ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private DateFormat mDateTimeStampFormat; 130ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 131ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private String mPreparePreviewString; 132ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private String mDialogTitle; 133ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private String mDialogOkString; 134ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private String mDialogPanoramaFailedString; 135ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private String mDialogWaitingPreviousString; 136ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 137ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mIndicatorColor; 138ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mIndicatorColorFast; 139ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 140ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private boolean mUsingFrontCamera; 141ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mPreviewWidth; 142ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mPreviewHeight; 143ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mCameraState; 144ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mCaptureState; 145ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private PowerManager.WakeLock mPartialWakeLock; 146ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private MosaicFrameProcessor mMosaicFrameProcessor; 147ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private boolean mMosaicFrameProcessorInitialized; 148ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private AsyncTask <Void, Void, Void> mWaitProcessorTask; 149ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private long mTimeTaken; 150ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private Handler mMainHandler; 151ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private SurfaceTexture mCameraTexture; 152ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private boolean mThreadRunning; 153ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private boolean mCancelComputation; 154ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private float mHorizontalViewAngle; 155ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private float mVerticalViewAngle; 156ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 157ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Prefer FOCUS_MODE_INFINITY to FOCUS_MODE_CONTINUOUS_VIDEO because of 158ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // getting a better image quality by the former. 159ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private String mTargetFocusMode = Parameters.FOCUS_MODE_INFINITY; 160ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 161ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private PanoOrientationEventListener mOrientationEventListener; 162ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // The value could be 0, 90, 180, 270 for the 4 different orientations measured in clockwise 163ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // respectively. 164ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mDeviceOrientation; 165ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mDeviceOrientationAtCapture; 166ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mCameraOrientation; 167ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private int mOrientationCompensation; 168ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 169ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private RotateDialogController mRotateDialog; 170ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 171ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private SoundClips.Player mSoundPlayer; 172ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 173ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private Runnable mOnFrameAvailableRunnable; 174ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 175ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private CameraActivity mActivity; 176ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private View mRootView; 177ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private CameraProxy mCameraDevice; 178ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private boolean mPaused; 179ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 180ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private class MosaicJpeg { 181ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public MosaicJpeg(byte[] data, int width, int height) { 182ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb this.data = data; 183ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb this.width = width; 184ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb this.height = height; 185ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb this.isValid = true; 186ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 187ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 188ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public MosaicJpeg() { 189ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb this.data = null; 190ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb this.width = 0; 191ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb this.height = 0; 192ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb this.isValid = false; 193ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 194ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 195ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public final byte[] data; 196ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public final int width; 197ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public final int height; 198ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public final boolean isValid; 199ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 200ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 201ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private class PanoOrientationEventListener extends OrientationEventListener { 202ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public PanoOrientationEventListener(Context context) { 203ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb super(context); 204ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 205ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 206ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 207ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onOrientationChanged(int orientation) { 208ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // We keep the last known orientation. So if the user first orient 209ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // the camera then point the camera to floor or sky, we still have 210ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // the correct orientation. 211ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (orientation == ORIENTATION_UNKNOWN) return; 212ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDeviceOrientation = Util.roundOrientation(orientation, mDeviceOrientation); 213ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // When the screen is unlocked, display rotation may change. Always 214ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // calculate the up-to-date orientationCompensation. 215ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int orientationCompensation = mDeviceOrientation 216ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb + Util.getDisplayRotation(mActivity) % 360; 217ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mOrientationCompensation != orientationCompensation) { 218ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mOrientationCompensation = orientationCompensation; 2193851712c5a250c6764c894b99984e262a8f206a4John Reck mActivity.getGLRoot().requestLayoutContentPane(); 220ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 221ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 222ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 223ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 224ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 225ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void init(CameraActivity activity, View parent, boolean reuseScreenNail) { 226ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity = activity; 227ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRootView = (ViewGroup) parent; 228ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 229ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb createContentView(); 230ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 231ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mContentResolver = mActivity.getContentResolver(); 232ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (reuseScreenNail) { 233ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.reuseCameraScreenNail(true); 234ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 235ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.createCameraScreenNail(true); 236ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 237ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 238ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // This runs in UI thread. 239ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mOnFrameAvailableRunnable = new Runnable() { 240ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 241ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void run() { 242ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Frames might still be available after the activity is paused. 243ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // If we call onFrameAvailable after pausing, the GL thread will crash. 244ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mPaused) return; 245ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 246ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mGLRootView.getVisibility() != View.VISIBLE) { 247ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicPreviewRenderer.showPreviewFrameSync(); 248ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGLRootView.setVisibility(View.VISIBLE); 249ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 250ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCaptureState == CAPTURE_STATE_VIEWFINDER) { 251ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicPreviewRenderer.showPreviewFrame(); 252ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 2538ed91ce2179d82e80437339fd17da7a3a8366b29Wu-cheng Li mMosaicPreviewRenderer.alignFrameSync(); 254ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessor.processFrame(); 255ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 256ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 257ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 258ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }; 259ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 260ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGPSDateStampFormat = new SimpleDateFormat(GPS_DATE_FORMAT_STR); 261ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGPSTimeStampFormat = new SimpleDateFormat(GPS_TIME_FORMAT_STR); 262ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDateTimeStampFormat = new SimpleDateFormat(DATETIME_FORMAT_STR); 263ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb TimeZone tzUTC = TimeZone.getTimeZone("UTC"); 264ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGPSDateStampFormat.setTimeZone(tzUTC); 265ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGPSTimeStampFormat.setTimeZone(tzUTC); 266ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 267ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb PowerManager pm = (PowerManager) mActivity.getSystemService(Context.POWER_SERVICE); 268ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPartialWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Panorama"); 269ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 270ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mOrientationEventListener = new PanoOrientationEventListener(mActivity); 271ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 272ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessor = MosaicFrameProcessor.getInstance(); 273ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 274ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Resources appRes = mActivity.getResources(); 275ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPreparePreviewString = appRes.getString(R.string.pano_dialog_prepare_preview); 276ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDialogTitle = appRes.getString(R.string.pano_dialog_title); 277ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDialogOkString = appRes.getString(R.string.dialog_ok); 278ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDialogPanoramaFailedString = appRes.getString(R.string.pano_dialog_panorama_failed); 279ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDialogWaitingPreviousString = appRes.getString(R.string.pano_dialog_waiting_previous); 280ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 281ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGLRootView = (GLRootView) mActivity.getGLRoot(); 282ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 283ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler = new Handler() { 284ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 285ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void handleMessage(Message msg) { 286ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb switch (msg.what) { 287ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case MSG_LOW_RES_FINAL_MOSAIC_READY: 288ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb onBackgroundThreadFinished(); 289ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb showFinalMosaic((Bitmap) msg.obj); 290ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb saveHighResMosaic(); 291ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb break; 292ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case MSG_GENERATE_FINAL_MOSAIC_ERROR: 293ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb onBackgroundThreadFinished(); 294ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mPaused) { 295ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb resetToPreview(); 296ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 297ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRotateDialog.showAlertDialog( 298ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDialogTitle, mDialogPanoramaFailedString, 299ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDialogOkString, new Runnable() { 300ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 301ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void run() { 302ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb resetToPreview(); 303ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }}, 304ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb null, null); 305ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 306ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb clearMosaicFrameProcessorIfNeeded(); 307ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb break; 308ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case MSG_RESET_TO_PREVIEW: 309ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb onBackgroundThreadFinished(); 310ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb resetToPreview(); 311ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb clearMosaicFrameProcessorIfNeeded(); 312ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb break; 313ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case MSG_CLEAR_SCREEN_DELAY: 314ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.getWindow().clearFlags(WindowManager.LayoutParams. 315ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb FLAG_KEEP_SCREEN_ON); 316ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb break; 317ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 318ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 319ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }; 320ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 321ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 322ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 323ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public boolean dispatchTouchEvent(MotionEvent m) { 3244d628bcbaf4e6f2330dc9619f2129770863666dcMichael Kolb return mActivity.superDispatchTouchEvent(m); 325ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 326ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 327ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void setupCamera() throws CameraHardwareException, CameraDisabledException { 328ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb openCamera(); 329ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Parameters parameters = mCameraDevice.getParameters(); 330ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb setupCaptureParams(parameters); 331ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb configureCamera(parameters); 332ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 333ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 334ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void releaseCamera() { 335ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCameraDevice != null) { 336ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraDevice.setPreviewCallbackWithBuffer(null); 337ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb CameraHolder.instance().release(); 338ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraDevice = null; 339ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraState = PREVIEW_STOPPED; 340ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 341ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 342ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 343ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void openCamera() throws CameraHardwareException, CameraDisabledException { 344ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int cameraId = CameraHolder.instance().getBackCameraId(); 345ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // If there is no back camera, use the first camera. Camera id starts 346ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // from 0. Currently if a camera is not back facing, it is front facing. 347ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // This is also forward compatible if we have a new facing other than 348ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // back or front in the future. 349ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (cameraId == -1) cameraId = 0; 350ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraDevice = Util.openCamera(mActivity, cameraId); 351ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraOrientation = Util.getCameraOrientation(cameraId); 352ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (cameraId == CameraHolder.instance().getFrontCameraId()) mUsingFrontCamera = true; 353ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 354ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 355ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, 356ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb boolean needSmaller) { 357ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int pixelsDiff = DEFAULT_CAPTURE_PIXELS; 358ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb boolean hasFound = false; 359ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb for (Size size : supportedSizes) { 360ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int h = size.height; 361ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int w = size.width; 362ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // we only want 4:3 format. 363ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int d = DEFAULT_CAPTURE_PIXELS - h * w; 364ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (needSmaller && d < 0) { // no bigger preview than 960x720. 365ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb continue; 366ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 367ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (need4To3 && (h * 4 != w * 3)) { 368ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb continue; 369ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 370ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb d = Math.abs(d); 371ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (d < pixelsDiff) { 372ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPreviewWidth = w; 373ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPreviewHeight = h; 374ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb pixelsDiff = d; 375ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb hasFound = true; 376ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 377ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 378ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return hasFound; 379ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 380ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 381ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void setupCaptureParams(Parameters parameters) { 382ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); 383ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (!findBestPreviewSize(supportedSizes, true, true)) { 384ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.w(TAG, "No 4:3 ratio preview size supported."); 385ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (!findBestPreviewSize(supportedSizes, false, true)) { 386ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); 387ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb findBestPreviewSize(supportedSizes, false, false); 388ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 389ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 390ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth); 391ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb parameters.setPreviewSize(mPreviewWidth, mPreviewHeight); 392ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 393ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb List<int[]> frameRates = parameters.getSupportedPreviewFpsRange(); 394ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int last = frameRates.size() - 1; 395ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX]; 396ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX]; 397ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb parameters.setPreviewFpsRange(minFps, maxFps); 398ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.v(TAG, "preview fps: " + minFps + ", " + maxFps); 399ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 400ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb List<String> supportedFocusModes = parameters.getSupportedFocusModes(); 401ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (supportedFocusModes.indexOf(mTargetFocusMode) >= 0) { 402ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb parameters.setFocusMode(mTargetFocusMode); 403ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 404ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Use the default focus mode and log a message 405ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.w(TAG, "Cannot set the focus mode to " + mTargetFocusMode + 406ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb " becuase the mode is not supported."); 407ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 408ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 409ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb parameters.set(Util.RECORDING_HINT, Util.FALSE); 410ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 411ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mHorizontalViewAngle = parameters.getHorizontalViewAngle(); 412ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mVerticalViewAngle = parameters.getVerticalViewAngle(); 413ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 414ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 415ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public int getPreviewBufSize() { 416ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb PixelFormat pixelInfo = new PixelFormat(); 417ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo); 418ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // TODO: remove this extra 32 byte after the driver bug is fixed. 419ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32; 420ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 421ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 422ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void configureCamera(Parameters parameters) { 423ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraDevice.setParameters(parameters); 424ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 425ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 426ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void configMosaicPreview(int w, int h) { 427ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb stopCameraPreview(); 428ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; 429ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb screenNail.setSize(w, h); 430ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (screenNail.getSurfaceTexture() == null) { 431ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb screenNail.acquireSurfaceTexture(); 432ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 433ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb screenNail.releaseSurfaceTexture(); 434ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb screenNail.acquireSurfaceTexture(); 435ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.notifyScreenNailChanged(); 436ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 437ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb boolean isLandscape = (mActivity.getResources().getConfiguration().orientation 438ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb == Configuration.ORIENTATION_LANDSCAPE); 439ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mMosaicPreviewRenderer != null) mMosaicPreviewRenderer.release(); 440ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicPreviewRenderer = new MosaicPreviewRenderer( 441ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb screenNail.getSurfaceTexture(), w, h, isLandscape); 442ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 443ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraTexture = mMosaicPreviewRenderer.getInputSurfaceTexture(); 444ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (!mPaused && !mThreadRunning && mWaitProcessorTask == null) { 445ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb resetToPreview(); 446ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 447ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 448ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 449ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Receives the layout change event from the preview area. So we can set 450ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // the camera preview screennail to the same size and initialize the mosaic 451ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // preview renderer. 452ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 453ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onLayoutChange(View v, int l, int t, int r, int b) { 454ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.i(TAG, "layout change: "+(r - l) + "/" +(b - t)); 455ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.onLayoutChange(v, l, t, r, b); 456ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb configMosaicPreview(r - l, b - t); 457ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 458ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 459ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 460ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onFrameAvailable(SurfaceTexture surface) { 461ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb /* This function may be called by some random thread, 462ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * so let's be safe and jump back to ui thread. 463ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * No OpenGL calls can be done here. */ 464ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.runOnUiThread(mOnFrameAvailableRunnable); 465ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 466ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 467ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void hideDirectionIndicators() { 468ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mLeftIndicator.setVisibility(View.GONE); 469ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRightIndicator.setVisibility(View.GONE); 470ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 471ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 472ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void showDirectionIndicators(int direction) { 473ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb switch (direction) { 474ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case PanoProgressBar.DIRECTION_NONE: 475ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mLeftIndicator.setVisibility(View.VISIBLE); 476ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRightIndicator.setVisibility(View.VISIBLE); 477ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb break; 478ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case PanoProgressBar.DIRECTION_LEFT: 479ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mLeftIndicator.setVisibility(View.VISIBLE); 480ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRightIndicator.setVisibility(View.GONE); 481ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb break; 482ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case PanoProgressBar.DIRECTION_RIGHT: 483ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mLeftIndicator.setVisibility(View.GONE); 484ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRightIndicator.setVisibility(View.VISIBLE); 485ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb break; 486ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 487ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 488ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 489ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void startCapture() { 490ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Reset values so we can do this again. 491ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCancelComputation = false; 492ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mTimeTaken = System.currentTimeMillis(); 493ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.setSwipingEnabled(false); 494da04f24a205d92c72c32d7768f0d3b4b1f93512dMichael Kolb mActivity.hideSwitcher(); 495da04f24a205d92c72c32d7768f0d3b4b1f93512dMichael Kolb mShutterButton.setImageResource(R.drawable.btn_shutter_recording); 496ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureState = CAPTURE_STATE_MOSAIC; 497ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureIndicator.setVisibility(View.VISIBLE); 498ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb showDirectionIndicators(PanoProgressBar.DIRECTION_NONE); 499ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 500ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() { 501ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 502ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onProgress(boolean isFinished, float panningRateX, float panningRateY, 503ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb float progressX, float progressY) { 504ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb float accumulatedHorizontalAngle = progressX * mHorizontalViewAngle; 505ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb float accumulatedVerticalAngle = progressY * mVerticalViewAngle; 506ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (isFinished 507ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb || (Math.abs(accumulatedHorizontalAngle) >= DEFAULT_SWEEP_ANGLE) 508ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb || (Math.abs(accumulatedVerticalAngle) >= DEFAULT_SWEEP_ANGLE)) { 509ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb stopCapture(false); 510ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 511ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb float panningRateXInDegree = panningRateX * mHorizontalViewAngle; 512ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb float panningRateYInDegree = panningRateY * mVerticalViewAngle; 513ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb updateProgress(panningRateXInDegree, panningRateYInDegree, 514ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb accumulatedHorizontalAngle, accumulatedVerticalAngle); 515ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 516ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 517ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }); 518ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 519ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.reset(); 520ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // TODO: calculate the indicator width according to different devices to reflect the actual 521ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // angle of view of the camera device. 522ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setIndicatorWidth(20); 523ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setMaxProgress(DEFAULT_SWEEP_ANGLE); 524ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setVisibility(View.VISIBLE); 525ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mDeviceOrientationAtCapture = mDeviceOrientation; 526ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb keepScreenOn(); 527032dea1d8406cde556ec0a441e4c90409edf9d63John Reck mActivity.getOrientationManager().lockOrientation(); 528fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li setupProgressDirectionMatrix(); 529fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li } 530fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li 531fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li void setupProgressDirectionMatrix() { 532fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li int degrees = Util.getDisplayRotation(mActivity); 533fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li int cameraId = CameraHolder.instance().getBackCameraId(); 534fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li int orientation = Util.getDisplayOrientation(degrees, cameraId); 535fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li mProgressDirectionMatrix.reset(); 536fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li mProgressDirectionMatrix.postRotate(orientation); 537ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 538ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 539ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void stopCapture(boolean aborted) { 540ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureState = CAPTURE_STATE_VIEWFINDER; 541ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureIndicator.setVisibility(View.GONE); 542ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb hideTooFastIndication(); 543ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb hideDirectionIndicators(); 544ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 545ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessor.setProgressListener(null); 546ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb stopCameraPreview(); 547ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 548ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraTexture.setOnFrameAvailableListener(null); 549ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 550ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (!aborted && !mThreadRunning) { 551ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRotateDialog.showWaitingDialog(mPreparePreviewString); 552725aec5162fc18330b3a915b6e7a0488bbae2fecDoris Liu // Hide shutter button, shutter icon, etc when waiting for 553725aec5162fc18330b3a915b6e7a0488bbae2fecDoris Liu // panorama to stitch 554725aec5162fc18330b3a915b6e7a0488bbae2fecDoris Liu mActivity.hideUI(); 555ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb runBackgroundThread(new Thread() { 556ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 557ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void run() { 558ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb MosaicJpeg jpeg = generateFinalMosaic(false); 559ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 560ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (jpeg != null && jpeg.isValid) { 561ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Bitmap bitmap = null; 562ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb bitmap = BitmapFactory.decodeByteArray(jpeg.data, 0, jpeg.data.length); 563ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.sendMessage(mMainHandler.obtainMessage( 564ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb MSG_LOW_RES_FINAL_MOSAIC_READY, bitmap)); 565ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 566ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.sendMessage(mMainHandler.obtainMessage( 567ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb MSG_RESET_TO_PREVIEW)); 568ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 569ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 570ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }); 571ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 572ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb keepScreenOnAwhile(); 573ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 574ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 575ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void showTooFastIndication() { 576ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mTooFastPrompt.setVisibility(View.VISIBLE); 577ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // The PreviewArea also contains the border for "too fast" indication. 578ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPreviewArea.setVisibility(View.VISIBLE); 579ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setIndicatorColor(mIndicatorColorFast); 580ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mLeftIndicator.setEnabled(true); 581ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRightIndicator.setEnabled(true); 582ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 583ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 584ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void hideTooFastIndication() { 585ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mTooFastPrompt.setVisibility(View.GONE); 586ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // We set "INVISIBLE" instead of "GONE" here because we need mPreviewArea to have layout 587ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // information so we can know the size and position for mCameraScreenNail. 588ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPreviewArea.setVisibility(View.INVISIBLE); 589ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setIndicatorColor(mIndicatorColor); 590ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mLeftIndicator.setEnabled(false); 591ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRightIndicator.setEnabled(false); 592ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 593ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 594ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void updateProgress(float panningRateXInDegree, float panningRateYInDegree, 595ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb float progressHorizontalAngle, float progressVerticalAngle) { 596ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGLRootView.requestRender(); 597ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 598ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if ((Math.abs(panningRateXInDegree) > PANNING_SPEED_THRESHOLD) 599ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb || (Math.abs(panningRateYInDegree) > PANNING_SPEED_THRESHOLD)) { 600ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb showTooFastIndication(); 601ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 602ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb hideTooFastIndication(); 603ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 604fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li 605fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li // progressHorizontalAngle and progressVerticalAngle are relative to the 606fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li // camera. Convert them to UI direction. 607fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li mProgressAngle[0] = progressHorizontalAngle; 608fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li mProgressAngle[1] = progressVerticalAngle; 609fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li mProgressDirectionMatrix.mapPoints(mProgressAngle); 610fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li 611ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int angleInMajorDirection = 612fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li (Math.abs(mProgressAngle[0]) > Math.abs(mProgressAngle[1])) 613fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li ? (int) mProgressAngle[0] 614fd3edfbbbe8328b738ce7b4c3a1fd37ee053b72eWu-cheng Li : (int) mProgressAngle[1]; 615ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setProgress((angleInMajorDirection)); 616ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 617ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 618ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void setViews(Resources appRes) { 619ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureState = CAPTURE_STATE_VIEWFINDER; 620ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_pan_progress_bar); 621ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); 622ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_done)); 623ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setIndicatorColor(mIndicatorColor); 624ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setOnDirectionChangeListener( 625ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb new PanoProgressBar.OnDirectionChangeListener () { 626ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 627ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onDirectionChange(int direction) { 628ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCaptureState == CAPTURE_STATE_MOSAIC) { 629ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb showDirectionIndicators(direction); 630ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 631ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 632ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }); 633ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 634ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mLeftIndicator = mRootView.findViewById(R.id.pano_pan_left_indicator); 635ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRightIndicator = mRootView.findViewById(R.id.pano_pan_right_indicator); 636ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mLeftIndicator.setEnabled(false); 637ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRightIndicator.setEnabled(false); 638ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mTooFastPrompt = (TextView) mRootView.findViewById(R.id.pano_capture_too_fast_textview); 639ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // This mPreviewArea also shows the border for visual "too fast" indication. 640ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPreviewArea = (LayoutNotifyView) mRootView.findViewById(R.id.pano_preview_area); 641ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPreviewArea.setOnLayoutChangeListener(this); 642ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 643ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSavingProgressBar = (PanoProgressBar) mRootView.findViewById(R.id.pano_saving_progress_bar); 644ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSavingProgressBar.setIndicatorWidth(0); 645ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSavingProgressBar.setMaxProgress(100); 646ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSavingProgressBar.setBackgroundColor(appRes.getColor(R.color.pano_progress_empty)); 647ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSavingProgressBar.setDoneColor(appRes.getColor(R.color.pano_progress_indication)); 648ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 649445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li mCaptureIndicator = mRootView.findViewById(R.id.pano_capture_indicator); 650ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 651ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mReviewLayout = mRootView.findViewById(R.id.pano_review_layout); 652ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mReview = (ImageView) mRootView.findViewById(R.id.pano_reviewarea); 653ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb View cancelButton = mRootView.findViewById(R.id.pano_review_cancel_button); 654ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb cancelButton.setOnClickListener(new OnClickListener() { 655ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 656ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onClick(View arg0) { 657ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mPaused || mCameraTexture == null) return; 658ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb cancelHighResComputation(); 659ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 660ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }); 661ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 662ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mShutterButton = mActivity.getShutterButton(); 663da04f24a205d92c72c32d7768f0d3b4b1f93512dMichael Kolb mShutterButton.setImageResource(R.drawable.btn_new_shutter); 664ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mShutterButton.setOnShutterButtonListener(this); 665ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 666ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mActivity.getResources().getConfiguration().orientation 667ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb == Configuration.ORIENTATION_PORTRAIT) { 668445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li Rotatable view = (Rotatable) mRootView.findViewById(R.id.pano_rotate_reviewarea); 669445ed7298889bb5f3ba1ee8c0db4ae6e46f1fbb8Wu-cheng Li view.setOrientation(270, false); 670ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 671ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 672ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 673ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void createContentView() { 674ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.getLayoutInflater().inflate(R.layout.panorama_module, (ViewGroup) mRootView); 675ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Resources appRes = mActivity.getResources(); 676ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureLayout = (LinearLayout) mRootView.findViewById(R.id.camera_app_root); 677ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mIndicatorColor = appRes.getColor(R.color.pano_progress_indication); 678ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mIndicatorColorFast = appRes.getColor(R.color.pano_progress_indication_fast); 679ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoLayout = (ViewGroup) mRootView.findViewById(R.id.pano_layout); 680ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRotateDialog = new RotateDialogController(mActivity, R.layout.rotate_dialog); 681ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb setViews(appRes); 682ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 683ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 684ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 685ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onShutterButtonClick() { 686ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // If mCameraTexture == null then GL setup is not finished yet. 687ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // No buttons can be pressed. 688ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mPaused || mThreadRunning || mCameraTexture == null) return; 689ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Since this button will stay on the screen when capturing, we need to check the state 690ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // right now. 691ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb switch (mCaptureState) { 692ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case CAPTURE_STATE_VIEWFINDER: 693ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if(mActivity.getStorageSpace() <= Storage.LOW_STORAGE_THRESHOLD) return; 694ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSoundPlayer.play(SoundClips.START_VIDEO_RECORDING); 695ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb startCapture(); 696ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb break; 697ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case CAPTURE_STATE_MOSAIC: 698ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSoundPlayer.play(SoundClips.STOP_VIDEO_RECORDING); 699ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb stopCapture(false); 700ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 701ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 702ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 703ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 704ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onShutterButtonFocus(boolean pressed) { 705ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 706ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 707ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void reportProgress() { 708ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSavingProgressBar.reset(); 709ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSavingProgressBar.setRightIncreasing(true); 710ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Thread t = new Thread() { 711ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 712ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void run() { 713ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb while (mThreadRunning) { 714ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb final int progress = mMosaicFrameProcessor.reportProgress( 715ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb true, mCancelComputation); 716ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 717ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb try { 718ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb synchronized (mWaitObject) { 719ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mWaitObject.wait(50); 720ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 721ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } catch (InterruptedException e) { 722ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb throw new RuntimeException("Panorama reportProgress failed", e); 723ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 724ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Update the progress bar 725ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.runOnUiThread(new Runnable() { 726ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 727ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void run() { 728ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSavingProgressBar.setProgress(progress); 729ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 730ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }); 731ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 732ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 733ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }; 734ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb t.start(); 735ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 736ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 737dc56e543d39b366c3e360c7752d7ac94141c3885John Reck private int getCaptureOrientation() { 738dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // The panorama image returned from the library is oriented based on the 739dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // natural orientation of a camera. We need to set an orientation for the image 740dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // in its EXIF header, so the image can be displayed correctly. 741dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // The orientation is calculated from compensating the 742dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // device orientation at capture and the camera orientation respective to 743dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // the natural orientation of the device. 744dc56e543d39b366c3e360c7752d7ac94141c3885John Reck int orientation; 745dc56e543d39b366c3e360c7752d7ac94141c3885John Reck if (mUsingFrontCamera) { 746dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // mCameraOrientation is negative with respect to the front facing camera. 747dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // See document of android.hardware.Camera.Parameters.setRotation. 748dc56e543d39b366c3e360c7752d7ac94141c3885John Reck orientation = (mDeviceOrientationAtCapture - mCameraOrientation + 360) % 360; 749dc56e543d39b366c3e360c7752d7ac94141c3885John Reck } else { 750dc56e543d39b366c3e360c7752d7ac94141c3885John Reck orientation = (mDeviceOrientationAtCapture + mCameraOrientation) % 360; 751dc56e543d39b366c3e360c7752d7ac94141c3885John Reck } 752dc56e543d39b366c3e360c7752d7ac94141c3885John Reck return orientation; 753dc56e543d39b366c3e360c7752d7ac94141c3885John Reck } 754dc56e543d39b366c3e360c7752d7ac94141c3885John Reck 755ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void saveHighResMosaic() { 756ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb runBackgroundThread(new Thread() { 757ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 758ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void run() { 759ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPartialWakeLock.acquire(); 760ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb MosaicJpeg jpeg; 761ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb try { 762ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb jpeg = generateFinalMosaic(true); 763ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } finally { 764ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPartialWakeLock.release(); 765ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 766ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 767ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (jpeg == null) { // Cancelled by user. 768ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.sendEmptyMessage(MSG_RESET_TO_PREVIEW); 769ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else if (!jpeg.isValid) { // Error when generating mosaic. 770ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.sendEmptyMessage(MSG_GENERATE_FINAL_MOSAIC_ERROR); 771ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 772dc56e543d39b366c3e360c7752d7ac94141c3885John Reck int orientation = getCaptureOrientation(); 773ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Uri uri = savePanorama(jpeg.data, jpeg.width, jpeg.height, orientation); 774ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (uri != null) { 775ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.addSecureAlbumItemIfNeeded(false, uri); 776ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Util.broadcastNewPicture(mActivity, uri); 777ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 778ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.sendMessage( 7791acc316227cf39a5c5eead6b307b8b3a76f5e284Wu-cheng Li mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW)); 780ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 781ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 782ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb }); 783ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb reportProgress(); 784ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 785ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 786ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void runBackgroundThread(Thread thread) { 787ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mThreadRunning = true; 788ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb thread.start(); 789ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 790ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 791ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void onBackgroundThreadFinished() { 792ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mThreadRunning = false; 793ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRotateDialog.dismissDialog(); 794ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 795ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 796ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void cancelHighResComputation() { 797ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCancelComputation = true; 798ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb synchronized (mWaitObject) { 799ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mWaitObject.notify(); 800ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 801ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 802ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 803ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // This function will be called upon the first camera frame is available. 804ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void reset() { 805ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureState = CAPTURE_STATE_VIEWFINDER; 806ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 8074de11f3b5d5a83c23822c13b8c2c80872a375878Doris Liu mActivity.getOrientationManager().unlockOrientation(); 808ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // We should set mGLRootView visible too. However, since there might be no 809ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // frame available yet, setting mGLRootView visible should be done right after 810ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // the first camera frame is available and therefore it is done by 811ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // mOnFirstFrameAvailableRunnable. 812ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.setSwipingEnabled(true); 813da04f24a205d92c72c32d7768f0d3b4b1f93512dMichael Kolb mShutterButton.setImageResource(R.drawable.btn_new_shutter); 814ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mReviewLayout.setVisibility(View.GONE); 815ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoProgressBar.setVisibility(View.GONE); 8163125574902f989e58e57425700e66a0e9bca0744Wu-cheng Li // Orientation change will trigger onLayoutChange->configMosaicPreview-> 8173125574902f989e58e57425700e66a0e9bca0744Wu-cheng Li // resetToPreview. Do not show the capture UI in film strip. 8183125574902f989e58e57425700e66a0e9bca0744Wu-cheng Li if (mActivity.mShowCameraAppView) { 8193125574902f989e58e57425700e66a0e9bca0744Wu-cheng Li mCaptureLayout.setVisibility(View.VISIBLE); 8203125574902f989e58e57425700e66a0e9bca0744Wu-cheng Li mActivity.showUI(); 8213125574902f989e58e57425700e66a0e9bca0744Wu-cheng Li } 822ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessor.reset(); 823ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 824ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 825ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void resetToPreview() { 826ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb reset(); 827ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (!mPaused) startCameraPreview(); 828ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 829ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 830dc56e543d39b366c3e360c7752d7ac94141c3885John Reck private static class FlipBitmapDrawable extends BitmapDrawable { 831dc56e543d39b366c3e360c7752d7ac94141c3885John Reck 832dc56e543d39b366c3e360c7752d7ac94141c3885John Reck public FlipBitmapDrawable(Resources res, Bitmap bitmap) { 833dc56e543d39b366c3e360c7752d7ac94141c3885John Reck super(res, bitmap); 834dc56e543d39b366c3e360c7752d7ac94141c3885John Reck } 835dc56e543d39b366c3e360c7752d7ac94141c3885John Reck 836dc56e543d39b366c3e360c7752d7ac94141c3885John Reck @Override 837dc56e543d39b366c3e360c7752d7ac94141c3885John Reck public void draw(Canvas canvas) { 838dc56e543d39b366c3e360c7752d7ac94141c3885John Reck Rect bounds = getBounds(); 839dc56e543d39b366c3e360c7752d7ac94141c3885John Reck int cx = bounds.centerX(); 840dc56e543d39b366c3e360c7752d7ac94141c3885John Reck int cy = bounds.centerY(); 841dc56e543d39b366c3e360c7752d7ac94141c3885John Reck canvas.save(Canvas.MATRIX_SAVE_FLAG); 842dc56e543d39b366c3e360c7752d7ac94141c3885John Reck canvas.rotate(180, cx, cy); 843dc56e543d39b366c3e360c7752d7ac94141c3885John Reck super.draw(canvas); 844dc56e543d39b366c3e360c7752d7ac94141c3885John Reck canvas.restore(); 845dc56e543d39b366c3e360c7752d7ac94141c3885John Reck } 846dc56e543d39b366c3e360c7752d7ac94141c3885John Reck } 847dc56e543d39b366c3e360c7752d7ac94141c3885John Reck 848ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void showFinalMosaic(Bitmap bitmap) { 849ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (bitmap != null) { 850dc56e543d39b366c3e360c7752d7ac94141c3885John Reck int orientation = getCaptureOrientation(); 851dc56e543d39b366c3e360c7752d7ac94141c3885John Reck if (orientation >= 180) { 852dc56e543d39b366c3e360c7752d7ac94141c3885John Reck // We need to flip the drawable to compensate 853dc56e543d39b366c3e360c7752d7ac94141c3885John Reck mReview.setImageDrawable(new FlipBitmapDrawable( 854dc56e543d39b366c3e360c7752d7ac94141c3885John Reck mActivity.getResources(), bitmap)); 855dc56e543d39b366c3e360c7752d7ac94141c3885John Reck } else { 856dc56e543d39b366c3e360c7752d7ac94141c3885John Reck mReview.setImageBitmap(bitmap); 857dc56e543d39b366c3e360c7752d7ac94141c3885John Reck } 858ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 859ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 860ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGLRootView.setVisibility(View.GONE); 861ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureLayout.setVisibility(View.GONE); 862ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mReviewLayout.setVisibility(View.VISIBLE); 863ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 864ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 865ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private Uri savePanorama(byte[] jpegData, int width, int height, int orientation) { 866ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (jpegData != null) { 867ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb String filename = PanoUtil.createName( 868ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.getResources().getString(R.string.pano_file_name_format), mTimeTaken); 86920523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li String filepath = Storage.generateFilepath(filename); 87020523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li Storage.writeFile(filepath, jpegData); 87120523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li 87220523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li // Add Exif tags. 87320523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li try { 87420523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li ExifInterface exif = new ExifInterface(filepath); 87520523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li exif.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, 87620523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li mGPSDateStampFormat.format(mTimeTaken)); 87720523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li exif.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, 87820523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li mGPSTimeStampFormat.format(mTimeTaken)); 87920523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li exif.setAttribute(ExifInterface.TAG_DATETIME, 88020523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li mDateTimeStampFormat.format(mTimeTaken)); 88120523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li exif.setAttribute(ExifInterface.TAG_ORIENTATION, 88220523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li getExifOrientation(orientation)); 88320523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li exif.saveAttributes(); 88420523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li } catch (IOException e) { 88520523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li Log.e(TAG, "Cannot set EXIF for " + filepath, e); 886ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 88720523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li 88820523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li int jpegLength = (int) (new File(filepath).length()); 88920523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li return Storage.addImage(mContentResolver, filename, mTimeTaken, 89020523f6b162324ac642358b8802fc12a664aa73eWu-cheng Li null, orientation, jpegLength, filepath, width, height); 891ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 892ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return null; 893ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 894ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 895ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private static String getExifOrientation(int orientation) { 896ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb switch (orientation) { 897ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case 0: 898ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return String.valueOf(ExifInterface.ORIENTATION_NORMAL); 899ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case 90: 900ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return String.valueOf(ExifInterface.ORIENTATION_ROTATE_90); 901ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case 180: 902ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return String.valueOf(ExifInterface.ORIENTATION_ROTATE_180); 903ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb case 270: 904ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return String.valueOf(ExifInterface.ORIENTATION_ROTATE_270); 905ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb default: 906ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb throw new AssertionError("invalid: " + orientation); 907ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 908ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 909ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 910ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void clearMosaicFrameProcessorIfNeeded() { 911ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (!mPaused || mThreadRunning) return; 912ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Only clear the processor if it is initialized by this activity 913ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // instance. Other activity instances may be using it. 914ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mMosaicFrameProcessorInitialized) { 915ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessor.clear(); 916ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessorInitialized = false; 917ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 918ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 919ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 920ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void initMosaicFrameProcessorIfNeeded() { 921ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mPaused || mThreadRunning) return; 922ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessor.initialize( 923ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPreviewWidth, mPreviewHeight, getPreviewBufSize()); 924ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessorInitialized = true; 925ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 926ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 927ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 928ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onPauseBeforeSuper() { 929ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPaused = true; 930ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 931ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 932ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 933ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onPauseAfterSuper() { 934ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mOrientationEventListener.disable(); 935ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCameraDevice == null) { 936ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Camera open failed. Nothing should be done here. 937ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return; 938ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 939ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Stop the capturing first. 940ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCaptureState == CAPTURE_STATE_MOSAIC) { 941ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb stopCapture(true); 942ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb reset(); 943ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 944ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 945ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb releaseCamera(); 946ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraTexture = null; 947ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 948ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // The preview renderer might not have a chance to be initialized before 949ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // onPause(). 950ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mMosaicPreviewRenderer != null) { 951ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicPreviewRenderer.release(); 952ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicPreviewRenderer = null; 953ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 954ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 955ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb clearMosaicFrameProcessorIfNeeded(); 956ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mWaitProcessorTask != null) { 957ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mWaitProcessorTask.cancel(true); 958ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mWaitProcessorTask = null; 959ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 960ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb resetScreenOn(); 961ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mSoundPlayer != null) { 962ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSoundPlayer.release(); 963ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSoundPlayer = null; 964ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 965ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb CameraScreenNail screenNail = (CameraScreenNail) mActivity.mCameraScreenNail; 966ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (screenNail.getSurfaceTexture() != null) { 967ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb screenNail.releaseSurfaceTexture(); 968ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 969ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb System.gc(); 970ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 971ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 972ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 973ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onConfigurationChanged(Configuration newConfig) { 974ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 975ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Drawable lowResReview = null; 976ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mThreadRunning) lowResReview = mReview.getDrawable(); 977ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 978ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Change layout in response to configuration change 979ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureLayout.setOrientation( 980ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE 981ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); 982ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureLayout.removeAllViews(); 983ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb LayoutInflater inflater = mActivity.getLayoutInflater(); 984ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb inflater.inflate(R.layout.preview_frame_pano, mCaptureLayout); 985ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 986ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPanoLayout.removeView(mReviewLayout); 987ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb inflater.inflate(R.layout.pano_review, mPanoLayout); 988ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 989ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb setViews(mActivity.getResources()); 990ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mThreadRunning) { 991ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mReview.setImageDrawable(lowResReview); 992ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureLayout.setVisibility(View.GONE); 993ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mReviewLayout.setVisibility(View.VISIBLE); 994ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 995ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 996ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 997ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 99878711c990e57ce7c6228c5446cfb6902f2a47cb6Doris Liu public void onOrientationChanged(int orientation) { 99978711c990e57ce7c6228c5446cfb6902f2a47cb6Doris Liu } 100078711c990e57ce7c6228c5446cfb6902f2a47cb6Doris Liu 100178711c990e57ce7c6228c5446cfb6902f2a47cb6Doris Liu @Override 1002ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onResumeBeforeSuper() { 1003ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mPaused = false; 1004ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1005ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1006ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1007ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onResumeAfterSuper() { 1008ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mOrientationEventListener.enable(); 1009ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1010ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCaptureState = CAPTURE_STATE_VIEWFINDER; 1011ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1012ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb try { 1013f99fd501c9cbff7617129af36707d1e22952aa31Wu-cheng Li setupCamera(); 1014f99fd501c9cbff7617129af36707d1e22952aa31Wu-cheng Li } catch (CameraHardwareException e) { 1015ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Util.showErrorAndFinish(mActivity, R.string.cannot_connect_camera); 1016ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return; 1017f99fd501c9cbff7617129af36707d1e22952aa31Wu-cheng Li } catch (CameraDisabledException e) { 1018ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Util.showErrorAndFinish(mActivity, R.string.camera_disabled); 1019ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return; 1020ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1021ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1022ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Set up sound playback for shutter button 1023ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mSoundPlayer = SoundClips.getPlayer(mActivity); 1024ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1025ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Check if another panorama instance is using the mosaic frame processor. 1026ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRotateDialog.dismissDialog(); 1027ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (!mThreadRunning && mMosaicFrameProcessor.isMosaicMemoryAllocated()) { 1028ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGLRootView.setVisibility(View.GONE); 1029ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRotateDialog.showWaitingDialog(mDialogWaitingPreviousString); 1030725aec5162fc18330b3a915b6e7a0488bbae2fecDoris Liu // If stitching is still going on, make sure switcher and shutter button 1031725aec5162fc18330b3a915b6e7a0488bbae2fecDoris Liu // are not showing 1032725aec5162fc18330b3a915b6e7a0488bbae2fecDoris Liu mActivity.hideUI(); 1033ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mWaitProcessorTask = new WaitProcessorTask().execute(); 1034ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else { 1035ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (!mThreadRunning) mGLRootView.setVisibility(View.VISIBLE); 1036ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Camera must be initialized before MosaicFrameProcessor is 1037ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // initialized. The preview size has to be decided by camera device. 1038ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb initMosaicFrameProcessorIfNeeded(); 1039ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int w = mPreviewArea.getWidth(); 1040ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int h = mPreviewArea.getHeight(); 1041ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (w != 0 && h != 0) { // The layout has been calculated. 1042ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb configMosaicPreview(w, h); 1043ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1044ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1045ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb keepScreenOnAwhile(); 1046ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1047ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Dismiss open menu if exists. 1048ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb PopupManager.getInstance(mActivity).notifyShowPopup(null); 1049ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRootView.requestLayout(); 1050ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1051ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1052ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb /** 1053ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * Generate the final mosaic image. 1054ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * 1055ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * @param highRes flag to indicate whether we want to get a high-res version. 1056ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * @return a MosaicJpeg with its isValid flag set to true if successful; null if the generation 1057ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * process is cancelled; and a MosaicJpeg with its isValid flag set to false if there 1058ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb * is an error in generating the final mosaic. 1059ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb */ 1060ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public MosaicJpeg generateFinalMosaic(boolean highRes) { 1061ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int mosaicReturnCode = mMosaicFrameProcessor.createMosaic(highRes); 1062ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mosaicReturnCode == Mosaic.MOSAIC_RET_CANCELLED) { 1063ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return null; 1064ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } else if (mosaicReturnCode == Mosaic.MOSAIC_RET_ERROR) { 1065ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return new MosaicJpeg(); 1066ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1067ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1068ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21(); 1069ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (imageData == null) { 1070ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.e(TAG, "getFinalMosaicNV21() returned null."); 1071ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return new MosaicJpeg(); 1072ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1073ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1074ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int len = imageData.length - 8; 1075ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16) 1076ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF); 1077ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16) 1078ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF); 1079ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height); 1080ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1081ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (width <= 0 || height <= 0) { 1082ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // TODO: pop up an error message indicating that the final result is not generated. 1083ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " + 1084ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb height); 1085ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return new MosaicJpeg(); 1086ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1087ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1088ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null); 1089ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb ByteArrayOutputStream out = new ByteArrayOutputStream(); 1090ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out); 1091ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb try { 1092ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb out.close(); 1093ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } catch (Exception e) { 1094ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.e(TAG, "Exception in storing final mosaic", e); 1095ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return new MosaicJpeg(); 1096ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1097ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return new MosaicJpeg(out.toByteArray(), width, height); 1098ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1099ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1100ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void startCameraPreview() { 1101ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCameraDevice == null) { 1102ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Camera open failed. Return. 1103ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return; 1104ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1105ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1106ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // This works around a driver issue. startPreview may fail if 1107ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // stopPreview/setPreviewTexture/startPreview are called several times 1108ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // in a row. mCameraTexture can be null after pressing home during 1109ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // mosaic generation and coming back. Preview will be started later in 1110ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // onLayoutChange->configMosaicPreview. This also reduces the latency. 1111ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCameraTexture == null) return; 1112ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1113ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // If we're previewing already, stop the preview first (this will blank 1114ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // the screen). 1115ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCameraState != PREVIEW_STOPPED) stopCameraPreview(); 1116ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1117ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // Set the display orientation to 0, so that the underlying mosaic library 1118ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // can always get undistorted mPreviewWidth x mPreviewHeight image data 1119ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // from SurfaceTexture. 1120ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraDevice.setDisplayOrientation(0); 1121ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1122ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCameraTexture != null) mCameraTexture.setOnFrameAvailableListener(this); 1123ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraDevice.setPreviewTextureAsync(mCameraTexture); 1124ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1125ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraDevice.startPreviewAsync(); 1126ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraState = PREVIEW_ACTIVE; 1127ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1128ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1129ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void stopCameraPreview() { 1130ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { 1131ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb Log.v(TAG, "stopPreview"); 1132ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraDevice.stopPreview(); 1133ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1134ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mCameraState = PREVIEW_STOPPED; 1135ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1136ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1137ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1138ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onUserInteraction() { 1139ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mCaptureState != CAPTURE_STATE_MOSAIC) keepScreenOnAwhile(); 1140ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1141ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1142ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1143ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public boolean onBackPressed() { 1144ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // If panorama is generating low res or high res mosaic, ignore back 1145ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // key. So the activity will not be destroyed. 1146ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (mThreadRunning) return true; 1147ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return false; 1148ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1149ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1150ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void resetScreenOn() { 1151ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); 1152ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1153ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1154ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1155ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void keepScreenOnAwhile() { 1156ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); 1157ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1158ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.sendEmptyMessageDelayed(MSG_CLEAR_SCREEN_DELAY, SCREEN_DELAY); 1159ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1160ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1161ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private void keepScreenOn() { 1162ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMainHandler.removeMessages(MSG_CLEAR_SCREEN_DELAY); 1163ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mActivity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 1164ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1165ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1166ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb private class WaitProcessorTask extends AsyncTask<Void, Void, Void> { 1167ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1168ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb protected Void doInBackground(Void... params) { 1169ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb synchronized (mMosaicFrameProcessor) { 1170ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb while (!isCancelled() && mMosaicFrameProcessor.isMosaicMemoryAllocated()) { 1171ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb try { 1172ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mMosaicFrameProcessor.wait(); 1173ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } catch (Exception e) { 1174ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb // ignore 1175ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1176ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1177ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1178ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return null; 1179ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1180ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1181ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1182ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb protected void onPostExecute(Void result) { 1183ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mWaitProcessorTask = null; 1184ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mRotateDialog.dismissDialog(); 1185ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb mGLRootView.setVisibility(View.VISIBLE); 1186ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb initMosaicFrameProcessorIfNeeded(); 1187ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int w = mPreviewArea.getWidth(); 1188ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb int h = mPreviewArea.getHeight(); 1189ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb if (w != 0 && h != 0) { // The layout has been calculated. 1190ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb configMosaicPreview(w, h); 1191ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1192ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb resetToPreview(); 1193ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1194ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1195ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1196ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1197ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onFullScreenChanged(boolean full) { 1198ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1199ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1200ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1201ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1202ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onStop() { 1203ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1204ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1205ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1206ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void installIntentFilter() { 1207ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1208ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1209ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1210ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onActivityResult(int requestCode, int resultCode, Intent data) { 1211ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1212ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1213ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1214ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1215ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public boolean onKeyDown(int keyCode, KeyEvent event) { 1216ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return false; 1217ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1218ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1219ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1220ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public boolean onKeyUp(int keyCode, KeyEvent event) { 1221ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return false; 1222ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1223ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1224ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1225ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onSingleTapUp(View view, int x, int y) { 1226ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1227ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1228ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1229ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void onPreviewTextureCopied() { 1230ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1231ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1232ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1233d282a28c60ca8f4ee82d519b12e8b0b057b294d4George Mount public void onCaptureTextureCopied() { 1234d282a28c60ca8f4ee82d519b12e8b0b057b294d4George Mount } 1235d282a28c60ca8f4ee82d519b12e8b0b057b294d4George Mount 1236d282a28c60ca8f4ee82d519b12e8b0b057b294d4George Mount @Override 1237ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public boolean updateStorageHintOnResume() { 1238ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return false; 1239ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1240ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1241ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1242ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public void updateCameraAppView() { 1243ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 1244ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb 1245ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb @Override 1246ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb public boolean collapseCameraControls() { 1247ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb return false; 1248ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb } 124990ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb 125090ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb @Override 125190ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb public boolean needsSwitcher() { 125290ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb return true; 125390ef46f0248437fbcb2c80c8a65239f4da32b039Michael Kolb } 1254561af39348f34db4d67bc954536d6f6cbf296054John Reck 1255561af39348f34db4d67bc954536d6f6cbf296054John Reck @Override 1256561af39348f34db4d67bc954536d6f6cbf296054John Reck public void onShowSwitcherPopup() { 1257561af39348f34db4d67bc954536d6f6cbf296054John Reck } 1258ce1d8396924bf4ca9be076cfdf9594c4d33ebd9bMichael Kolb} 1259