From f5b1181157b6d7f65376c0068768f8f3f94b5d69 Mon Sep 17 00:00:00 2001 From: Alok Kediya Date: Thu, 7 Nov 2013 13:53:09 +0530 Subject: Camera2: Adds support for longshot/burst mode - The longshot/burst pipeline mode uses an optimized path for triggering 'takePicture()' on each shutter callback. This should improve the shot-2-shot time. In addition to this there is also support for jpeg callbacks that only contain a jpeg file path. The callback in this case will only move the file stored by the lower layers in the correct directory. - The longshot burst pipeline can be enabled via this property: "persist.camera.longshot.enable"<-"0/1" - This change will allow longshot mode to be triggered in non-zsl mode as well. (Cherry picked from: I693366a7d06d3b386a8d96f86ee9a0574749c50b) (Cherry picked from: Id630b2033f18d1c04a636597e910e695a8692ac8) Change-Id: Idda8d58fc6d889128c1812c9c5ddadca3993c246 --- .../android/camera/AndroidCameraManagerImpl.java | 14 ++ src/com/android/camera/CameraManager.java | 7 + src/com/android/camera/FocusOverlayManager.java | 4 + src/com/android/camera/PhotoController.java | 2 + src/com/android/camera/PhotoModule.java | 147 ++++++++++++++++++++- src/com/android/camera/ShutterButton.java | 14 ++ src/com/android/camera/Storage.java | 10 +- src/com/android/camera/VideoModule.java | 3 + src/com/android/camera/WideAnglePanoramaUI.java | 3 + 9 files changed, 196 insertions(+), 8 deletions(-) mode change 100755 => 100644 src/com/android/camera/ShutterButton.java (limited to 'src/com/android') diff --git a/src/com/android/camera/AndroidCameraManagerImpl.java b/src/com/android/camera/AndroidCameraManagerImpl.java index 84dc0a8de..b72fbd0da 100644 --- a/src/com/android/camera/AndroidCameraManagerImpl.java +++ b/src/com/android/camera/AndroidCameraManagerImpl.java @@ -88,6 +88,8 @@ class AndroidCameraManagerImpl implements CameraManager { // Histogram private static final int SET_HISTOGRAM_MODE = 601; private static final int SEND_HISTOGRAM_DATA = 602; + //LONGSHOT + private static final int SET_LONGSHOT = 701; private CameraHandler mCameraHandler; private android.hardware.Camera mCamera; @@ -329,6 +331,11 @@ class AndroidCameraManagerImpl implements CameraManager { case SEND_HISTOGRAM_DATA: mCamera.sendHistogramData(); break; + + case SET_LONGSHOT: + mCamera.setLongshot((Boolean) msg.obj); + break; + default: throw new RuntimeException("Invalid CameraProxy message=" + msg.what); } @@ -552,6 +559,13 @@ class AndroidCameraManagerImpl implements CameraManager { mCameraHandler.obtainMessage( ENABLE_SHUTTER_SOUND, (enable ? 1 : 0), 0).sendToTarget(); } + + @Override + public void setLongshot(boolean enable) { + mCameraHandler.obtainMessage(SET_LONGSHOT, + new Boolean(enable)).sendToTarget(); + } + @Override public void setHistogramMode(CameraDataCallback cb) { mCameraHandler.obtainMessage(SET_HISTOGRAM_MODE, cb).sendToTarget(); diff --git a/src/com/android/camera/CameraManager.java b/src/com/android/camera/CameraManager.java index 4c43c27b8..8ad0d52d6 100644 --- a/src/com/android/camera/CameraManager.java +++ b/src/com/android/camera/CameraManager.java @@ -361,5 +361,12 @@ public interface CameraManager { * */ public void sendHistogramData(); + /** + * Enables/Disables longshot mode. + * + * @param enable {@code true} to enable longshot mode, + * {@code false} to disable it. + */ + public void setLongshot(boolean enable); } } diff --git a/src/com/android/camera/FocusOverlayManager.java b/src/com/android/camera/FocusOverlayManager.java index 3176ea2b9..686122723 100644 --- a/src/com/android/camera/FocusOverlayManager.java +++ b/src/com/android/camera/FocusOverlayManager.java @@ -580,4 +580,8 @@ public class FocusOverlayManager { public void setZslEnable(boolean value) { mZslEnabled = value; } + + public boolean isZslEnabled() { + return mZslEnabled; + } } diff --git a/src/com/android/camera/PhotoController.java b/src/com/android/camera/PhotoController.java index 291b5df49..f6898a34f 100644 --- a/src/com/android/camera/PhotoController.java +++ b/src/com/android/camera/PhotoController.java @@ -30,6 +30,8 @@ public interface PhotoController extends OnShutterButtonListener { public static final int SNAPSHOT_IN_PROGRESS = 3; // Switching between cameras. public static final int SWITCHING_CAMERA = 4; + // Longshot mode + public static final int LONGSHOT = 5; // returns the actual set zoom value public int onZoomChanged(int requestedZoom); diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java index 714d64cc3..31b9e8b26 100644 --- a/src/com/android/camera/PhotoModule.java +++ b/src/com/android/camera/PhotoModule.java @@ -178,6 +178,7 @@ public class PhotoModule private boolean mAwbLockSupported; private boolean mContinuousFocusSupported; private boolean mTouchAfAecFlag; + private boolean mLongshotSave = false; // The degrees of the device rotated clockwise from its natural orientation. private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; @@ -188,6 +189,9 @@ public class PhotoModule private ContentProviderClient mMediaProviderClient; private boolean mFaceDetectionStarted = false; + private static final String PERSIST_LONG_ENABLE = "persist.camera.longshot.enable"; + private static final String PERSIST_LONG_SAVE = "persist.camera.longshot.save"; + private static final int MINIMUM_BRIGHTNESS = 0; private static final int MAXIMUM_BRIGHTNESS = 6; private int mbrightness = 3; @@ -756,6 +760,34 @@ public class PhotoModule } } + private final class LongshotShutterCallback + implements CameraShutterCallback { + + @Override + public void onShutter(CameraProxy camera) { + mShutterCallbackTime = System.currentTimeMillis(); + mShutterLag = mShutterCallbackTime - mCaptureStartTime; + Log.e(TAG, "[KPI Perf] PROFILE_SHUTTER_LAG mShutterLag = " + mShutterLag + "ms"); + synchronized(mCameraDevice) { + + if (mCameraState != LONGSHOT) { + return; + } + + if (mLongshotSave) { + mCameraDevice.takePicture(mHandler, + new LongshotShutterCallback(), + mRawPictureCallback, mPostViewPictureCallback, + new LongshotPictureCallback(null)); + } else { + mCameraDevice.takePicture(mHandler,new LongshotShutterCallback(), + mRawPictureCallback, mPostViewPictureCallback, + new JpegPictureCallback(null)); + } + } + } + } + private final class ShutterCallback implements CameraShutterCallback { @@ -821,6 +853,64 @@ public class PhotoModule } } + private final class LongshotPictureCallback implements CameraPictureCallback { + Location mLocation; + + public LongshotPictureCallback(Location loc) { + mLocation = loc; + } + + @Override + public void onPictureTaken(final byte [] jpegData, CameraProxy camera) { + if (mPaused) { + return; + } + + mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden. + + String jpegFilePath = new String(jpegData); + mNamedImages.nameNewImage(mCaptureStartTime); + NamedEntity name = mNamedImages.getNextNameEntity(); + String title = (name == null) ? null : name.title; + long date = (name == null) ? -1 : name.date; + + if (title == null) { + Log.e(TAG, "Unbalanced name/data pair"); + return; + } + + + if (date == -1 ) { + Log.e(TAG, "Invalid filename date"); + return; + } + + String dstPath = Storage.DIRECTORY; + File sdCard = android.os.Environment.getExternalStorageDirectory(); + File dstFile = new File(dstPath); + if (dstFile == null) { + Log.e(TAG, "Destination file path invalid"); + return; + } + + File srcFile = new File(jpegFilePath); + if (srcFile == null) { + Log.e(TAG, "Source file path invalid"); + return; + } + + if ( srcFile.renameTo(dstFile) ) { + Size s = mParameters.getPictureSize(); + String pictureFormat = mParameters.get(KEY_PICTURE_FORMAT); + mActivity.getMediaSaveService().addImage( + null, title, date, mLocation, s.width, s.height, + 0, null, mOnMediaSavedListener, mContentResolver, pictureFormat); + } else { + Log.e(TAG, "Failed to move jpeg file"); + } + } + } + private final class JpegPictureCallback implements CameraPictureCallback { Location mLocation; @@ -872,11 +962,13 @@ public class PhotoModule mFocusManager.updateFocusUI(); // Ensure focus indicator is hidden. boolean needRestartPreview = !mIsImageCaptureIntent + && (mCameraState != LONGSHOT) && (mSnapshotMode != CameraInfo.CAMERA_SUPPORT_MODE_ZSL) && (mReceivedSnapNum == mBurstSnapNum); if (needRestartPreview) { setupPreview(); - }else if (mReceivedSnapNum == mBurstSnapNum){ + }else if ((mReceivedSnapNum == mBurstSnapNum) + && (mCameraState != LONGSHOT)){ mFocusManager.resetTouchFocus(); setCameraState(IDLE); } @@ -1086,6 +1178,7 @@ public class PhotoModule switch (state) { case PhotoController.PREVIEW_STOPPED: case PhotoController.SNAPSHOT_IN_PROGRESS: + case PhotoController.LONGSHOT: case PhotoController.SWITCHING_CAMERA: mUI.enableGestures(false); break; @@ -1162,15 +1255,30 @@ public class PhotoModule // We don't want user to press the button again while taking a // multi-second HDR photo. mUI.enableShutter(false); - mCameraDevice.takePicture(mHandler, - new ShutterCallback(!animateBefore), - mRawPictureCallback, mPostViewPictureCallback, - new JpegPictureCallback(loc)); + + if (mCameraState == LONGSHOT) { + if(mLongshotSave) { + mCameraDevice.takePicture(mHandler, + new LongshotShutterCallback(), + mRawPictureCallback, mPostViewPictureCallback, + new LongshotPictureCallback(loc)); + } else { + mCameraDevice.takePicture(mHandler, + new LongshotShutterCallback(), + mRawPictureCallback, mPostViewPictureCallback, + new JpegPictureCallback(loc)); + } + } else { + mCameraDevice.takePicture(mHandler, + new ShutterCallback(!animateBefore), + mRawPictureCallback, mPostViewPictureCallback, + new JpegPictureCallback(loc)); + setCameraState(SNAPSHOT_IN_PROGRESS); + } mNamedImages.nameNewImage(mCaptureStartTime); mFaceDetectionStarted = false; - setCameraState(SNAPSHOT_IN_PROGRESS); UsageStatistics.onEvent(UsageStatistics.COMPONENT_CAMERA, UsageStatistics.ACTION_CAPTURE_DONE, "Photo"); return true; @@ -1375,6 +1483,18 @@ public class PhotoModule || (mCameraState == SNAPSHOT_IN_PROGRESS) || (mCameraState == PREVIEW_STOPPED)) return; + synchronized(mCameraDevice) { + if (mCameraState == LONGSHOT) { + mCameraDevice.setLongshot(false); + if (!mFocusManager.isZslEnabled()) { + setupPreview(); + } else { + setCameraState(IDLE); + mFocusManager.resetTouchFocus(); + } + } + } + // Do not do focus if there is not enough storage. if (pressed && !canTakePicture()) return; @@ -1447,6 +1567,21 @@ public class PhotoModule } } + @Override + public void onShutterButtonLongClick() { + if ((null != mCameraDevice) && (mCameraState == IDLE)) { + boolean enable = false; + enable = SystemProperties.getBoolean(PERSIST_LONG_ENABLE, false); + if ( enable ) { + enable = SystemProperties.getBoolean(PERSIST_LONG_SAVE, false); + mLongshotSave = enable; + mCameraDevice.setLongshot(true); + setCameraState(PhotoController.LONGSHOT); + mFocusManager.doSnap(); + } + } + } + @Override public void installIntentFilter() { // Do nothing. diff --git a/src/com/android/camera/ShutterButton.java b/src/com/android/camera/ShutterButton.java old mode 100755 new mode 100644 index a1bbb1a0d..f1d969f9d --- a/src/com/android/camera/ShutterButton.java +++ b/src/com/android/camera/ShutterButton.java @@ -29,7 +29,18 @@ import android.widget.ImageView; */ public class ShutterButton extends ImageView { + private class LongClickListener implements View.OnLongClickListener { + public boolean onLongClick(View v) { + if ( null != mListener ) { + mListener.onShutterButtonLongClick(); + return true; + } + return false; + } + } + private boolean mTouchEnabled = true; + private LongClickListener mLongClick = new LongClickListener(); /** * A callback to be invoked when a ShutterButton's pressed state changes. @@ -42,6 +53,7 @@ public class ShutterButton extends ImageView { */ void onShutterButtonFocus(boolean pressed); void onShutterButtonClick(); + void onShutterButtonLongClick(); } private OnShutterButtonListener mListener; @@ -53,6 +65,7 @@ public class ShutterButton extends ImageView { public void setOnShutterButtonListener(OnShutterButtonListener listener) { mListener = listener; + setOnLongClickListener(mLongClick); } @Override @@ -66,6 +79,7 @@ public class ShutterButton extends ImageView { public void enableTouch(boolean enable) { mTouchEnabled = enable; + setLongClickable(enable); } /** diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java index 00bd8d1c4..49435e4c0 100644 --- a/src/com/android/camera/Storage.java +++ b/src/com/android/camera/Storage.java @@ -82,6 +82,12 @@ public class Storage { public static Uri addImage(ContentResolver resolver, String title, long date, Location location, int orientation, ExifInterface exif, byte[] jpeg, int width, int height, String pictureFormat) { + int jpegLength = 0; + + if (jpeg != null) { + jpegLength = jpeg.length; + } + // Save the image. String path = generateFilepath(title, pictureFormat); if (exif != null && (pictureFormat == null || @@ -91,7 +97,7 @@ public class Storage { } catch (Exception e) { Log.e(TAG, "Failed to write data", e); } - } else { + } else if (jpeg != null) { if (!(pictureFormat.equalsIgnoreCase("jpeg") || pictureFormat == null)) { File dir = new File(RAW_DIRECTORY); dir.mkdirs(); @@ -99,7 +105,7 @@ public class Storage { writeFile(path, jpeg); } return addImage(resolver, title, date, location, orientation, - jpeg.length, path, width, height, pictureFormat); + jpegLength, path, width, height, pictureFormat); } // Add the image to media store. diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index 3d748a97b..36e5862a2 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -648,6 +648,9 @@ public class VideoModule implements CameraModule, mUI.setShutterPressed(pressed); } + @Override + public void onShutterButtonLongClick() {} + private void qcomReadVideoPreferences() { String videoEncoder = mPreferences.getString( CameraSettings.KEY_VIDEO_ENCODER, diff --git a/src/com/android/camera/WideAnglePanoramaUI.java b/src/com/android/camera/WideAnglePanoramaUI.java index 2a47d233e..02ce5516f 100644 --- a/src/com/android/camera/WideAnglePanoramaUI.java +++ b/src/com/android/camera/WideAnglePanoramaUI.java @@ -315,6 +315,9 @@ public class WideAnglePanoramaUI implements mController.onShutterButtonClick(); } + @Override + public void onShutterButtonLongClick() {} + @Override public void onLayoutChange( View v, int l, int t, int r, int b, -- cgit v1.2.3