From 929d67931a209e6830b8b83d9a2a0f3dbd38c841 Mon Sep 17 00:00:00 2001 From: junjiez Date: Tue, 20 Dec 2016 15:55:31 +0800 Subject: SnapdragonCamera: add features for 3rd-party apps Add capture and recording features for 3rd-party app. Change-Id: Iefedbed2cb17cca17941e70f861448a2b8f97da2 CRs-Fixed: 1095457 --- src/com/android/camera/CameraActivity.java | 3 +- src/com/android/camera/CaptureModule.java | 328 +++++++++++++++++++-- src/com/android/camera/CaptureUI.java | 159 +++++++++- .../camera/imageprocessor/PostProcessor.java | 31 +- .../imageprocessor/filter/BestpictureFilter.java | 3 + src/com/android/camera/ui/OneUICameraControls.java | 41 ++- 6 files changed, 514 insertions(+), 51 deletions(-) mode change 100644 => 100755 src/com/android/camera/CameraActivity.java mode change 100644 => 100755 src/com/android/camera/CaptureUI.java mode change 100644 => 100755 src/com/android/camera/imageprocessor/PostProcessor.java mode change 100644 => 100755 src/com/android/camera/imageprocessor/filter/BestpictureFilter.java (limited to 'src/com') diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java old mode 100644 new mode 100755 index d3c39793a..fcb410888 --- a/src/com/android/camera/CameraActivity.java +++ b/src/com/android/camera/CameraActivity.java @@ -1518,7 +1518,8 @@ public class CameraActivity extends Activity } boolean cam2on = PersistUtil.getCamera2Mode(); - if (cam2on && moduleIndex == ModuleSwitcher.PHOTO_MODULE_INDEX) + if (cam2on && (moduleIndex == ModuleSwitcher.PHOTO_MODULE_INDEX || + moduleIndex == ModuleSwitcher.VIDEO_MODULE_INDEX)) moduleIndex = ModuleSwitcher.CAPTURE_MODULE_INDEX; mOrientationListener = new MyOrientationEventListener(this); diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index e870161f3..e5ceb4e11 100644 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -19,19 +19,23 @@ package com.android.camera; +import android.app.Activity; import android.app.ActivityManager; import android.app.AlertDialog; +import android.content.ActivityNotFoundException; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; +import android.graphics.Bitmap; import android.graphics.ImageFormat; import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; +import android.hardware.Camera; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; import android.hardware.camera2.CameraCharacteristics; @@ -59,12 +63,14 @@ import android.media.MediaRecorder; import android.media.EncoderCapabilities; import android.media.EncoderCapabilities.VideoEncoderCap; import android.net.Uri; +import android.os.Bundle; import android.os.Debug; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Bundle; import android.os.Message; +import android.os.ParcelFileDescriptor; import android.os.SystemClock; import android.provider.MediaStore; import android.util.Log; @@ -104,13 +110,17 @@ import org.codeaurora.snapcam.R; import org.codeaurora.snapcam.filter.ClearSightImageProcessor; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStream; import java.nio.ByteBuffer; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.Set; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.lang.reflect.Method; @@ -126,6 +136,10 @@ public class CaptureModule implements CameraModule, PhotoController, public static final int BAYER_ID = 0; public static int MONO_ID = -1; public static int FRONT_ID = -1; + public static final int INTENT_MODE_NORMAL = 0; + public static final int INTENT_MODE_CAPTURE = 1; + public static final int INTENT_MODE_VIDEO = 2; + public static final int INTENT_MODE_CAPTURE_SECURE = 3; private static final int BACK_MODE = 0; private static final int FRONT_MODE = 1; private static final int CANCEL_TOUCH_FOCUS_DELAY = 3000; @@ -134,6 +148,8 @@ public class CaptureModule implements CameraModule, PhotoController, private static final int MAX_NUM_CAM = 3; private static final MeteringRectangle[] ZERO_WEIGHT_3A_REGION = new MeteringRectangle[]{ new MeteringRectangle(0, 0, 0, 0, 0)}; + private static final String EXTRA_QUICK_CAPTURE = + "android.intent.extra.quickCapture"; /** * Camera state: Showing camera preview. */ @@ -244,6 +260,15 @@ public class CaptureModule implements CameraModule, PhotoController, boolean mUnsupportedResolution = false; private static final int SDCARD_SIZE_LIMIT = 4000 * 1024 * 1024; + private static final String sTempCropFilename = "crop-temp"; + private static final int REQUEST_CROP = 1000; + private int mIntentMode = INTENT_MODE_NORMAL; + private String mCropValue; + private Uri mCurrentVideoUri; + private ParcelFileDescriptor mVideoFileDescriptor; + private Uri mSaveUri; + private boolean mQuickCapture; + private byte[] mJpegImageData; /** * A {@link CameraCaptureSession } for camera preview. @@ -380,6 +405,7 @@ public class CaptureModule implements CameraModule, PhotoController, public void onMediaSaved(Uri uri) { if (uri != null) { mActivity.notifyNewMedia(uri); + mCurrentVideoUri = uri; } } }; @@ -1088,6 +1114,7 @@ public class CaptureModule implements CameraModule, PhotoController, mFrameProcessor = new FrameProcessor(mActivity, this); mContentResolver = mActivity.getContentResolver(); + initModeByIntent(); mUI = new CaptureUI(activity, this, parent); mUI.initializeControlByIntent(); @@ -1095,6 +1122,49 @@ public class CaptureModule implements CameraModule, PhotoController, mLocationManager = new LocationManager(mActivity, this); } + private void initModeByIntent() { + String action = mActivity.getIntent().getAction(); + if (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)) { + mIntentMode = INTENT_MODE_CAPTURE; + } else if (CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action)) { + mIntentMode = INTENT_MODE_CAPTURE_SECURE; + } else if (MediaStore.ACTION_VIDEO_CAPTURE.equals(action)) { + mIntentMode = INTENT_MODE_VIDEO; + } + mQuickCapture = mActivity.getIntent().getBooleanExtra(EXTRA_QUICK_CAPTURE, false); + Bundle myExtras = mActivity.getIntent().getExtras(); + if (myExtras != null) { + mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); + mCropValue = myExtras.getString("crop"); + } + } + + public boolean isQuickCapture() { + return mQuickCapture; + } + + public void setJpegImageData(byte[] data) { + mJpegImageData = data; + } + + public void showCapturedReview(byte[] jpegData, int orientation, boolean mirror) { + mActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mUI.showCapturedImageForReview(jpegData, orientation, mirror); + } + }); + } + + + public int getCurrentIntentMode() { + return mIntentMode; + } + + public void cancelCapture() { + mActivity.finish(); + } + /** * Initiate a still image capture. */ @@ -1245,6 +1315,7 @@ public class CaptureModule implements CameraModule, PhotoController, private void captureStillPicture(final int id) { Log.d(TAG, "captureStillPicture " + id); + mJpegImageData = null; mIsRefocus = false; CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { @@ -1549,14 +1620,24 @@ public class CaptureModule implements CameraModule, PhotoController, ExifInterface exif = Exif.getExif(bytes); int orientation = Exif.getOrientation(exif); - mActivity.getMediaSaveService().addImage(bytes, title, date, - null, image.getWidth(), image.getHeight(), orientation, null, - mOnMediaSavedListener, mContentResolver, "jpeg"); - - if(mLongshotActive) { - mLastJpegData = bytes; + if (getCameraMode() != CaptureModule.INTENT_MODE_NORMAL) { + mJpegImageData = bytes; + if (!mQuickCapture) { + showCapturedReview(bytes, orientation, + mPostProcessor.isSelfieMirrorOn()); + } else { + onCaptureDone(); + } } else { - mActivity.updateThumbnail(bytes); + mActivity.getMediaSaveService().addImage(bytes, title, date, + null, image.getWidth(), image.getHeight(), orientation, null, + mOnMediaSavedListener, mContentResolver, "jpeg"); + + if(mLongshotActive) { + mLastJpegData = bytes; + } else { + mActivity.updateThumbnail(bytes); + } } image.close(); } @@ -1955,6 +2036,8 @@ public class CaptureModule implements CameraModule, PhotoController, stopBackgroundThread(); mLastJpegData = null; setProModeVisible(); + mJpegImageData = null; + closeVideoFileDescriptor(); } @Override @@ -2173,7 +2256,13 @@ public class CaptureModule implements CameraModule, PhotoController, String scene = mSettingsManager.getValue(SettingsManager.KEY_SCENE_MODE); if(isPanoSetting(scene)) { - mActivity.onModuleSelected(ModuleSwitcher.PANOCAPTURE_MODULE_INDEX); + if (mIntentMode != CaptureModule.INTENT_MODE_NORMAL) { + mSettingsManager.setValue( + SettingsManager.KEY_SCENE_MODE, ""+SettingsManager.SCENE_MODE_AUTO_INT); + showToast("Pano Capture is not supported in this mode"); + } else { + mActivity.onModuleSelected(ModuleSwitcher.PANOCAPTURE_MODULE_INDEX); + } } } @@ -2304,7 +2393,99 @@ public class CaptureModule implements CameraModule, PhotoController, @Override public void onCaptureDone() { + if (mPaused) { + return; + } + byte[] data = mJpegImageData; + + if (mCropValue == null) { + // First handle the no crop case -- just return the value. If the + // caller specifies a "save uri" then write the data to its + // stream. Otherwise, pass back a scaled down version of the bitmap + // directly in the extras. + if (mSaveUri != null) { + OutputStream outputStream = null; + try { + outputStream = mContentResolver.openOutputStream(mSaveUri); + outputStream.write(data); + outputStream.close(); + + mActivity.setResultEx(Activity.RESULT_OK); + mActivity.finish(); + } catch (IOException ex) { + // ignore exception + } finally { + CameraUtil.closeSilently(outputStream); + } + } else { + ExifInterface exif = Exif.getExif(data); + int orientation = Exif.getOrientation(exif); + Bitmap bitmap = CameraUtil.makeBitmap(data, 50 * 1024); + bitmap = CameraUtil.rotate(bitmap, orientation); + mActivity.setResultEx(Activity.RESULT_OK, + new Intent("inline-data").putExtra("data", bitmap)); + mActivity.finish(); + } + } else { + // Save the image to a temp file and invoke the cropper + Uri tempUri = null; + FileOutputStream tempStream = null; + try { + File path = mActivity.getFileStreamPath(sTempCropFilename); + path.delete(); + tempStream = mActivity.openFileOutput(sTempCropFilename, 0); + tempStream.write(data); + tempStream.close(); + tempUri = Uri.fromFile(path); + } catch (FileNotFoundException ex) { + mActivity.setResultEx(Activity.RESULT_CANCELED); + mActivity.finish(); + return; + } catch (IOException ex) { + mActivity.setResultEx(Activity.RESULT_CANCELED); + mActivity.finish(); + return; + } finally { + CameraUtil.closeSilently(tempStream); + } + + Bundle newExtras = new Bundle(); + if (mCropValue.equals("circle")) { + newExtras.putString("circleCrop", "true"); + } + if (mSaveUri != null) { + newExtras.putParcelable(MediaStore.EXTRA_OUTPUT, mSaveUri); + } else { + newExtras.putBoolean(CameraUtil.KEY_RETURN_DATA, true); + } + if (mActivity.isSecureCamera()) { + newExtras.putBoolean(CameraUtil.KEY_SHOW_WHEN_LOCKED, true); + } + + // TODO: Share this constant. + final String CROP_ACTION = "com.android.camera.action.CROP"; + Intent cropIntent = new Intent(CROP_ACTION); + + cropIntent.setData(tempUri); + cropIntent.putExtras(newExtras); + + mActivity.startActivityForResult(cropIntent, REQUEST_CROP); + } + } + + public void onRecordingDone(boolean valid) { + Intent resultIntent = new Intent(); + int resultCode; + if (valid) { + resultCode = Activity.RESULT_OK; + resultIntent.setData(mCurrentVideoUri); + resultIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } else { + resultCode = Activity.RESULT_CANCELED; + } + mActivity.setResultEx(resultCode, resultIntent); + mActivity.finish(); } @Override @@ -3012,6 +3193,14 @@ public class CaptureModule implements CameraModule, PhotoController, mUI.enableShutter(true); mIsRecordingVideo = false; + if (mIntentMode == INTENT_MODE_VIDEO) { + if (isQuickCapture()) { + onRecordingDone(true); + } else { + Bitmap thumbnail = getVideoThumbnail(); + mUI.showRecordVideoForReview(thumbnail); + } + } if(mFrameProcessor != null) { mFrameProcessor.onOpen(getFrameProcFilterId(), mPreviewSize); @@ -3073,28 +3262,30 @@ public class CaptureModule implements CameraModule, PhotoController, } private void saveVideo() { - File origFile = new File(mVideoFilename); - if (!origFile.exists() || origFile.length() <= 0) { - Log.e(TAG, "Invalid file"); - mCurrentVideoValues = null; - return; - } + if (mVideoFileDescriptor == null) { + File origFile = new File(mVideoFilename); + if (!origFile.exists() || origFile.length() <= 0) { + Log.e(TAG, "Invalid file"); + mCurrentVideoValues = null; + return; + } - long duration = 0L; - MediaMetadataRetriever retriever = new MediaMetadataRetriever(); + long duration = 0L; + MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - try { - retriever.setDataSource(mVideoFilename); - duration = Long.valueOf(retriever.extractMetadata( - MediaMetadataRetriever.METADATA_KEY_DURATION)); - } catch (IllegalArgumentException e) { - Log.e(TAG, "cannot access the file"); - } - retriever.release(); + try { + retriever.setDataSource(mVideoFilename); + duration = Long.valueOf(retriever.extractMetadata( + MediaMetadataRetriever.METADATA_KEY_DURATION)); + } catch (IllegalArgumentException e) { + Log.e(TAG, "cannot access the file"); + } + retriever.release(); - mActivity.getMediaSaveService().addVideo(mVideoFilename, - duration, mCurrentVideoValues, - mOnVideoSavedListener, mContentResolver); + mActivity.getMediaSaveService().addVideo(mVideoFilename, + duration, mCurrentVideoValues, + mOnVideoSavedListener, mContentResolver); + } mCurrentVideoValues = null; } @@ -3102,11 +3293,20 @@ public class CaptureModule implements CameraModule, PhotoController, Log.d(TAG, "setUpMediaRecorder"); String videoSize = mSettingsManager.getValue(SettingsManager.KEY_VIDEO_QUALITY); int size = CameraSettings.VIDEO_QUALITY_TABLE.get(videoSize); + Intent intent = mActivity.getIntent(); + if (intent.hasExtra(MediaStore.EXTRA_VIDEO_QUALITY)) { + int extraVideoQuality = + intent.getIntExtra(MediaStore.EXTRA_VIDEO_QUALITY, 0); + if (extraVideoQuality > 0) { + size = CamcorderProfile.QUALITY_HIGH; + } else { // 0 is mms. + size = CamcorderProfile.QUALITY_LOW; + } + } if (mCaptureTimeLapse) { size = CameraSettings.getTimeLapseQualityFor(size); } - Intent intent = mActivity.getIntent(); Bundle myExtras = intent.getExtras(); if (mMediaRecorder == null) mMediaRecorder = new MediaRecorder(); @@ -3135,9 +3335,26 @@ public class CaptureModule implements CameraModule, PhotoController, mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); mMediaRecorder.setOutputFormat(mProfile.fileFormat); - String fileName = generateVideoFilename(mProfile.fileFormat); - Log.v(TAG, "New video filename: " + fileName); - mMediaRecorder.setOutputFile(fileName); + closeVideoFileDescriptor(); + if (mIntentMode == CaptureModule.INTENT_MODE_VIDEO && myExtras != null) { + Uri saveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); + if (saveUri != null) { + try { + mCurrentVideoUri = saveUri; + mVideoFileDescriptor = + mContentResolver.openFileDescriptor(saveUri, "rw"); + mCurrentVideoUri = saveUri; + } catch (java.io.FileNotFoundException ex) { + // invalid uri + Log.e(TAG, ex.toString()); + } + } + mMediaRecorder.setOutputFile(mVideoFileDescriptor.getFileDescriptor()); + } else { + String fileName = generateVideoFilename(mProfile.fileFormat); + Log.v(TAG, "New video filename: " + fileName); + mMediaRecorder.setOutputFile(fileName); + } mMediaRecorder.setVideoFrameRate(mProfile.videoFrameRate); mMediaRecorder.setVideoEncodingBitRate(mProfile.videoBitRate); if(mFrameProcessor.isFrameFilterEnabled()) { @@ -4168,6 +4385,55 @@ public class CaptureModule implements CameraModule, PhotoController, .KEY_CAMERA_SAVEPATH).equals("1")); } + public void startPlayVideoActivity() { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(mCurrentVideoUri, + CameraUtil.convertOutputFormatToMimeType(mProfile.fileFormat)); + try { + mActivity + .startActivityForResult(intent, CameraActivity.REQ_CODE_DONT_SWITCH_TO_PREVIEW); + } catch (ActivityNotFoundException ex) { + Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex); + } + } + + private void closeVideoFileDescriptor() { + if (mVideoFileDescriptor != null) { + try { + mVideoFileDescriptor.close(); + } catch (IOException e) { + Log.e(TAG, "Fail to close fd", e); + } + mVideoFileDescriptor = null; + } + } + + private Bitmap getVideoThumbnail() { + Bitmap bitmap = null; + if (mVideoFileDescriptor != null) { + bitmap = Thumbnail.createVideoThumbnailBitmap(mVideoFileDescriptor.getFileDescriptor(), + mVideoPreviewSize.getWidth()); + } else if (mCurrentVideoUri != null) { + try { + mVideoFileDescriptor = mContentResolver.openFileDescriptor(mCurrentVideoUri, "r"); + bitmap = Thumbnail.createVideoThumbnailBitmap( + mVideoFileDescriptor.getFileDescriptor(), mVideoPreviewSize.getWidth()); + } catch (java.io.FileNotFoundException ex) { + // invalid uri + Log.e(TAG, ex.toString()); + } + } + + if (bitmap != null) { + // MetadataRetriever already rotates the thumbnail. We should rotate + // it to match the UI orientation (and mirror if it is front-facing camera). + Camera.CameraInfo[] info = CameraHolder.instance().getCameraInfo(); + boolean mirror = mPostProcessor.isSelfieMirrorOn(); + bitmap = CameraUtil.rotateAndMirror(bitmap, 0, mirror); + } + return bitmap; + } + private void deleteVideoFile(String fileName) { Log.v(TAG, "Deleting video " + fileName); File f = new File(fileName); diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java old mode 100644 new mode 100755 index 1cb7d7510..8bbbf1753 --- a/src/com/android/camera/CaptureUI.java +++ b/src/com/android/camera/CaptureUI.java @@ -20,17 +20,23 @@ package com.android.camera; import android.animation.Animator; +import android.app.Activity; import android.app.AlertDialog; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; +import android.graphics.Bitmap; import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.AnimationDrawable; import android.hardware.Camera.Face; +import android.os.AsyncTask; import android.preference.PreferenceManager; import android.renderscript.Allocation; import android.renderscript.Element; @@ -196,6 +202,16 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, private ImageView mSceneModeLabelCloseIcon; private AlertDialog mSceneModeInstructionalDialog = null; + private ImageView mCancelButton; + private View mReviewCancelButton; + private View mReviewDoneButton; + private View mReviewRetakeButton; + private View mReviewPlayButton; + private FrameLayout mPreviewLayout; + private ImageView mReviewImage; + private int mDownSampleFactor = 4; + private DecodeImageForReview mDecodeTaskForReview = null; + int mPreviewWidth; int mPreviewHeight; private boolean mIsVideoUI = false; @@ -204,11 +220,13 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, private void previewUIReady() { if((mSurfaceHolder != null && mSurfaceHolder.getSurface().isValid())) { mModule.onPreviewUIReady(); - if (mIsVideoUI && mThumbnail != null) { + if ((mIsVideoUI || mModule.getCurrentIntentMode() != CaptureModule.INTENT_MODE_NORMAL) + && mThumbnail != null){ mThumbnail.setVisibility(View.INVISIBLE); mThumbnail = null; mActivity.updateThumbnail(mThumbnail); - } else if (!mIsVideoUI){ + } else if (!mIsVideoUI && + mModule.getCurrentIntentMode() == CaptureModule.INTENT_MODE_NORMAL){ if (mThumbnail == null) mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb); mActivity.updateThumbnail(mThumbnail); @@ -361,6 +379,56 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, mCameraControls = (OneUICameraControls) mRootView.findViewById(R.id.camera_controls); mFaceView = (Camera2FaceView) mRootView.findViewById(R.id.face_view); + mCancelButton = (ImageView) mRootView.findViewById(R.id.cancel_button); + int intentMode = mModule.getCurrentIntentMode(); + if (intentMode != CaptureModule.INTENT_MODE_NORMAL) { + mCameraControls.setIntentMode(intentMode); + mCameraControls.setVideoMode(false); + mCancelButton.setVisibility(View.VISIBLE); + mReviewCancelButton = mRootView.findViewById(R.id.preview_btn_cancel); + mReviewDoneButton = mRootView.findViewById(R.id.preview_btn_done); + mReviewRetakeButton = mRootView.findViewById(R.id.preview_btn_retake); + mReviewPlayButton = mRootView.findViewById(R.id.preview_play); + mPreviewLayout = (FrameLayout)mRootView.findViewById(R.id.preview_of_intent); + mReviewImage = (ImageView)mRootView.findViewById(R.id.preview_content); + mReviewCancelButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mActivity.setResultEx(Activity.RESULT_CANCELED, new Intent()); + mActivity.finish(); + } + }); + mReviewRetakeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mPreviewLayout.setVisibility(View.GONE); + mReviewImage.setImageBitmap(null); + } + }); + mReviewDoneButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (intentMode == CaptureModule.INTENT_MODE_CAPTURE) { + mModule.onCaptureDone(); + } else if (intentMode == CaptureModule.INTENT_MODE_VIDEO) { + mModule.onRecordingDone(true); + } + } + }); + mReviewPlayButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mModule.startPlayVideoActivity(); + } + }); + mCancelButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + mModule.cancelCapture(); + } + }); + } + mActivity.getWindowManager().getDefaultDisplay().getSize(mDisplaySize); mScreenRatio = CameraUtil.determineRatio(mDisplaySize.x, mDisplaySize.y); if (mScreenRatio == CameraUtil.RATIO_16_9) { @@ -405,6 +473,22 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, showFirstTimeHelp(); } + protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) { + mDecodeTaskForReview = new CaptureUI.DecodeImageForReview(jpegData, orientation, mirror); + mDecodeTaskForReview.execute(); + mPreviewLayout.setVisibility(View.VISIBLE); + CameraUtil.fadeIn(mReviewDoneButton); + CameraUtil.fadeIn(mReviewRetakeButton); + } + + protected void showRecordVideoForReview(Bitmap preview) { + mReviewImage.setImageBitmap(preview); + mPreviewLayout.setVisibility(View.VISIBLE); + mReviewPlayButton.setVisibility(View.VISIBLE); + CameraUtil.fadeIn(mReviewDoneButton); + CameraUtil.fadeIn(mReviewRetakeButton); + } + private void toggleMakeup() { String value = mSettingsManager.getValue(SettingsManager.KEY_MAKEUP); if(value != null && !mIsVideoUI) { @@ -471,16 +555,25 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, public void initializeProMode(boolean promode) { mCameraControls.setProMode(promode); - if (promode) mVideoButton.setVisibility(View.INVISIBLE); - else mVideoButton.setVisibility(View.VISIBLE); + if (promode) + mVideoButton.setVisibility(View.INVISIBLE); + else if (mModule.getCurrentIntentMode() == CaptureModule.INTENT_MODE_NORMAL) + mVideoButton.setVisibility(View.VISIBLE); } // called from onResume but only the first time public void initializeFirstTime() { // Initialize shutter button. + int intentMode = mModule.getCurrentIntentMode(); + if (intentMode == CaptureModule.INTENT_MODE_CAPTURE) { + mVideoButton.setVisibility(View.INVISIBLE); + } else if (intentMode == CaptureModule.INTENT_MODE_VIDEO) { + mShutterButton.setVisibility(View.INVISIBLE); + } else { + mShutterButton.setVisibility(View.VISIBLE); + mVideoButton.setVisibility(View.VISIBLE); + } mShutterButton.setOnShutterButtonListener(mModule); - mShutterButton.setVisibility(View.VISIBLE); - mVideoButton.setVisibility(View.VISIBLE); mShutterButton.setImageResource(R.drawable.one_ui_shutter_anim); mShutterButton.setOnClickListener(new View.OnClickListener() { @Override @@ -531,6 +624,9 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, } public void openSettingsMenu() { + if (mPreviewLayout.getVisibility() == View.VISIBLE) { + return; + } clearFocus(); removeFilterMenu(false); Intent intent = new Intent(mActivity, SettingsActivity.class); @@ -1011,6 +1107,9 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, mActivity.gotoGallery(); } }); + if (mModule.getCurrentIntentMode() != CaptureModule.INTENT_MODE_NORMAL) { + mCameraControls.setIntentMode(mModule.getCurrentIntentMode()); + } } public void doShutterAnimation() { @@ -1599,6 +1698,54 @@ public class CaptureUI implements FocusOverlayManager.FocusUI, } } + private class DecodeTask extends AsyncTask { + private final byte [] mData; + private int mOrientation; + private boolean mMirror; + + public DecodeTask(byte[] data, int orientation, boolean mirror) { + mData = data; + mOrientation = orientation; + mMirror = mirror; + } + + @Override + protected Bitmap doInBackground(Void... params) { + Bitmap bitmap = CameraUtil.downSample(mData, mDownSampleFactor); + // Decode image in background. + if ((mOrientation != 0 || mMirror) && (bitmap != null)) { + Matrix m = new Matrix(); + if (mMirror) { + // Flip horizontally + m.setScale(-1f, 1f); + } + m.preRotate(mOrientation); + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m, + false); + } + return bitmap; + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + } + } + + private class DecodeImageForReview extends CaptureUI.DecodeTask { + public DecodeImageForReview(byte[] data, int orientation, boolean mirror) { + super(data, orientation, mirror); + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + if (isCancelled()) { + return; + } + mReviewImage.setImageBitmap(bitmap); + mReviewImage.setVisibility(View.VISIBLE); + mDecodeTaskForReview = null; + } + } public ImageView getVideoButton() { return mVideoButton; diff --git a/src/com/android/camera/imageprocessor/PostProcessor.java b/src/com/android/camera/imageprocessor/PostProcessor.java old mode 100644 new mode 100755 index 8e6caa953..637e5ba29 --- a/src/com/android/camera/imageprocessor/PostProcessor.java +++ b/src/com/android/camera/imageprocessor/PostProcessor.java @@ -363,6 +363,7 @@ public class PostProcessor{ } public boolean takeZSLPicture() { + mController.setJpegImageData(null); ZSLQueue.ImageItem imageItem = mZSLQueue.tryToGetMatchingItem(); if(mController.getPreviewCaptureResult() == null || mController.getPreviewCaptureResult().get(CaptureResult.CONTROL_AE_STATE) == CameraMetadata.CONTROL_AE_STATE_FLASH_REQUIRED) { @@ -965,6 +966,16 @@ public class PostProcessor{ mOrientation, null, mediaSavedListener, contentResolver, "jpeg"); } bytes = nv21ToJpeg(resultImage, mOrientation, waitForMetaData(0)); + if (mController.getCurrentIntentMode() == + CaptureModule.INTENT_MODE_CAPTURE) { + mController.setJpegImageData(bytes); + if (mController.isQuickCapture()) { + mController.onCaptureDone(); + } else { + mController.showCapturedReview( + bytes, mOrientation, isSelfieMirrorOn()); + } + } mActivity.getMediaSaveService().addImage( bytes, title, date, null, resultImage.outRoi.width(), resultImage.outRoi.height(), mOrientation, null, mediaSavedListener, contentResolver, "jpeg"); @@ -1031,11 +1042,21 @@ public class PostProcessor{ image.getPlanes()[0].getBuffer().get(bytes, 0, size); ExifInterface exif = Exif.getExif(bytes); int orientation = Exif.getOrientation(exif); - mActivity.getMediaSaveService().addImage( - bytes, title, date, null, image.getCropRect().width(), image.getCropRect().height(), - orientation, null, mController.getMediaSavedListener(), mActivity.getContentResolver(), "jpeg"); - mController.updateThumbnailJpegData(bytes); - image.close(); + if (mController.getCurrentIntentMode() != CaptureModule.INTENT_MODE_NORMAL) { + mController.setJpegImageData(bytes); + if (mController.isQuickCapture()) { + mController.onCaptureDone(); + } else { + mController.showCapturedReview(bytes, + orientation, isSelfieMirrorOn()); + } + } else { + mActivity.getMediaSaveService().addImage( + bytes, title, date, null, image.getCropRect().width(), image.getCropRect().height(), + orientation, null, mController.getMediaSavedListener(), mActivity.getContentResolver(), "jpeg"); + mController.updateThumbnailJpegData(bytes); + image.close(); + } } }); } diff --git a/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java b/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java old mode 100644 new mode 100755 index fcb4a4900..bf1852450 --- a/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java +++ b/src/com/android/camera/imageprocessor/filter/BestpictureFilter.java @@ -220,6 +220,9 @@ public class BestpictureFilter implements ImageFilter { @Override public boolean isSupported() { + if (mModule.getCurrentIntentMode() != CaptureModule.INTENT_MODE_NORMAL) { + return false; + } return mIsSupported; } diff --git a/src/com/android/camera/ui/OneUICameraControls.java b/src/com/android/camera/ui/OneUICameraControls.java index 3dce60d22..866bf6056 100755 --- a/src/com/android/camera/ui/OneUICameraControls.java +++ b/src/com/android/camera/ui/OneUICameraControls.java @@ -34,6 +34,7 @@ import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; +import com.android.camera.CaptureModule; import com.android.camera.Storage; import com.android.camera.imageprocessor.filter.BeautificationFilter; @@ -57,6 +58,7 @@ public class OneUICameraControls extends RotatableLayout { private View mMakeupSeekBarLowText; private View mMakeupSeekBarHighText; private View mMakeupSeekBarLayout; + private View mCancelButton; private ViewGroup mProModeLayout; private View mProModeCloseButton; @@ -85,6 +87,7 @@ public class OneUICameraControls extends RotatableLayout { private int mBottomLargeSize; private int mBottomSmallSize; + private int mIntentMode = CaptureModule.INTENT_MODE_NORMAL; private ProMode mProMode; private ImageView mExposureIcon; private ImageView mManualIcon; @@ -125,6 +128,14 @@ public class OneUICameraControls extends RotatableLayout { this(context, null); } + public void setIntentMode(int mode) { + mIntentMode = mode; + } + + public int getIntentMode() { + return mIntentMode; + } + @Override public void onFinishInflate() { super.onFinishInflate(); @@ -145,6 +156,7 @@ public class OneUICameraControls extends RotatableLayout { mFilterModeSwitcher = findViewById(R.id.filter_mode_switcher); mRemainingPhotos = (LinearLayout) findViewById(R.id.remaining_photos); mRemainingPhotosText = (TextView) findViewById(R.id.remaining_photos_text); + mCancelButton = findViewById(R.id.cancel_button); mProModeLayout = (ViewGroup) findViewById(R.id.pro_mode_layout); mProModeCloseButton = findViewById(R.id.promode_close_button); @@ -225,15 +237,14 @@ public class OneUICameraControls extends RotatableLayout { mViews = new View[]{ mSceneModeSwitcher, mFilterModeSwitcher, mFrontBackSwitcher, mTsMakeupSwitcher, mFlashButton, mShutter, mPreview, mVideoShutter, - mPauseButton + mPauseButton, mCancelButton }; mBottomLargeSize = getResources().getDimensionPixelSize( R.dimen.one_ui_bottom_large); mBottomSmallSize = getResources().getDimensionPixelSize( R.dimen.one_ui_bottom_small); if(!BeautificationFilter.isSupportedStatic()) { - mTsMakeupSwitcher.setVisibility(View.GONE); - mTsMakeupSwitcher = null; + mTsMakeupSwitcher.setEnabled(false); } } @@ -333,9 +344,17 @@ public class OneUICameraControls extends RotatableLayout { setLocation(mFrontBackSwitcher, true, 2); setLocation(mTsMakeupSwitcher, true, 3); setLocation(mFlashButton, true, 4); - setLocation(mPreview, false, 0); - setLocation(mShutter, false, 2); - setLocation(mVideoShutter, false, 3.15f); + if (mIntentMode == CaptureModule.INTENT_MODE_CAPTURE) { + setLocation(mShutter, false, 2); + setLocation(mCancelButton, false, 0.85f); + } else if (mIntentMode == CaptureModule.INTENT_MODE_VIDEO) { + setLocation(mVideoShutter, false, 2); + setLocation(mCancelButton, false, 0.85f); + } else { + setLocation(mShutter, false, 2); + setLocation(mPreview, false, 0); + setLocation(mVideoShutter, false, 3.15f); + } } setLocationCustomBottom(mMakeupSeekBarLayout, 0, 1); setLocation(mProModeCloseButton, false, 4); @@ -411,8 +430,14 @@ public class OneUICameraControls extends RotatableLayout { setBottomButtionSize(mVideoShutter, mBottomLargeSize, mBottomLargeSize); setBottomButtionSize(mShutter, mBottomSmallSize, mBottomSmallSize); } else { - setBottomButtionSize(mShutter, mBottomLargeSize, mBottomLargeSize); - setBottomButtionSize(mVideoShutter, mBottomSmallSize, mBottomSmallSize); + if (mIntentMode == CaptureModule.INTENT_MODE_CAPTURE) { + setBottomButtionSize(mShutter, mBottomLargeSize, mBottomLargeSize); + } else if (mIntentMode == CaptureModule.INTENT_MODE_VIDEO) { + setBottomButtionSize(mVideoShutter, mBottomLargeSize, mBottomLargeSize); + } else { + setBottomButtionSize(mShutter, mBottomLargeSize, mBottomLargeSize); + setBottomButtionSize(mVideoShutter, mBottomSmallSize, mBottomSmallSize); + } } } -- cgit v1.2.3