PanoramaActivity.java revision e46486104523760a4433f03e09ed615987d83b6c
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; 52bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 53ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kongimport java.io.ByteArrayOutputStream; 54bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chenimport java.util.List; 55bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 56a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong/** 57a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong * Activity to handle panorama capturing. 58a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong */ 5998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chenpublic class PanoramaActivity extends Activity implements 6041a2e9735136f372de95652d0828600282c8e967mbansal ModePicker.OnModeChangeListener, 6136839102e03107e3fb121197036365a58ec2686eAngus Kong SurfaceTexture.OnFrameAvailableListener, 6236839102e03107e3fb121197036365a58ec2686eAngus Kong MosaicRendererSurfaceViewRenderer.MosaicSurfaceCreateListener { 63ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong public static final int DEFAULT_SWEEP_ANGLE = 160; 64bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; 65bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; 66bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 67ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private static final int MSG_FINAL_MOSAIC_READY = 1; 68142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private static final int MSG_RESET_TO_PREVIEW = 2; 6994f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen 70ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private static final String TAG = "PanoramaActivity"; 7198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private static final int PREVIEW_STOPPED = 0; 7298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private static final int PREVIEW_ACTIVE = 1; 7341a2e9735136f372de95652d0828600282c8e967mbansal private static final int CAPTURE_VIEWFINDER = 0; 7441a2e9735136f372de95652d0828600282c8e967mbansal private static final int CAPTURE_MOSAIC = 1; 7541a2e9735136f372de95652d0828600282c8e967mbansal 76a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong // Ratio of nanosecond to second 77a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private static final float NS2S = 1.0f / 1000000000.0f; 78142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 79142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private boolean mPausing; 80142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 81a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private View mPanoControlLayout; 82a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private View mCaptureLayout; 8360fc534ec8f68d95a486984cb396a2da0e200518Angus Kong private Button mStopCaptureButton; 84a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private View mReviewLayout; 85bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private ImageView mReview; 86bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private CaptureView mCaptureView; 87eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal private MosaicRendererSurfaceView mRealTimeMosaicView; 88142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 89bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private int mPreviewWidth; 90bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private int mPreviewHeight; 918a2c41754655a3733175fce81fb7506ff7022959Angus Kong private Camera mCameraDevice; 9298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen private int mCameraState; 9341a2e9735136f372de95652d0828600282c8e967mbansal private int mCaptureState; 94bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private SensorManager mSensorManager; 95bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private Sensor mSensor; 96a72d73cbac59db43d413291e4db66763be08143arepo sync private ModePicker mModePicker; 978a2c41754655a3733175fce81fb7506ff7022959Angus Kong private MosaicFrameProcessor mMosaicFrameProcessor; 988a2c41754655a3733175fce81fb7506ff7022959Angus Kong private String mCurrentImagePath = null; 998a2c41754655a3733175fce81fb7506ff7022959Angus Kong private long mTimeTaken; 100ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private Handler mMainHandler; 10141a2e9735136f372de95652d0828600282c8e967mbansal private SurfaceTexture mSurface; 102142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private boolean mThreadRunning; 103142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 104bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 105bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onCreate(Bundle icicle) { 106bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen super.onCreate(icicle); 107bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 108bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, 109bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 110bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 111bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen createContentView(); 112bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 113bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); 114bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); 115bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (mSensor == null) { 116bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); 117bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 1188a2c41754655a3733175fce81fb7506ff7022959Angus Kong 119ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong mMainHandler = new Handler() { 120ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong @Override 121ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong public void handleMessage(Message msg) { 122ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong switch (msg.what) { 123ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong case MSG_FINAL_MOSAIC_READY: 124142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mThreadRunning = false; 125142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong showFinalMosaic((Bitmap) msg.obj); 126142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong break; 127142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong case MSG_RESET_TO_PREVIEW: 128142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mThreadRunning = false; 129142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong resetToPreview(); 130142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong break; 131ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 132142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong clearMosaicFrameProcessorIfNeeded(); 133ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 134ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong }; 135bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 136bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 137bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void setupCamera() { 138bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen openCamera(); 139bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Parameters parameters = mCameraDevice.getParameters(); 140bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen setupCaptureParams(parameters); 141bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen configureCamera(parameters); 142bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 143bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 144ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong private void releaseCamera() { 145ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong if (mCameraDevice != null) { 146142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mCameraDevice.setPreviewCallbackWithBuffer(null); 147ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong CameraHolder.instance().release(); 148ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong mCameraDevice = null; 14998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_STOPPED; 150ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 151ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong } 152ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong 153bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void openCamera() { 154bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen try { 155bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId()); 156bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } catch (CameraHardwareException e) { 157bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Util.showErrorAndFinish(this, R.string.cannot_connect_camera); 158bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return; 159bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } catch (CameraDisabledException e) { 160bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Util.showErrorAndFinish(this, R.string.camera_disabled); 161bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return; 162bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 163bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 164bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 165bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, 166bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen boolean needSmaller) { 167bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int pixelsDiff = DEFAULT_CAPTURE_PIXELS; 168bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen boolean hasFound = false; 1698a2c41754655a3733175fce81fb7506ff7022959Angus Kong for (Size size : supportedSizes) { 170bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int h = size.height; 171bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int w = size.width; 172bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen // we only want 4:3 format. 173bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int d = DEFAULT_CAPTURE_PIXELS - h * w; 17494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen if (needSmaller && d < 0) { // no bigger preview than 960x720. 175bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen continue; 176bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 177bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (need4To3 && (h * 4 != w * 3)) { 178bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen continue; 179bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 180bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen d = Math.abs(d); 181bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (d < pixelsDiff) { 182bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mPreviewWidth = w; 183bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mPreviewHeight = h; 184bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen pixelsDiff = d; 185bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen hasFound = true; 186bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 187bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 188bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return hasFound; 189bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 190bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 191bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void setupCaptureParams(Parameters parameters) { 192bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); 193bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (!findBestPreviewSize(supportedSizes, true, true)) { 194bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.w(TAG, "No 4:3 ratio preview size supported."); 195bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (!findBestPreviewSize(supportedSizes, false, true)) { 196bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); 197bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen findBestPreviewSize(supportedSizes, false, false); 198bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 199bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 200bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth); 201bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen parameters.setPreviewSize(mPreviewWidth, mPreviewHeight); 202bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 203bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen List<int[]> frameRates = parameters.getSupportedPreviewFpsRange(); 204bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int last = frameRates.size() - 1; 205bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX]; 206bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX]; 207bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen parameters.setPreviewFpsRange(minFps, maxFps); 208bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen Log.v(TAG, "preview fps: " + minFps + ", " + maxFps); 2093ab4f0912da83f7f5f8266a57a606d521c1649e3Wu-cheng Li 21093ad273a53e7d2975a67d7d1f8a157f845e41cf2Wu-cheng Li parameters.setRecordingHint(false); 211bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 212bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 213bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public int getPreviewBufSize() { 214bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen PixelFormat pixelInfo = new PixelFormat(); 215bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo); 216bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen // TODO: remove this extra 32 byte after the driver bug is fixed. 217bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32; 218bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 219bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 220bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void configureCamera(Parameters parameters) { 221bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCameraDevice.setParameters(parameters); 222bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 2234b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li int orientation = Util.getDisplayOrientation(Util.getDisplayRotation(this), 2244b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li CameraHolder.instance().getBackCameraId()); 2254b602592e0d189499b22d107d997b83e798b5bd9Wu-cheng Li mCameraDevice.setDisplayOrientation(orientation); 226bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 227bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 228a72d73cbac59db43d413291e4db66763be08143arepo sync private boolean switchToOtherMode(int mode) { 229a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong if (isFinishing()) { 23094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen return false; 231a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong } 232a72d73cbac59db43d413291e4db66763be08143arepo sync MenuHelper.gotoMode(mode, this); 233a72d73cbac59db43d413291e4db66763be08143arepo sync finish(); 234a72d73cbac59db43d413291e4db66763be08143arepo sync return true; 235a72d73cbac59db43d413291e4db66763be08143arepo sync } 236a72d73cbac59db43d413291e4db66763be08143arepo sync 237a72d73cbac59db43d413291e4db66763be08143arepo sync public boolean onModeChanged(int mode) { 238a72d73cbac59db43d413291e4db66763be08143arepo sync if (mode != ModePicker.MODE_PANORAMA) { 239a72d73cbac59db43d413291e4db66763be08143arepo sync return switchToOtherMode(mode); 240a72d73cbac59db43d413291e4db66763be08143arepo sync } else { 241a72d73cbac59db43d413291e4db66763be08143arepo sync return true; 242a72d73cbac59db43d413291e4db66763be08143arepo sync } 243a72d73cbac59db43d413291e4db66763be08143arepo sync } 244a72d73cbac59db43d413291e4db66763be08143arepo sync 24536839102e03107e3fb121197036365a58ec2686eAngus Kong public void onMosaicSurfaceCreated(final SurfaceTexture surface) { 24636839102e03107e3fb121197036365a58ec2686eAngus Kong runOnUiThread(new Runnable() { 24736839102e03107e3fb121197036365a58ec2686eAngus Kong @Override 24836839102e03107e3fb121197036365a58ec2686eAngus Kong public void run() { 24936839102e03107e3fb121197036365a58ec2686eAngus Kong mSurface = surface; 25036839102e03107e3fb121197036365a58ec2686eAngus Kong mSurface.setOnFrameAvailableListener(PanoramaActivity.this); 25136839102e03107e3fb121197036365a58ec2686eAngus Kong startCameraPreview(); 25236839102e03107e3fb121197036365a58ec2686eAngus Kong } 25336839102e03107e3fb121197036365a58ec2686eAngus Kong }); 25436839102e03107e3fb121197036365a58ec2686eAngus Kong } 25536839102e03107e3fb121197036365a58ec2686eAngus Kong 25641a2e9735136f372de95652d0828600282c8e967mbansal public void runViewFinder() { 25741a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setWarping(false); 25841a2e9735136f372de95652d0828600282c8e967mbansal 25941a2e9735136f372de95652d0828600282c8e967mbansal // First update the surface texture... 26041a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.updateSurfaceTexture(); 26141a2e9735136f372de95652d0828600282c8e967mbansal // ...then call preprocess to render it to low-res and high-res RGB textures 26241a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.preprocess(); 26341a2e9735136f372de95652d0828600282c8e967mbansal 26441a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setReady(); 26541a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.requestRender(); 26641a2e9735136f372de95652d0828600282c8e967mbansal } 26741a2e9735136f372de95652d0828600282c8e967mbansal 26841a2e9735136f372de95652d0828600282c8e967mbansal public void runMosaicCapture() { 26941a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setWarping(true); 27041a2e9735136f372de95652d0828600282c8e967mbansal 27141a2e9735136f372de95652d0828600282c8e967mbansal // Lock the condition variable 27241a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.lockPreviewReadyFlag(); 27341a2e9735136f372de95652d0828600282c8e967mbansal // First update the surface texture... 27441a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.updateSurfaceTexture(); 27541a2e9735136f372de95652d0828600282c8e967mbansal // ...then call preprocess to render it to low-res and high-res RGB textures 27641a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.preprocess(); 27741a2e9735136f372de95652d0828600282c8e967mbansal // Now, transfer the textures from GPU to CPU memory for processing 27841a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.transferGPUtoCPU(); 27941a2e9735136f372de95652d0828600282c8e967mbansal // Wait on the condition variable (will be opened when GPU->CPU transfer is done). 28041a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.waitUntilPreviewReady(); 28141a2e9735136f372de95652d0828600282c8e967mbansal 2820adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mMosaicFrameProcessor.processFrame(); 28341a2e9735136f372de95652d0828600282c8e967mbansal } 28441a2e9735136f372de95652d0828600282c8e967mbansal 285739f9e1541c30735e45d5cb90255dd36a32d3604Angus Kong public synchronized void onFrameAvailable(SurfaceTexture surface) { 28641a2e9735136f372de95652d0828600282c8e967mbansal /* For simplicity, SurfaceTexture calls here when it has new 28741a2e9735136f372de95652d0828600282c8e967mbansal * data available. Call may come in from some random thread, 28841a2e9735136f372de95652d0828600282c8e967mbansal * so let's be safe and use synchronize. No OpenGL calls can be done here. 28941a2e9735136f372de95652d0828600282c8e967mbansal */ 29041a2e9735136f372de95652d0828600282c8e967mbansal if (mCaptureState == CAPTURE_VIEWFINDER) { 29141a2e9735136f372de95652d0828600282c8e967mbansal runViewFinder(); 29241a2e9735136f372de95652d0828600282c8e967mbansal } else { 29341a2e9735136f372de95652d0828600282c8e967mbansal runMosaicCapture(); 29441a2e9735136f372de95652d0828600282c8e967mbansal } 29541a2e9735136f372de95652d0828600282c8e967mbansal } 29641a2e9735136f372de95652d0828600282c8e967mbansal 297a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong public void startCapture() { 2988a2c41754655a3733175fce81fb7506ff7022959Angus Kong // Reset values so we can do this again. 2998a2c41754655a3733175fce81fb7506ff7022959Angus Kong mTimeTaken = System.currentTimeMillis(); 30041a2e9735136f372de95652d0828600282c8e967mbansal mCaptureState = CAPTURE_MOSAIC; 3018a2c41754655a3733175fce81fb7506ff7022959Angus Kong 3028a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.setProgressListener(new MosaicFrameProcessor.ProgressListener() { 3038a2c41754655a3733175fce81fb7506ff7022959Angus Kong @Override 3048a2c41754655a3733175fce81fb7506ff7022959Angus Kong public void onProgress(boolean isFinished, float translationRate, int traversedAngleX, 305d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen int traversedAngleY) { 3068a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (isFinished) { 307a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong stopCapture(); 3088a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 309d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen updateProgress(translationRate, traversedAngleX, traversedAngleY); 3108a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3118a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3128a2c41754655a3733175fce81fb7506ff7022959Angus Kong }); 3138a2c41754655a3733175fce81fb7506ff7022959Angus Kong 31460fc534ec8f68d95a486984cb396a2da0e200518Angus Kong mStopCaptureButton.setVisibility(View.VISIBLE); 315f921d46b1e1c9b4a8f1b017ce26675fd9accd609Wei-Ta Chen mRealTimeMosaicView.setVisibility(View.VISIBLE); 316a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong mPanoControlLayout.setVisibility(View.GONE); 31741a2e9735136f372de95652d0828600282c8e967mbansal 3188a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3198a2c41754655a3733175fce81fb7506ff7022959Angus Kong 320a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong private void stopCapture() { 32141a2e9735136f372de95652d0828600282c8e967mbansal mCaptureState = CAPTURE_VIEWFINDER; 32241a2e9735136f372de95652d0828600282c8e967mbansal 3238a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.setProgressListener(null); 32436839102e03107e3fb121197036365a58ec2686eAngus Kong stopCameraPreview(); 32541a2e9735136f372de95652d0828600282c8e967mbansal 32641a2e9735136f372de95652d0828600282c8e967mbansal mSurface.setOnFrameAvailableListener(null); 32741a2e9735136f372de95652d0828600282c8e967mbansal 328ac86e91982dbb64eac089aa8ccf23bddb51f27f1Angus Kong // TODO: show some dialog for long computation. 329142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (!mThreadRunning) { 330142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mThreadRunning = true; 331142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong Thread t = new Thread() { 332142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong @Override 333142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong public void run() { 334ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong byte[] jpegData = generateFinalMosaic(false); 335ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Bitmap bitmap = null; 336ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong if (jpegData != null) { 337ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong bitmap = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length); 338ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } 339ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mMainHandler.sendMessage(mMainHandler.obtainMessage( 340ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong MSG_FINAL_MOSAIC_READY, bitmap)); 341142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 342142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong }; 343142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong t.start(); 344142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 3458a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3468a2c41754655a3733175fce81fb7506ff7022959Angus Kong 347d690626cc82e43eb3fadde968ea15a10e40590bfWei-Ta Chen private void updateProgress(float translationRate, int traversedAngleX, int traversedAngleY) { 348eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal 349eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView.setReady(); 350eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView.requestRender(); 351eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal 3528a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (translationRate > 150) { 35394f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen // TODO: remove the text and draw implications according to the UI 35494f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen // spec. 3558a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCaptureView.setStatusText("S L O W D O W N"); 35694f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1); 3578a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCaptureView.invalidate(); 3588a2c41754655a3733175fce81fb7506ff7022959Angus Kong } else { 3598a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCaptureView.setStatusText(""); 36094f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mCaptureView.setSweepAngle(Math.max(traversedAngleX, traversedAngleY) + 1); 3618a2c41754655a3733175fce81fb7506ff7022959Angus Kong mCaptureView.invalidate(); 3628a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3638a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 3648a2c41754655a3733175fce81fb7506ff7022959Angus Kong 365bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private void createContentView() { 366bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen setContentView(R.layout.panorama); 367bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 36841a2e9735136f372de95652d0828600282c8e967mbansal mCaptureState = CAPTURE_VIEWFINDER; 36941a2e9735136f372de95652d0828600282c8e967mbansal 370a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong mCaptureLayout = (View) findViewById(R.id.pano_capture_layout); 37160fc534ec8f68d95a486984cb396a2da0e200518Angus Kong mStopCaptureButton = (Button) findViewById(R.id.pano_capture_stop_button); 372a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong mReviewLayout = (View) findViewById(R.id.pano_review_layout); 37398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 374bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCaptureView = (CaptureView) findViewById(R.id.pano_capture_view); 375bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCaptureView.setStartAngle(-DEFAULT_SWEEP_ANGLE / 2); 376bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mReview = (ImageView) findViewById(R.id.pano_reviewarea); 377bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 378eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView = (MosaicRendererSurfaceView) findViewById(R.id.pano_renderer); 37936839102e03107e3fb121197036365a58ec2686eAngus Kong mRealTimeMosaicView.getRenderer().setMosaicSurfaceCreateListener(this); 380eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal 381a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong mPanoControlLayout = (View) findViewById(R.id.pano_control_layout); 382a955261dd734524eb7d8e1af76c695122efc8aa7Angus Kong 383a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker = (ModePicker) findViewById(R.id.mode_picker); 384a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setVisibility(View.VISIBLE); 385a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setOnModeChangeListener(this); 386a72d73cbac59db43d413291e4db66763be08143arepo sync mModePicker.setCurrentMode(ModePicker.MODE_PANORAMA); 38741a2e9735136f372de95652d0828600282c8e967mbansal 38841a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setVisibility(View.VISIBLE); 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); 430142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mPanoControlLayout.setVisibility(View.VISIBLE); 43160fc534ec8f68d95a486984cb396a2da0e200518Angus Kong mCaptureLayout.setVisibility(View.VISIBLE); 432142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.reset(); 43341a2e9735136f372de95652d0828600282c8e967mbansal 43441a2e9735136f372de95652d0828600282c8e967mbansal mSurface.setOnFrameAvailableListener(this); 43541a2e9735136f372de95652d0828600282c8e967mbansal 43636839102e03107e3fb121197036365a58ec2686eAngus Kong if (!mPausing) startCameraPreview(); 43741a2e9735136f372de95652d0828600282c8e967mbansal 43841a2e9735136f372de95652d0828600282c8e967mbansal mRealTimeMosaicView.setVisibility(View.VISIBLE); 439142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 440142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 441142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void showFinalMosaic(Bitmap bitmap) { 442142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (bitmap != null) { 443142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mReview.setImageBitmap(bitmap); 444142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 445ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mCaptureLayout.setVisibility(View.GONE); 446ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mReviewLayout.setVisibility(View.VISIBLE); 447ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mCaptureView.setStatusText(""); 448ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong mCaptureView.setSweepAngle(0); 449142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 450142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 451ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong private void savePanorama(byte[] jpegData) { 452ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong if (jpegData != null) { 453ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong String imagePath = PanoUtil.createName( 454ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong getResources().getString(R.string.pano_file_name_format), mTimeTaken); 455ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Storage.addImage(getContentResolver(), imagePath, mTimeTaken, null, 0, 456ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong jpegData); 457142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 458142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 459142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 460142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void clearMosaicFrameProcessorIfNeeded() { 461142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (!mPausing || mThreadRunning) return; 462142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.clear(); 463142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 464142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong 465142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong private void initMosaicFrameProcessorIfNeeded() { 466142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (mPausing || mThreadRunning) return; 467142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong if (mMosaicFrameProcessor == null) { 468142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong // Start the activity for the first time. 469142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor = new MosaicFrameProcessor(DEFAULT_SWEEP_ANGLE - 5, 4700adf2489520d3a98a56e081aeacb1ab9336a012fWei-Ta Chen mPreviewWidth, mPreviewHeight, getPreviewBufSize()); 471142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong } 472142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mMosaicFrameProcessor.initialize(); 473bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 474bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 475bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 476bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen protected void onPause() { 477bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen super.onPause(); 47841a2e9735136f372de95652d0828600282c8e967mbansal mSurface.setOnFrameAvailableListener(null); 479bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen releaseCamera(); 480142402d57c1689c1342d096c976b9b0826f8ce1aAngus Kong mPausing = true; 48141a2e9735136f372de95652d0828600282c8e967mbansal 482eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView.onPause(); 48341a2e9735136f372de95652d0828600282c8e967mbansal mCaptureView.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(); 50794f592fc405ca45b8794007cd9083c3250924b50Wei-Ta Chen mCaptureView.onResume(); 508eeb94d4de94bfd4e01f3a716803f77a530f5b92cmbansal mRealTimeMosaicView.onResume(); 509bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 510bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 511bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private final SensorEventListener mListener = new SensorEventListener() { 512bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private float mCompassCurrX; // degrees 513bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private float mCompassCurrY; // degrees 514bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen private float mTimestamp; 515bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 516bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onSensorChanged(SensorEvent event) { 517bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { 518bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen if (mTimestamp != 0) { 519bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen final float dT = (event.timestamp - mTimestamp) * NS2S; 520bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCompassCurrX += event.values[1] * dT * 180.0f / Math.PI; 521bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCompassCurrY += event.values[0] * dT * 180.0f / Math.PI; 522bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 523bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mTimestamp = event.timestamp; 524bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 525bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { 526bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCompassCurrX = event.values[0]; 527bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen mCompassCurrY = event.values[1]; 528bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 529bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 5308a2c41754655a3733175fce81fb7506ff7022959Angus Kong if (mMosaicFrameProcessor != null) { 5318a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.updateCompassValue(mCompassCurrX, mCompassCurrY); 532bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 533bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 534bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 535bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen @Override 536bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen public void onAccuracyChanged(Sensor sensor, int accuracy) { 537bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 538bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen }; 539bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 540ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong public byte[] generateFinalMosaic(boolean highRes) { 5418a2c41754655a3733175fce81fb7506ff7022959Angus Kong mMosaicFrameProcessor.createMosaic(highRes); 542bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen 543ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong byte[] imageData = mMosaicFrameProcessor.getFinalMosaicNV21(); 544ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong if (imageData == null) { 545ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.e(TAG, "getFinalMosaicNV21() returned null."); 546ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong return null; 5478a2c41754655a3733175fce81fb7506ff7022959Angus Kong } 5488a2c41754655a3733175fce81fb7506ff7022959Angus Kong 549ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int len = imageData.length - 8; 550ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int width = (imageData[len + 0] << 24) + ((imageData[len + 1] & 0xFF) << 16) 551ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong + ((imageData[len + 2] & 0xFF) << 8) + (imageData[len + 3] & 0xFF); 552ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong int height = (imageData[len + 4] << 24) + ((imageData[len + 5] & 0xFF) << 16) 553ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong + ((imageData[len + 6] & 0xFF) << 8) + (imageData[len + 7] & 0xFF); 554ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.v(TAG, "ImLength = " + (len) + ", W = " + width + ", H = " + height); 5558a2c41754655a3733175fce81fb7506ff7022959Angus Kong 556e46486104523760a4433f03e09ed615987d83b6cAngus Kong if (width <= 0 || height <= 0) { 557e46486104523760a4433f03e09ed615987d83b6cAngus Kong // TODO: pop up a error meesage indicating that the final result is not generated. 558e46486104523760a4433f03e09ed615987d83b6cAngus Kong Log.e(TAG, "width|height <= 0!!, len = " + (len) + ", W = " + width + ", H = " + 559e46486104523760a4433f03e09ed615987d83b6cAngus Kong height); 560e46486104523760a4433f03e09ed615987d83b6cAngus Kong return null; 561e46486104523760a4433f03e09ed615987d83b6cAngus Kong } 562e46486104523760a4433f03e09ed615987d83b6cAngus Kong 563ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong YuvImage yuvimage = new YuvImage(imageData, ImageFormat.NV21, width, height, null); 564ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong ByteArrayOutputStream out = new ByteArrayOutputStream(); 565ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong yuvimage.compressToJpeg(new Rect(0, 0, width, height), 100, out); 566ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong try { 567ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong out.close(); 568ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } catch (Exception e) { 569ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong Log.e(TAG, "Exception in storing final mosaic", e); 570ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong return null; 571ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong } 572ef91f8514bf3c21091dde6b292f9616464dc32e8Angus Kong return out.toByteArray(); 573bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen } 5748a2c41754655a3733175fce81fb7506ff7022959Angus Kong 57541a2e9735136f372de95652d0828600282c8e967mbansal private void setPreviewTexture(SurfaceTexture surface) { 57698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen try { 57741a2e9735136f372de95652d0828600282c8e967mbansal mCameraDevice.setPreviewTexture(surface); 57898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } catch (Throwable ex) { 57998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen releaseCamera(); 58041a2e9735136f372de95652d0828600282c8e967mbansal throw new RuntimeException("setPreviewTexture failed", ex); 58198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 58298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 58398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 58436839102e03107e3fb121197036365a58ec2686eAngus Kong private void startCameraPreview() { 58598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen // If we're previewing already, stop the preview first (this will blank 58698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen // the screen). 58736839102e03107e3fb121197036365a58ec2686eAngus Kong if (mCameraState != PREVIEW_STOPPED) stopCameraPreview(); 58898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 58941a2e9735136f372de95652d0828600282c8e967mbansal setPreviewTexture(mSurface); 59098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 59198f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen try { 59298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen Log.v(TAG, "startPreview"); 59398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraDevice.startPreview(); 59498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } catch (Throwable ex) { 59598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen releaseCamera(); 59698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen throw new RuntimeException("startPreview failed", ex); 59798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 59898f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_ACTIVE; 59998f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 60098f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen 60136839102e03107e3fb121197036365a58ec2686eAngus Kong private void stopCameraPreview() { 60298f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen if (mCameraDevice != null && mCameraState != PREVIEW_STOPPED) { 60398f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen Log.v(TAG, "stopPreview"); 60498f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraDevice.stopPreview(); 60598f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 60698f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen mCameraState = PREVIEW_STOPPED; 60798f41918daf64318a7da4ec94712eeb8d6697f31Wei-Ta Chen } 608bdc7e2b461064b25b7f17b0941077fc97653093dWei-Ta Chen} 609