diff options
Diffstat (limited to 'src/com/android/camera/panorama/PanoramaActivity.java')
-rw-r--r-- | src/com/android/camera/panorama/PanoramaActivity.java | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/src/com/android/camera/panorama/PanoramaActivity.java b/src/com/android/camera/panorama/PanoramaActivity.java new file mode 100644 index 0000000..5d18525 --- /dev/null +++ b/src/com/android/camera/panorama/PanoramaActivity.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.camera.panorama; + +import android.app.Activity; +import android.content.Context; +import android.graphics.PixelFormat; +import android.hardware.Camera.Parameters; +import android.hardware.Camera.Size; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.net.Uri; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.WindowManager; +import android.widget.ImageView; + +import com.android.camera.CameraDisabledException; +import com.android.camera.CameraHardwareException; +import com.android.camera.CameraHolder; +import com.android.camera.R; +import com.android.camera.ShutterButton; +import com.android.camera.Util; + +import java.util.List; + +public class PanoramaActivity extends Activity { + public static final int DEFAULT_SWEEP_ANGLE = 60; + public static final int DEFAULT_BLEND_MODE = Mosaic.BLENDTYPE_HORIZONTAL; + public static final int DEFAULT_CAPTURE_PIXELS = 960 * 720; + + private static final String TAG = "PanoramaActivity"; + private static final float NS2S = 1.0f / 1000000000.0f; // TODO: commit for this constant. + + private Preview mPreview; + private ImageView mReview; + private CaptureView mCaptureView; + private ShutterButton mShutterButton; + private int mPreviewWidth; + private int mPreviewHeight; + private android.hardware.Camera mCameraDevice; + private SensorManager mSensorManager; + private Sensor mSensor; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + + getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON, + WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + createContentView(); + + mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); + + mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE); + if (mSensor == null) { + mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); + } + } + + private void setupCamera() { + openCamera(); + Parameters parameters = mCameraDevice.getParameters(); + setupCaptureParams(parameters); + configureCamera(parameters); + } + + private void openCamera() { + try { + mCameraDevice = Util.openCamera(this, CameraHolder.instance().getBackCameraId()); + } catch (CameraHardwareException e) { + Util.showErrorAndFinish(this, R.string.cannot_connect_camera); + return; + } catch (CameraDisabledException e) { + Util.showErrorAndFinish(this, R.string.camera_disabled); + return; + } + } + + private boolean findBestPreviewSize(List<Size> supportedSizes, boolean need4To3, + boolean needSmaller) { + int pixelsDiff = DEFAULT_CAPTURE_PIXELS; + boolean hasFound = false; + for (Size size: supportedSizes) { + int h = size.height; + int w = size.width; + // we only want 4:3 format. + int d = DEFAULT_CAPTURE_PIXELS - h * w; + if (needSmaller && d < 0) { // no bigger preview than 960x720. + continue; + } + if (need4To3 && (h * 4 != w * 3)) { + continue; + } + d = Math.abs(d); + if (d < pixelsDiff) { + mPreviewWidth = w; + mPreviewHeight = h; + pixelsDiff = d; + hasFound = true; + } + } + return hasFound; + } + + private void setupCaptureParams(Parameters parameters) { + List<Size> supportedSizes = parameters.getSupportedPreviewSizes(); + if (!findBestPreviewSize(supportedSizes, true, true)) { + Log.w(TAG, "No 4:3 ratio preview size supported."); + if (!findBestPreviewSize(supportedSizes, false, true)) { + Log.w(TAG, "Can't find a supported preview size smaller than 960x720."); + findBestPreviewSize(supportedSizes, false, false); + } + } + Log.v(TAG, "preview h = " + mPreviewHeight + " , w = " + mPreviewWidth); + parameters.setPreviewSize(mPreviewWidth, mPreviewHeight); + + List<int[]> frameRates = parameters.getSupportedPreviewFpsRange(); + int last = frameRates.size() - 1; + int minFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MIN_INDEX]; + int maxFps = (frameRates.get(last))[Parameters.PREVIEW_FPS_MAX_INDEX]; + parameters.setPreviewFpsRange(minFps, maxFps); + Log.v(TAG, "preview fps: " + minFps + ", " + maxFps); + } + + public int getPreviewBufSize() { + PixelFormat pixelInfo = new PixelFormat(); + PixelFormat.getPixelFormatInfo(mCameraDevice.getParameters().getPreviewFormat(), pixelInfo); + // TODO: remove this extra 32 byte after the driver bug is fixed. + return (mPreviewWidth * mPreviewHeight * pixelInfo.bitsPerPixel / 8) + 32; + } + + private void configureCamera(Parameters parameters) { + mCameraDevice.setParameters(parameters); + + int bufSize = getPreviewBufSize(); + Log.v(TAG, "BufSize = " + bufSize); + for (int i = 0; i < 10; i++) { + try { + mCameraDevice.addCallbackBuffer(new byte[bufSize]); + } catch (OutOfMemoryError e) { + Log.v(TAG, "Buffer allocation failed: buffer " + i); + break; + } + } + } + + private void createContentView() { + setContentView(R.layout.panorama); + + mPreview = (Preview) findViewById(R.id.pano_preview); + mCaptureView = (CaptureView) findViewById(R.id.pano_capture_view); + mCaptureView.setStartAngle(-DEFAULT_SWEEP_ANGLE / 2); + mCaptureView.setVisibility(View.INVISIBLE); + + mReview = (ImageView) findViewById(R.id.pano_reviewarea); + mReview.setVisibility(View.INVISIBLE); + + mShutterButton = (ShutterButton) findViewById(R.id.pano_shutter_button); + mShutterButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mPreview.setCaptureStarted(DEFAULT_SWEEP_ANGLE, DEFAULT_BLEND_MODE); + } + }); + } + + public void showResultingMosaic(String uri) { + Uri parsed = Uri.parse(uri); + mReview.setImageURI(parsed); + mReview.setVisibility(View.VISIBLE); + mPreview.setVisibility(View.INVISIBLE); + mCaptureView.setVisibility(View.INVISIBLE); + } + + @Override + protected void onPause() { + super.onPause(); + mPreview.onPause(); + mSensorManager.unregisterListener(mListener); + releaseCamera(); + } + + @Override + protected void onResume() { + super.onResume(); + + /* + * It is not necessary to get accelerometer events at a very high + * rate, by using a slower rate (SENSOR_DELAY_UI), we get an + * automatic low-pass filter, which "extracts" the gravity component + * of the acceleration. As an added benefit, we use less power and + * CPU resources. + */ + mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_UI); + + setupCamera(); + mPreview.setCameraDevice(mCameraDevice); + mCameraDevice.startPreview(); + } + + private void releaseCamera() { + if (mCameraDevice != null){ + CameraHolder.instance().release(); + mCameraDevice = null; + } + } + + private final SensorEventListener mListener = new SensorEventListener() { + private float mCompassCurrX; // degrees + private float mCompassCurrY; // degrees + private float mTimestamp; + + public void onSensorChanged(SensorEvent event) { + + if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) { + if (mTimestamp != 0) { + final float dT = (event.timestamp - mTimestamp) * NS2S; + mCompassCurrX += event.values[1] * dT * 180.0f / Math.PI; + mCompassCurrY += event.values[0] * dT * 180.0f / Math.PI; + } + mTimestamp = event.timestamp; + + } else if (event.sensor.getType() == Sensor.TYPE_ORIENTATION) { + mCompassCurrX = event.values[0]; + mCompassCurrY = event.values[1]; + } + + if (mPreview != null) { + mPreview.updateCompassValue(mCompassCurrX, mCompassCurrY); + } + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + } + }; + + public int getPreviewFrameWidth() { + return mPreviewWidth; + } + + public int getPreviewFrameHeight() { + return mPreviewHeight; + } + + public CaptureView getCaptureView() { + return mCaptureView; + } +} |