summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xres/layout/capture_module.xml53
-rwxr-xr-xres/layout/one_ui_layout.xml20
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/CameraActivity.java3
-rw-r--r--src/com/android/camera/CaptureModule.java328
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/CaptureUI.java159
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/imageprocessor/PostProcessor.java31
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/imageprocessor/filter/BestpictureFilter.java3
-rwxr-xr-xsrc/com/android/camera/ui/OneUICameraControls.java41
8 files changed, 587 insertions, 51 deletions
diff --git a/res/layout/capture_module.xml b/res/layout/capture_module.xml
index 44d5c59c6..84444597b 100755
--- a/res/layout/capture_module.xml
+++ b/res/layout/capture_module.xml
@@ -98,4 +98,57 @@
style="@style/CameraControls"
layout="@layout/menu_help"
android:layout_gravity="center" />
+
+ <FrameLayout
+ android:id="@+id/preview_of_intent"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="@android:color/black"
+ android:visibility="gone">
+ <ImageView
+ android:id="@+id/preview_content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:adjustViewBounds="true"
+ android:scaleType="fitXY"/>
+
+ <ImageView
+ android:id="@+id/preview_play"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/ic_gallery_play_big"
+ android:visibility="gone"
+ android:layout_gravity="center" />
+
+ <com.android.camera.ui.RotatableLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/CameraControls"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_marginBottom="2dip">
+ <com.android.camera.ui.RotateImageView android:id="@+id/preview_btn_done"
+ style="@style/ReviewControlIcon"
+ android:contentDescription="@string/accessibility_review_ok"
+ android:scaleType="center"
+ android:layout_gravity="right|bottom"
+ android:background="@drawable/bg_pressed"
+ android:src="@drawable/ic_menu_done_holo_light" />
+
+ <com.android.camera.ui.RotateImageView android:id="@+id/preview_btn_retake"
+ style="@style/ReviewControlIcon"
+ android:contentDescription="@string/accessibility_review_retake"
+ android:layout_gravity="bottom|center_horizontal"
+ android:scaleType="center"
+ android:focusable="true"
+ android:background="@drawable/bg_pressed"
+ android:src="@drawable/ic_btn_shutter_retake" />
+
+ <com.android.camera.ui.RotateImageView android:id="@+id/preview_btn_cancel"
+ style="@style/ReviewControlIcon"
+ android:contentDescription="@string/accessibility_review_cancel"
+ android:scaleType="center"
+ android:layout_gravity="left|bottom"
+ android:background="@drawable/bg_pressed"
+ android:src="@drawable/ic_menu_cancel_holo_light" />
+ </com.android.camera.ui.RotatableLayout>
+ </FrameLayout>
</merge>
diff --git a/res/layout/one_ui_layout.xml b/res/layout/one_ui_layout.xml
index 53174698c..38322663a 100755
--- a/res/layout/one_ui_layout.xml
+++ b/res/layout/one_ui_layout.xml
@@ -69,6 +69,26 @@
android:src="@drawable/btn_pause_recording"/>
<com.android.camera.ui.RotateImageView
+ android:id="@+id/cancel_button"
+ android:layout_width="@dimen/one_ui_bottom_small"
+ android:layout_height="@dimen/one_ui_bottom_small"
+ android:clickable="true"
+ android:focusable="true"
+ android:scaleType="fitCenter"
+ android:visibility="gone"
+ android:src="@drawable/ic_menu_cancel_holo_light" />
+
+ <com.android.camera.PauseButton
+ android:id="@+id/video_pause"
+ android:layout_width="@dimen/one_ui_bottom_small"
+ android:layout_height="@dimen/one_ui_bottom_small"
+ android:focusable="true"
+ android:clickable="true"
+ android:scaleType="fitCenter"
+ android:visibility="gone"
+ android:src="@drawable/btn_pause_recording"/>
+
+ <com.android.camera.ui.RotateImageView
android:id="@+id/preview_thumb"
android:layout_width="@dimen/capture_size"
android:layout_height="@dimen/capture_size"
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index d3c39793a..fcb410888 100644..100755
--- 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
index 1cb7d7510..8bbbf1753 100644..100755
--- 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<Void, Void, Bitmap> {
+ 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
index 8e6caa953..637e5ba29 100644..100755
--- 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
index fcb4a4900..bf1852450 100644..100755
--- 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);
+ }
}
}