PanoramaActivity.java revision fbc5751416caa3a0d065ae15f56d1fb0253552c5
1bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen/* 2bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Copyright (C) 2011 The Android Open Source Project 3bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * 4bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Licensed under the Apache License, Version 2.0 (the "License"); 5bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * you may not use this file except in compliance with the License. 6bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * You may obtain a copy of the License at 7bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * 8bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * http://www.apache.org/licenses/LICENSE-2.0 9bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * 10bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * Unless required by applicable law or agreed to in writing, software 11bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * distributed under the License is distributed on an "AS IS" BASIS, 12bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * See the License for the specific language governing permissions and 14bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen * limitations under the License. 15bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen */ 16bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 17bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenpackage com.android.camera.panorama; 18bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 19d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraDisabledException; 20d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraHardwareException; 21d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.CameraHolder; 22d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.MenuHelper; 23d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.ModePicker; 24d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.R; 25d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Storage; 26d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Liimport com.android.camera.Util; 27d1cff41cd8ae0fc6e9df1050730bb5e47bd364afWu-cheng Li 28bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.app.Activity; 29bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.content.Context; 30142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.Bitmap; 31142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kongimport android.graphics.BitmapFactory; 328a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.ImageFormat; 33bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.graphics.PixelFormat; 348a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.Rect; 3541a2e9735136f372de95652d0828600282c8e967mbansalimport android.graphics.SurfaceTexture; 368a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.graphics.YuvImage; 378a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.hardware.Camera; 3836839102e03107e3fb121197036365a58ec2686eAngus Kongimport android.hardware.Camera.Parameters; 3936839102e03107e3fb121197036365a58ec2686eAngus Kongimport android.hardware.Camera.Size; 40bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.Sensor; 41bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorEvent; 42bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorEventListener; 43bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.hardware.SensorManager; 44bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.os.Bundle; 458a2c41754655a3733175fce81fb7506ff7022959Angus Kongimport android.os.Handler; 46ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport android.os.Message; 47bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.util.Log; 48bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.View; 49bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.view.WindowManager; 5060fc534ec8f68d95a486984cb396a2da0e200518Angus Kongimport android.widget.Button; 51bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport android.widget.ImageView; 52fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kongimport android.widget.TextView; 53bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 54ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport java.io.ByteArrayOutputStream; 55bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport java.util.List; 56bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 57a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong/** 58a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong * Activity to handle panorama capturing. 59a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong */ 6098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chenpublic class PanoramaActivity extends Activity implements 6141a2e9735136f372de95652d0828600282c8e967mbansal ModePicker.OnModeChangeListener, 6236839102e03107e3fb121197036365a58ec2686eAngus Kong SurfaceTexture.OnFrameAvailableListener, 6336839102e03107e3fb121197036365a58ec2686eAngus Kong MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener { 64ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong public static final int DEFAULT_SWEEP_ANGLE = 160; 65bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; 66bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; 67bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 68ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private static final int MSG_FINAL_MOSAIC_READY = 1; 69142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private static final int MSG_RESET_TO_PREVIEW = 2; 7094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 71ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private static final String TAG = "PanoramaActivity"; 7298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private static final int PREVIEW_STOPPED = 0; 7398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private static final int PREVIEW_ACTIVE = 1; 7441a2e9735136f372de95652d0828600282c8e967mbansal private static final int CAPTURE_VIEWFINDER = 0; 7541a2e9735136f372de95652d0828600282c8e967mbansal private static final int CAPTURE_MOSAIC = 1; 7641a2e9735136f372de95652d0828600282c8e967mbansal 77a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong // Ratio of nanosecond to second 78a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private static final float NS2S = 1.0f / 1000000000.0f; 79142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 80142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private boolean mPausing; 81142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 82a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private View mPanoControlLayout; 83a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private View mCaptureLayout; 8460fc534ec8f68d95a486984cb396a2da0e200518Angus Kong private Button mStopCaptureButton; 85a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private View mReviewLayout; 86bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private ImageView mReview; 87bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private CaptureView mCaptureView; 88eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal private MosaicRendererSurfaceView mRealTimeMosaicView; 89fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong private TextView mTooFastPrompt; 90142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 91bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private int mPreviewWidth; 92bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private int mPreviewHeight; 938a2c41754655a3733175fce81fb7506ff7022959Angus Kong private Camera mCameraDevice; 9498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private int mCameraState; 9541a2e9735136f372de95652d0828600282c8e967mbansal private int mCaptureState; 96bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private SensorManager mSensorManager; 97bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private Sensor mSensor; 98a72d73cbac59db43d413291e4db66763be08143arepo sync private ModePicker mModePicker; 998a2c41754655a3733175fce81fb7506ff7022959Angus Kong private MosaicFrameProcessor mMosaicFrameProcessor; 1008a2c41754655a3733175fce81fb7506ff7022959Angus Kong private String mCurrentImagePath = null; 1018a2c41754655a3733175fce81fb7506ff7022959Angus Kong private long mTimeTaken; 102ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private Handler mMainHandler; 10341a2e9735136f372de95652d0828600282c8e967mbansal private SurfaceTexture mSurface; 104142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private boolean mThreadRunning; 105142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 106bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 107bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onCreate(Bundle icicle) { 108bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen super.onCreate(icicle); 109bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 110bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, 111bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 112bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 113bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen createContentView(); 114bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 115bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 116bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 117bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (mSensor == null) { 118bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); 119bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 1208a2c41754655a3733175fce81fb7506ff7022959Angus Kong 121ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong mMainHandler = new Handler() { 122ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong @Override 123ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong public void handleMessage(Message msg) { 124ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong switch (msg.what) { 125ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong case MSG_FINAL_MOSAIC_READY: 126142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mThreadRunning = false; 127142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong showFinalMosaic((Bitmap) msg.obj); 128142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong break; 129142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong case MSG_RESET_TO_PREVIEW: 130142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mThreadRunning = false; 131142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong resetToPreview(); 132142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong break; 133ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 134142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong clearMosaicFrameProcessorIfNeeded(); 135ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 136ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong }; 137bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 138bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 139bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void setupCamera() { 140bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen openCamera(); 141bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Parameters parameters = mCameraDevice.getParameters(); 142bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen setupCaptureParams(parameters); 143bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen configureCamera(parameters); 144bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 145bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 146ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private void releaseCamera() { 147ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong if (mCameraDevice != null) { 148142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mCameraDevice.setPreviewCallbackWithBuffer(null); 149ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong CameraHolder.instance().release(); 150ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong mCameraDevice = null; 15198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_STOPPED; 152ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 153ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 154ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong 155bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void openCamera() { 156bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen try { 157bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId()); 158bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } catch (CameraHardwareException e) { 159bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Util.showErrorAndFinish(this, R.string.cannot_connect_camera); 160bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return; 161bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } catch (CameraDisabledException e) { 162bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Util.showErrorAndFinish(this, R.string.camera_disabled); 163bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return; 164bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 165bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 166bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 167bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, 168bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen boolean needSmaller) { 169bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int pixelsDiff = DEFAULT_CAPTURE_PIXELS; 170bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen boolean hasFound = false; 1718a2c41754655a3733175fce81fb7506ff7022959Angus Kong for (Size size : supportedSizes) { 172bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int h = size.height; 173bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int w = size.width; 174bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen // we only want 4:3 format. 175bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int d = DEFAULT_CAPTURE_PIXELS - h * w; 17694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen if (needSmaller && d < 0) { // no bigger preview than 960x720. 177bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen continue; 178bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 179bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (need4To3 && (h * 4 != w * 3)) { 180bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen continue; 181bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 182bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen d = Math.abs(d); 183bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (d < pixelsDiff) { 184bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mPreviewWidth = w; 185bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mPreviewHeight = h; 186bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen pixelsDiff = d; 187bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen hasFound = true; 188bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 189bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 190bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return hasFound; 191bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 192bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 193bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void setupCaptureParams(Parameters parameters) { 194bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); 195bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (!findBestPreviewSize(supportedSizes, true, true)) { 196bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.w(TAG, "No 4:3 ratio preview size supported."); 197bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (!findBestPreviewSize(supportedSizes, false, true)) { 198bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); 199bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen findBestPreviewSize(supportedSizes, false, false); 200bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 201bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 202bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth); 203bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen parameters.setPreviewSize(mPreviewWidth, mPreviewHeight); 204bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 205bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen List<int[]> frameRates = parameters.getSupportedPreviewFpsRange(); 206bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int last = frameRates.size() - 1; 207bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX]; 208bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX]; 209bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen parameters.setPreviewFpsRange(minFps, maxFps); 210bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.v(TAG, "preview fps: " + minFps + ", " + maxFps); 2113ab4f0912da83f7f5f8266a57a606d521c1649e3Wu-cheng Li 21293ad273a53e7d2975a67d7d1f8a157f845e41cf2Wu-cheng Li parameters.setRecordingHint(false); 213bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 214bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 215bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public int getPreviewBufSize() { 216bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen PixelFormat pixelInfo = new PixelFormat(); 217bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo); 218bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen // TODO: remove this extra 32 byte after the driver bug is fixed. 219bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32; 220bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 221bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 222bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void configureCamera(Parameters parameters) { 223bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCameraDevice.setParameters(parameters); 224bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 2254b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li int orientation = Util.getDisplayOrientation(Util.getDisplayRotation(this), 2264b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li CameraHolder.instance().getBackCameraId()); 2274b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li mCameraDevice.setDisplayOrientation(orientation); 228bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 229bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 230a72d73cbac59db43d413291e4db66763be08143arepo sync private boolean switchToOtherMode(int mode) { 231a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong if (isFinishing()) { 23294f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen return false; 233a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong } 234a72d73cbac59db43d413291e4db66763be08143arepo sync MenuHelper.gotoMode(mode, this); 235a72d73cbac59db43d413291e4db66763be08143arepo sync finish(); 236a72d73cbac59db43d413291e4db66763be08143arepo sync return true; 237a72d73cbac59db43d413291e4db66763be08143arepo sync } 238a72d73cbac59db43d413291e4db66763be08143arepo sync 239a72d73cbac59db43d413291e4db66763be08143arepo sync public boolean onModeChanged(int mode) { 240a72d73cbac59db43d413291e4db66763be08143arepo sync if (mode != ModePicker.MODE_PANORAMA) { 241a72d73cbac59db43d413291e4db66763be08143arepo sync return switchToOtherMode(mode); 242a72d73cbac59db43d413291e4db66763be08143arepo sync } else { 243a72d73cbac59db43d413291e4db66763be08143arepo sync return true; 244a72d73cbac59db43d413291e4db66763be08143arepo sync } 245a72d73cbac59db43d413291e4db66763be08143arepo sync } 246a72d73cbac59db43d413291e4db66763be08143arepo sync 24736839102e03107e3fb121197036365a58ec2686eAngus Kong public void onMosaicSurfaceCreated(final SurfaceTexture surface) { 24836839102e03107e3fb121197036365a58ec2686eAngus Kong runOnUiThread(new Runnable() { 24936839102e03107e3fb121197036365a58ec2686eAngus Kong @Override 25036839102e03107e3fb121197036365a58ec2686eAngus Kong public void run() { 25136839102e03107e3fb121197036365a58ec2686eAngus Kong mSurface = surface; 25236839102e03107e3fb121197036365a58ec2686eAngus Kong mSurface.setOnFrameAvailableListener(PanoramaActivity.this); 25336839102e03107e3fb121197036365a58ec2686eAngus Kong startCameraPreview(); 25436839102e03107e3fb121197036365a58ec2686eAngus Kong } 25536839102e03107e3fb121197036365a58ec2686eAngus Kong }); 25636839102e03107e3fb121197036365a58ec2686eAngus Kong } 25736839102e03107e3fb121197036365a58ec2686eAngus Kong 25841a2e9735136f372de95652d0828600282c8e967mbansal public void runViewFinder() { 25941a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setWarping(false); 26041a2e9735136f372de95652d0828600282c8e967mbansal 26141a2e9735136f372de95652d0828600282c8e967mbansal // First update the surface texture... 26241a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.updateSurfaceTexture(); 26341a2e9735136f372de95652d0828600282c8e967mbansal // ...then call preprocess to render it to low-res and high-res RGB textures 26441a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.preprocess(); 26541a2e9735136f372de95652d0828600282c8e967mbansal 26641a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setReady(); 26741a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.requestRender(); 26841a2e9735136f372de95652d0828600282c8e967mbansal } 26941a2e9735136f372de95652d0828600282c8e967mbansal 27041a2e9735136f372de95652d0828600282c8e967mbansal public void runMosaicCapture() { 27141a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setWarping(true); 27241a2e9735136f372de95652d0828600282c8e967mbansal 27341a2e9735136f372de95652d0828600282c8e967mbansal // Lock the condition variable 27441a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.lockPreviewReadyFlag(); 27541a2e9735136f372de95652d0828600282c8e967mbansal // First update the surface texture... 27641a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.updateSurfaceTexture(); 27741a2e9735136f372de95652d0828600282c8e967mbansal // ...then call preprocess to render it to low-res and high-res RGB textures 27841a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.preprocess(); 27941a2e9735136f372de95652d0828600282c8e967mbansal // Now, transfer the textures from GPU to CPU memory for processing 28041a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.transferGPUtoCPU(); 28141a2e9735136f372de95652d0828600282c8e967mbansal // Wait on the condition variable (will be opened when GPU->CPU transfer is done). 28241a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.waitUntilPreviewReady(); 28341a2e9735136f372de95652d0828600282c8e967mbansal 2840adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mMosaicFrameProcessor.processFrame(); 28541a2e9735136f372de95652d0828600282c8e967mbansal } 28641a2e9735136f372de95652d0828600282c8e967mbansal 287739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong public synchronized void onFrameAvailable(SurfaceTexture surface) { 28841a2e9735136f372de95652d0828600282c8e967mbansal /* For simplicity, SurfaceTexture calls here when it has new 28941a2e9735136f372de95652d0828600282c8e967mbansal * data available. Call may come in from some random thread, 29041a2e9735136f372de95652d0828600282c8e967mbansal * so let's be safe and use synchronize. No OpenGL calls can be done here. 29141a2e9735136f372de95652d0828600282c8e967mbansal */ 29241a2e9735136f372de95652d0828600282c8e967mbansal if (mCaptureState == CAPTURE_VIEWFINDER) { 29341a2e9735136f372de95652d0828600282c8e967mbansal runViewFinder(); 29441a2e9735136f372de95652d0828600282c8e967mbansal } else { 29541a2e9735136f372de95652d0828600282c8e967mbansal runMosaicCapture(); 29641a2e9735136f372de95652d0828600282c8e967mbansal } 29741a2e9735136f372de95652d0828600282c8e967mbansal } 29841a2e9735136f372de95652d0828600282c8e967mbansal 299a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong public void startCapture() { 3008a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Reset values so we can do this again. 3018a2c41754655a3733175fce81fb7506ff7022959Angus Kong mTimeTaken = System.currentTimeMillis(); 30241a2e9735136f372de95652d0828600282c8e967mbansal mCaptureState = CAPTURE_MOSAIC; 303fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong mTooFastPrompt.setVisibility(View.GONE); 3048a2c41754655a3733175fce81fb7506ff7022959Angus Kong 3058a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() { 3068a2c41754655a3733175fce81fb7506ff7022959Angus Kong @Override 3078a2c41754655a3733175fce81fb7506ff7022959Angus Kong public void onProgress(boolean isFinished, float translationRate, int traversedAngleX, 308d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen int traversedAngleY) { 3098a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (isFinished) { 310a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong stopCapture(); 3118a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 312d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen updateProgress(translationRate, traversedAngleX, traversedAngleY); 3138a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3148a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3158a2c41754655a3733175fce81fb7506ff7022959Angus Kong }); 3168a2c41754655a3733175fce81fb7506ff7022959Angus Kong 31760fc534ec8f68d95a486984cb396a2da0e200518Angus Kong mStopCaptureButton.setVisibility(View.VISIBLE); 3185af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mCaptureView.setVisibility(View.VISIBLE); 319f921d46b1e1c9b4a8f1b017ce26675fd9accd609Wei-Ta Chen mRealTimeMosaicView.setVisibility(View.VISIBLE); 320a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong mPanoControlLayout.setVisibility(View.GONE); 32141a2e9735136f372de95652d0828600282c8e967mbansal 3228a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3238a2c41754655a3733175fce81fb7506ff7022959Angus Kong 324a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private void stopCapture() { 32541a2e9735136f372de95652d0828600282c8e967mbansal mCaptureState = CAPTURE_VIEWFINDER; 32641a2e9735136f372de95652d0828600282c8e967mbansal 3278a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.setProgressListener(null); 32836839102e03107e3fb121197036365a58ec2686eAngus Kong stopCameraPreview(); 32941a2e9735136f372de95652d0828600282c8e967mbansal 33041a2e9735136f372de95652d0828600282c8e967mbansal mSurface.setOnFrameAvailableListener(null); 33141a2e9735136f372de95652d0828600282c8e967mbansal 332ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong // TODO: show some dialog for long computation. 333142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (!mThreadRunning) { 334142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mThreadRunning = true; 335142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong Thread t = new Thread() { 336142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @Override 337142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void run() { 338ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong byte[] jpegData = generateFinalMosaic(false); 339ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Bitmap bitmap = null; 340ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong if (jpegData != null) { 341ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length); 342ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } 343ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mMainHandler.sendMessage(mMainHandler.obtainMessage( 344ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong MSG_FINAL_MOSAIC_READY, bitmap)); 345142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 346142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong }; 347142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong t.start(); 348142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 3498a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3508a2c41754655a3733175fce81fb7506ff7022959Angus Kong 351d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen private void updateProgress(float translationRate, int traversedAngleX, int traversedAngleY) { 352eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal 353eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView.setReady(); 354eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView.requestRender(); 355eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal 3568a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (translationRate > 150) { 357fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong // TODO: draw speed indication according to the UI spec. 358fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong mTooFastPrompt.setVisibility(View.VISIBLE); 35994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1); 3608a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCaptureView.invalidate(); 3618a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 362fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong mTooFastPrompt.setVisibility(View.GONE); 36394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1); 3648a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCaptureView.invalidate(); 3658a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3668a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3678a2c41754655a3733175fce81fb7506ff7022959Angus Kong 368bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void createContentView() { 369bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen setContentView(R.layout.panorama); 370bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 37141a2e9735136f372de95652d0828600282c8e967mbansal mCaptureState = CAPTURE_VIEWFINDER; 37241a2e9735136f372de95652d0828600282c8e967mbansal 373a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong mCaptureLayout = (View) findViewById(R.id.pano_capture_layout); 3745af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mRealTimeMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer); 3755af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mRealTimeMosaicView.getRenderer().setMosaicSurfaceCreateListener(this); 376bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCaptureView = (CaptureView) findViewById(R.id.pano_capture_view); 377bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCaptureView.setStartAngle(-DEFAULT_SWEEP_ANGLE / 2); 3785af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mStopCaptureButton = (Button) findViewById(R.id.pano_capture_stop_button); 379fbc5751416caa3a0d065ae15f56d1fb0253552c5Angus Kong mTooFastPrompt = (TextView) findViewById(R.id.pano_capture_too_fast_textview); 380bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 3815af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mReviewLayout = (View) findViewById(R.id.pano_review_layout); 3825af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mReview = (ImageView) findViewById(R.id.pano_reviewarea); 383eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal 384a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong mPanoControlLayout = (View) findViewById(R.id.pano_control_layout); 385a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker = (ModePicker) findViewById(R.id.mode_picker); 386a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setVisibility(View.VISIBLE); 387a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setOnModeChangeListener(this); 388a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA); 389bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 390bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 391142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @OnClickAttr 392739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong public void onStartButtonClicked(View v) { 39336839102e03107e3fb121197036365a58ec2686eAngus Kong // If mSurface == null then GL setup is not finished yet. All buttons cannot be pressed. 39436839102e03107e3fb121197036365a58ec2686eAngus Kong if (mPausing || mThreadRunning || mSurface == null) return; 395739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong startCapture(); 396739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong } 397739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong 398739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong @OnClickAttr 399142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void onStopButtonClicked(View v) { 40036839102e03107e3fb121197036365a58ec2686eAngus Kong if (mPausing || mThreadRunning || mSurface == null) return; 401142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong stopCapture(); 402142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 403142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 404142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @OnClickAttr 405142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void onOkButtonClicked(View v) { 40636839102e03107e3fb121197036365a58ec2686eAngus Kong if (mPausing || mThreadRunning || mSurface == null) return; 407142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mThreadRunning = true; 408142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong Thread t = new Thread() { 409142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @Override 410142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void run() { 411ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong byte[] jpegData = generateFinalMosaic(true); 412ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong savePanorama(jpegData); 413ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mMainHandler.sendMessage(mMainHandler.obtainMessage(MSG_RESET_TO_PREVIEW)); 414142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 415142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong }; 416142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong t.start(); 417142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 418142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 419142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @OnClickAttr 420142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void onRetakeButtonClicked(View v) { 421142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (mPausing || mThreadRunning) return; 422142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong resetToPreview(); 423142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 424142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 425142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void resetToPreview() { 42641a2e9735136f372de95652d0828600282c8e967mbansal mCaptureState = CAPTURE_VIEWFINDER; 42741a2e9735136f372de95652d0828600282c8e967mbansal 42841a2e9735136f372de95652d0828600282c8e967mbansal mReviewLayout.setVisibility(View.GONE); 42960fc534ec8f68d95a486984cb396a2da0e200518Angus Kong mStopCaptureButton.setVisibility(View.GONE); 4305af9472f1c260c1a3b54d2e1bd448c27b5e5968fWei-Ta Chen mCaptureView.setVisibility(View.GONE); 431142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mPanoControlLayout.setVisibility(View.VISIBLE); 43260fc534ec8f68d95a486984cb396a2da0e200518Angus Kong mCaptureLayout.setVisibility(View.VISIBLE); 433142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.reset(); 43441a2e9735136f372de95652d0828600282c8e967mbansal 43541a2e9735136f372de95652d0828600282c8e967mbansal mSurface.setOnFrameAvailableListener(this); 43641a2e9735136f372de95652d0828600282c8e967mbansal 43736839102e03107e3fb121197036365a58ec2686eAngus Kong if (!mPausing) startCameraPreview(); 43841a2e9735136f372de95652d0828600282c8e967mbansal 43941a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setVisibility(View.VISIBLE); 440142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 441142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 442142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void showFinalMosaic(Bitmap bitmap) { 443142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (bitmap != null) { 444142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mReview.setImageBitmap(bitmap); 445142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 446ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mCaptureLayout.setVisibility(View.GONE); 447ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mReviewLayout.setVisibility(View.VISIBLE); 448ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mCaptureView.setStatusText(""); 449ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mCaptureView.setSweepAngle(0); 450142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 451142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 452ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong private void savePanorama(byte[] jpegData) { 453ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong if (jpegData != null) { 454ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong String imagePath = PanoUtil.createName( 455ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong getResources().getString(R.string.pano_file_name_format), mTimeTaken); 456ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null, 0, 457ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong jpegData); 458142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 459142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 460142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 461142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void clearMosaicFrameProcessorIfNeeded() { 462142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (!mPausing || mThreadRunning) return; 463142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.clear(); 464142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 465142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 466142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void initMosaicFrameProcessorIfNeeded() { 467142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (mPausing || mThreadRunning) return; 468142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (mMosaicFrameProcessor == null) { 469142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // Start the activity for the first time. 470142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor = new MosaicFrameProcessor(DEFAULT_SWEEP_ANGLE - 5, 4710adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mPreviewWidth, mPreviewHeight, getPreviewBufSize()); 472142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 473142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.initialize(); 474bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 475bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 476bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 477bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen protected void onPause() { 478bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen super.onPause(); 47941a2e9735136f372de95652d0828600282c8e967mbansal mSurface.setOnFrameAvailableListener(null); 480bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen releaseCamera(); 481142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mPausing = true; 48241a2e9735136f372de95652d0828600282c8e967mbansal 483eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView.onPause(); 48494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mSensorManager.unregisterListener(mListener); 485142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong clearMosaicFrameProcessorIfNeeded(); 48694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen System.gc(); 487bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 488bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 489bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 490bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen protected void onResume() { 491bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen super.onResume(); 492bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 493142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mPausing = false; 494bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen /* 49594f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * It is not necessary to get accelerometer events at a very high rate, 49694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * by using a slower rate (SENSOR_DELAY_UI), we get an automatic 49794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * low-pass filter, which "extracts" the gravity component of the 49894f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * acceleration. As an added benefit, we use less power and CPU 49994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen * resources. 500bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen */ 501bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI); 50241a2e9735136f372de95652d0828600282c8e967mbansal mCaptureState = CAPTURE_VIEWFINDER; 503bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen setupCamera(); 504142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // Camera must be initialized before MosaicFrameProcessor is initialized. The preview size 505142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // has to be decided by camera device. 506142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong initMosaicFrameProcessorIfNeeded(); 507eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView.onResume(); 508bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 509bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 510bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private final SensorEventListener mListener = new SensorEventListener() { 511bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private float mCompassCurrX; // degrees 512bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private float mCompassCurrY; // degrees 513bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private float mTimestamp; 514bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 515bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onSensorChanged(SensorEvent event) { 516bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { 517bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (mTimestamp != 0) { 518bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen final float dT = (event.timestamp - mTimestamp) * NS2S; 519bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCompassCurrX += event.values[1] * dT * 180.0f / Math.PI; 520bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCompassCurrY += event.values[0] * dT * 180.0f / Math.PI; 521bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 522bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mTimestamp = event.timestamp; 523bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 524bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { 525bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCompassCurrX = event.values[0]; 526bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCompassCurrY = event.values[1]; 527bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 528bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 5298a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mMosaicFrameProcessor != null) { 5308a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.updateCompassValue(mCompassCurrX, mCompassCurrY); 531bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 532bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 533bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 534bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 535bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onAccuracyChanged(Sensor sensor, int accuracy) { 536bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 537bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen }; 538bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 539ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong public byte[] generateFinalMosaic(boolean highRes) { 5408a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.createMosaic(highRes); 541bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 542ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21(); 543ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong if (imageData == null) { 544ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.e(TAG, "getFinalMosaicNV21() returned null."); 545ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong return null; 5468a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 5478a2c41754655a3733175fce81fb7506ff7022959Angus Kong 548ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int len = imageData.length - 8; 549ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16) 550ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF); 551ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16) 552ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF); 553ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height); 5548a2c41754655a3733175fce81fb7506ff7022959Angus Kong 555e46486104523760a4433f03e09ed615987d83b6cAngus Kong if (width <= 0 || height <= 0) { 556e46486104523760a4433f03e09ed615987d83b6cAngus Kong // TODO: pop up a error meesage indicating that the final result is not generated. 557e46486104523760a4433f03e09ed615987d83b6cAngus Kong Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " + 558e46486104523760a4433f03e09ed615987d83b6cAngus Kong height); 559e46486104523760a4433f03e09ed615987d83b6cAngus Kong return null; 560e46486104523760a4433f03e09ed615987d83b6cAngus Kong } 561e46486104523760a4433f03e09ed615987d83b6cAngus Kong 562ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null); 563ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong ByteArrayOutputStream out = new ByteArrayOutputStream(); 564ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out); 565ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong try { 566ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong out.close(); 567ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } catch (Exception e) { 568ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.e(TAG, "Exception in storing final mosaic", e); 569ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong return null; 570ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } 571ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong return out.toByteArray(); 572bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 5738a2c41754655a3733175fce81fb7506ff7022959Angus Kong 57441a2e9735136f372de95652d0828600282c8e967mbansal private void setPreviewTexture(SurfaceTexture surface) { 57598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen try { 57641a2e9735136f372de95652d0828600282c8e967mbansal mCameraDevice.setPreviewTexture(surface); 57798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } catch (Throwable ex) { 57898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen releaseCamera(); 57941a2e9735136f372de95652d0828600282c8e967mbansal throw new RuntimeException("setPreviewTexture failed", ex); 58098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 58198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 58298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 58336839102e03107e3fb121197036365a58ec2686eAngus Kong private void startCameraPreview() { 58498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen // If we're previewing already, stop the preview first (this will blank 58598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen // the screen). 58636839102e03107e3fb121197036365a58ec2686eAngus Kong if (mCameraState != PREVIEW_STOPPED) stopCameraPreview(); 58798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 58841a2e9735136f372de95652d0828600282c8e967mbansal setPreviewTexture(mSurface); 58998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 59098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen try { 59198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen Log.v(TAG, "startPreview"); 59298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraDevice.startPreview(); 59398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } catch (Throwable ex) { 59498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen releaseCamera(); 59598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen throw new RuntimeException("startPreview failed", ex); 59698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 59798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_ACTIVE; 59898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 59998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 60036839102e03107e3fb121197036365a58ec2686eAngus Kong private void stopCameraPreview() { 60198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { 60298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen Log.v(TAG, "stopPreview"); 60398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraDevice.stopPreview(); 60498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 60598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_STOPPED; 60698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 607bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen} 608