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