diff options
Diffstat (limited to 'src/com/android/camera/VideoCamera.java')
-rw-r--r-- | src/com/android/camera/VideoCamera.java | 319 |
1 files changed, 141 insertions, 178 deletions
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java index 0d6e74d..11d1a4e 100644 --- a/src/com/android/camera/VideoCamera.java +++ b/src/com/android/camera/VideoCamera.java @@ -19,14 +19,11 @@ package com.android.camera; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import android.app.Activity; -import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; @@ -34,21 +31,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; +import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffXfermode; -import android.graphics.RectF; -import android.graphics.drawable.ColorDrawable; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; -import android.graphics.drawable.TransitionDrawable; import android.location.LocationManager; -import android.media.MediaMetadataRetriever; import android.media.MediaRecorder; import android.net.Uri; import android.os.Bundle; @@ -67,7 +53,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.SurfaceHolder; import android.view.View; -import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.view.WindowManager; import android.view.MenuItem.OnMenuItemClickListener; @@ -84,8 +69,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, private static final boolean DEBUG = true; private static final boolean DEBUG_SUPPRESS_AUDIO_RECORDING = DEBUG && false; - private static final boolean DEBUG_DO_NOT_REUSE_MEDIA_RECORDER = DEBUG && true; - private static final boolean DEBUG_LOG_APP_LIFECYCLE = DEBUG && false; private static final int CLEAR_SCREEN_DELAY = 4; private static final int UPDATE_RECORD_TIME = 5; @@ -114,14 +97,13 @@ public class VideoCamera extends Activity implements View.OnClickListener, private static final float VIDEO_ASPECT_RATIO = 176.0f / 144.0f; VideoPreview mVideoPreview; SurfaceHolder mSurfaceHolder = null; - ImageView mBlackout = null; ImageView mVideoFrame; - Bitmap mVideoFrameBitmap; - private TransitionDrawable mThumbnailTransition; - private Drawable[] mThumbnails; - private boolean mShouldTransitionThumbnails; + + private boolean mIsVideoCaptureIntent; + // mLastPictureButton and mThumbController + // are non-null only if isVideoCaptureIntent() is true; private ImageView mLastPictureButton; - private Bitmap mLastPictureThumb; + private ThumbnailController mThumbController; private static final int MAX_RECORDING_DURATION_MS = 10 * 60 * 1000; @@ -268,9 +250,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, /** Called with the activity is first created. */ @Override public void onCreate(Bundle icicle) { - if (DEBUG_LOG_APP_LIFECYCLE) { - Log.v(TAG, "onCreate " + this.hashCode()); - } super.onCreate(icicle); mLocationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); @@ -292,9 +271,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, holder.addCallback(this); holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); - mBlackout = (ImageView) findViewById(R.id.blackout); - mBlackout.setBackgroundDrawable(new ColorDrawable(0xFF000000)); - mPostPictureAlert = findViewById(R.id.post_picture_panel); int[] ids = new int[]{R.id.play, R.id.share, R.id.discard, @@ -307,8 +283,15 @@ public class VideoCamera extends Activity implements View.OnClickListener, mShutterButton.setOnShutterButtonListener(this); mRecordingTimeView = (TextView) findViewById(R.id.recording_time); mVideoFrame = (ImageView) findViewById(R.id.video_frame); - mLastPictureButton = (ImageView) findViewById(R.id.last_picture_button); - mLastPictureButton.setOnClickListener(this); + mIsVideoCaptureIntent = isVideoCaptureIntent(); + if (!mIsVideoCaptureIntent) { + mLastPictureButton = (ImageView) findViewById(R.id.last_picture_button); + mLastPictureButton.setOnClickListener(this); + Drawable frame = getResources().getDrawable(R.drawable.frame_thumbnail); + mThumbController = new ThumbnailController(mLastPictureButton, + frame, mContentResolver); + mThumbController.loadData(ImageManager.getLastVideoThumbPath()); + } } private void startShareVideoActivity() { @@ -359,7 +342,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, } case R.id.last_picture_button: { - stopPreviewAndShowAlert(); + stopVideoRecordingAndShowAlert(); break; } } @@ -373,15 +356,18 @@ public class VideoCamera extends Activity implements View.OnClickListener, switch (button.getId()) { case R.id.shutter_button: if (mMediaRecorderRecording) { - if (isVideoCaptureIntent()) { + if (mIsVideoCaptureIntent) { stopVideoRecordingAndShowAlert(); } else { - stopVideoRecordingAndShowThumbnail(); - doStartCaptureMode(); + stopVideoRecordingAndGetThumbnail(); + initializeVideo(); + } + } else if (isAlertVisible()) { + if (mIsVideoCaptureIntent) { + discardCurrentVideoAndStartPreview(); + } else { + hideAlertAndStartVideoRecording(); } - } else if (mVideoFrame.getVisibility() == View.VISIBLE) { - doStartCaptureMode(); - startVideoRecording(); } else { startVideoRecording(); } @@ -389,14 +375,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } - private void doStartCaptureMode() { - if (isVideoCaptureIntent()) { - discardCurrentVideoAndStartPreview(); - } else { - hideVideoFrameAndStartPreview(); - } - } - private void doPlayCurrentVideo() { Log.e(TAG, "Playing current video: " + mCurrentVideoUri); Intent intent = new Intent(Intent.ACTION_VIEW, mCurrentVideoUri); @@ -409,7 +387,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, private void discardCurrentVideoAndStartPreview() { deleteCurrentVideo(); - hideVideoFrameAndStartPreview(); + hideAlertAndStartPreview(); } private OnScreenHint mStorageHint; @@ -452,9 +430,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, @Override public void onResume() { - if (DEBUG_LOG_APP_LIFECYCLE) { - Log.v(TAG, "onResume " + this.hashCode()); - } super.onResume(); setScreenTimeoutLong(); @@ -477,40 +452,40 @@ public class VideoCamera extends Activity implements View.OnClickListener, } }, 200); - mBlackout.setVisibility(View.INVISIBLE); - if (mVideoFrameBitmap == null) { - initializeVideo(); - } else { - showVideoFrame(); - } + initializeVideo(); } @Override public void onStop() { - if (DEBUG_LOG_APP_LIFECYCLE) { - Log.v(TAG, "onStop " + this.hashCode()); - } - stopVideoRecording(); setScreenTimeoutSystemDefault(); super.onStop(); } @Override protected void onPause() { - if (DEBUG_LOG_APP_LIFECYCLE) { - Log.v(TAG, "onPause " + this.hashCode()); - } super.onPause(); - stopVideoRecording(); - hideVideoFrame(); + // This is similar to what mShutterButton.performClick() does, + // but not quite the same. + if (mMediaRecorderRecording) { + if (mIsVideoCaptureIntent) { + stopVideoRecordingAndShowAlert(); + } else { + stopVideoRecordingAndGetThumbnail(); + } + } else { + stopVideoRecording(); + } mPausing = true; unregisterReceiver(mReceiver); - mBlackout.setVisibility(View.VISIBLE); setScreenTimeoutSystemDefault(); + if (!mIsVideoCaptureIntent) { + mThumbController.storeData(ImageManager.getLastVideoThumbPath()); + } + if (mStorageHint != null) { mStorageHint.cancel(); mStorageHint = null; @@ -526,8 +501,8 @@ public class VideoCamera extends Activity implements View.OnClickListener, if (mMediaRecorderRecording) { mShutterButton.performClick(); return true; - } else if(isPostRecordingAlertVisible()) { - hideVideoFrameAndStartPreview(); + } else if(isAlertVisible()) { + hideAlertAndStartPreview(); return true; } break; @@ -599,7 +574,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); - if (isVideoCaptureIntent()) { + if (mIsVideoCaptureIntent) { // No options menu for attach mode. return false; } else { @@ -685,14 +660,18 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } + // initializeVideo() starts preview and prepare media recorder. // Returns false if initializeVideo fails private boolean initializeVideo() { Log.v(TAG, "initializeVideo"); - boolean isCaptureIntent = isVideoCaptureIntent(); + + // We will call initializeVideo() again when the alert is hidden. + if (isAlertVisible()) return false; + Intent intent = getIntent(); Bundle myExtras = intent.getExtras(); - if (isCaptureIntent && myExtras != null) { + if (mIsVideoCaptureIntent && myExtras != null) { Uri saveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT); if (saveUri != null) { try { @@ -782,6 +761,15 @@ public class VideoCamera extends Activity implements View.OnClickListener, return false; } mMediaRecorderRecording = false; + + if (!mIsVideoCaptureIntent && !mThumbController.isUriValid()) { + updateLastVideo(); + } + + if (!mIsVideoCaptureIntent) { + mThumbController.updateDisplayIfNeeded(); + } + return true; } @@ -795,25 +783,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } - private void restartPreview() { - if (DEBUG_DO_NOT_REUSE_MEDIA_RECORDER) { - Log.v(TAG, "DEBUG_DO_NOT_REUSE_MEDIA_RECORDER recreating mMediaRecorder."); - initializeVideo(); - } else { - try { - mMediaRecorder.prepare(); - } catch (IOException exception) { - Log.e(TAG, "prepare failed for " + mCameraVideoFilename); - releaseMediaRecorder(); - // TODO: add more exception handling logic here - } - } - if (mShouldTransitionThumbnails) { - mShouldTransitionThumbnails = false; - mThumbnailTransition.startTransition(500); - } - } - private int getIntPreference(String key, int defaultValue) { String s = mPreferences.getString(key, ""); int result = defaultValue; @@ -982,7 +951,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, mHandler.sendEmptyMessage(UPDATE_RECORD_TIME); setScreenTimeoutInfinite(); hideLastPictureButton(); - recycleVideoFrameBitmap(); } } @@ -993,37 +961,23 @@ public class VideoCamera extends Activity implements View.OnClickListener, mShutterButton.setImageDrawable(drawable); } - private void stopVideoRecordingAndShowThumbnail() { - Log.v(TAG, "stopVideoRecordingAndShowThumbnail"); - if (mMediaRecorderRecording) { - stopVideoRecording(); - acquireVideoFrame(); - setLastPictureThumb(mVideoFrameBitmap); - showLastPictureButton(); - } + private void stopVideoRecordingAndGetThumbnail() { + stopVideoRecording(); + acquireVideoThumb(); } private void stopVideoRecordingAndShowAlert() { - Log.v(TAG, "stopVideoRecordingAndShowAlert"); - if (mMediaRecorderRecording) { - stopVideoRecording(); - acquireVideoFrame(); - showVideoFrame(); - } - } - - private void stopPreviewAndShowAlert() { stopVideoRecording(); - showVideoFrame(); + showAlert(); } - private void showVideoFrame() { + private void showAlert() { int[] pickIds = {R.id.attach, R.id.cancel}; int[] normalIds = {R.id.gallery, R.id.share, R.id.discard}; int[] alwaysOnIds = {R.id.play}; int[] hideIds = pickIds; int[] connectIds = normalIds; - if (isVideoCaptureIntent()) { + if (mIsVideoCaptureIntent) { hideIds = normalIds; connectIds = pickIds; } @@ -1037,11 +991,31 @@ public class VideoCamera extends Activity implements View.OnClickListener, connectAndFadeIn(connectIds); connectAndFadeIn(alwaysOnIds); hideLastPictureButton(); - mVideoFrame.setVisibility(View.VISIBLE); mPostPictureAlert.setVisibility(View.VISIBLE); + + // There are two cases we are here: + // (1) We are in a capture video intent, and we are reviewing the video + // we just taken. + // (2) The thumbnail button is clicked: we review the video associated + // with the thumbnail. + // For the second case, we copy the associated URI and filename to + // mCurrentVideoUri and mCurrentVideoFilename, so the video frame shown + // and the target for actions (play, delete, ...) will be correct. + + if (!mIsVideoCaptureIntent) { + mCurrentVideoUri = mThumbController.getUri(); + mCurrentVideoFilename = getDataPath(mCurrentVideoUri); + } + + String path = mCurrentVideoFilename; + if (path != null) { + Bitmap videoFrame = ImageManager.createVideoThumbnail(path); + mVideoFrame.setImageBitmap(videoFrame); + mVideoFrame.setVisibility(View.VISIBLE); + } } - private void hideVideoFrame() { + private void hideAlert() { mVideoFrame.setVisibility(View.INVISIBLE); mPostPictureAlert.setVisibility(View.INVISIBLE); showLastPictureButton(); @@ -1053,11 +1027,11 @@ public class VideoCamera extends Activity implements View.OnClickListener, view.setOnClickListener(this); Animation animation = new AlphaAnimation(0F, 1F); animation.setDuration(500); - view.setAnimation(animation); + view.startAnimation(animation); } } - private boolean isPostRecordingAlertVisible() { + private boolean isAlertVisible() { return mPostPictureAlert.getVisibility() == View.VISIBLE; } @@ -1130,82 +1104,71 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } - private void hideVideoFrameAndStartPreview() { - hideVideoFrame(); - restartPreview(); + private void hideAlertAndStartPreview() { + hideAlert(); + initializeVideo(); } - private void acquireVideoFrame() { - recycleVideoFrameBitmap(); - mVideoFrameBitmap = ImageManager.createVideoThumbnail(mCurrentVideoFilename); - mVideoFrame.setImageBitmap(mVideoFrameBitmap); - Log.v(TAG, "acquireVideoFrame:" + mVideoFrameBitmap); + private void hideAlertAndStartVideoRecording() { + hideAlert(); + startVideoRecording(); } - //TODO: Refactor the code so that the following code is shared between - // VideoCamera.java and Camera.java - private static Bitmap makeRoundedCorner(Bitmap thumb, int rx, int ry) { - if (thumb == null) return null; - int width = thumb.getWidth(); - int height = thumb.getHeight(); - - Bitmap result = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(result); - Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - paint.setStyle(Paint.Style.FILL); - canvas.drawRoundRect(new RectF(0, 0, width, height), rx, ry, paint); - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - canvas.drawBitmap(thumb, 0, 0, paint); - return result; + private void acquireVideoThumb() { + Bitmap videoFrame = ImageManager.createVideoThumbnail(mCurrentVideoFilename); + mThumbController.setData(mCurrentVideoUri, videoFrame); } - private void setLastPictureThumb(Bitmap videoFrame) { - - final int PADDING_WIDTH = 6; - final int PADDING_HEIGHT = 6; - LayoutParams layoutParams = mLastPictureButton.getLayoutParams(); - // Make the mini-thumbnail size smaller than the button size so that the image corners - // don't peek out from the rounded corners of the frame_thumbnail graphic: - final int miniThumbWidth = layoutParams.width - 2 * PADDING_WIDTH; - final int miniThumbHeight = layoutParams.height - 2 * PADDING_HEIGHT; - - Bitmap lastPictureThumb = ImageManager.extractMiniThumb(videoFrame, - miniThumbWidth, miniThumbHeight, false); - lastPictureThumb = makeRoundedCorner(lastPictureThumb, 3, 3); - - Drawable[] vignetteLayers = new Drawable[2]; - vignetteLayers[0] = getResources().getDrawable(R.drawable.frame_thumbnail); - if (mThumbnails == null) { - mThumbnails = new Drawable[2]; - mThumbnails[1] = new BitmapDrawable(lastPictureThumb); - vignetteLayers[1] = mThumbnails[1]; - } else { - mThumbnails[0] = mThumbnails[1]; - mThumbnails[1] = new BitmapDrawable(lastPictureThumb); - mThumbnailTransition = new TransitionDrawable(mThumbnails); - mShouldTransitionThumbnails = true; - vignetteLayers[1] = mThumbnailTransition; + private void showLastPictureButton() { + if (!mIsVideoCaptureIntent) { + mLastPictureButton.setVisibility(View.VISIBLE); } + } - LayerDrawable vignette = new LayerDrawable(vignetteLayers); - vignette.setLayerInset(1, PADDING_WIDTH, PADDING_HEIGHT, - PADDING_WIDTH, PADDING_HEIGHT); - mLastPictureButton.setImageDrawable(vignette); + private void hideLastPictureButton() { + if (!mIsVideoCaptureIntent) { + mLastPictureButton.setVisibility(View.INVISIBLE); + } } - private void showLastPictureButton() { - mLastPictureButton.setVisibility(View.VISIBLE); + private static ImageManager.DataLocation dataLocation() { + return ImageManager.DataLocation.EXTERNAL; } - private void hideLastPictureButton() { - mLastPictureButton.setVisibility(View.INVISIBLE); + private void updateLastVideo() { + ImageManager.IImageList list = ImageManager.instance().allImages( + this, + mContentResolver, + dataLocation(), + ImageManager.INCLUDE_VIDEOS, + ImageManager.SORT_ASCENDING, + ImageManager.CAMERA_IMAGE_BUCKET_ID); + int count = list.getCount(); + if (count > 0) { + ImageManager.IImage image = list.getImageAt(count-1); + Uri uri = image.fullSizeImageUri(); + mThumbController.setData(uri, image.miniThumbBitmap()); + } else { + mThumbController.setData(null, null); + } + list.deactivate(); } - private void recycleVideoFrameBitmap() { - if (mVideoFrameBitmap != null) { - mVideoFrame.setImageDrawable(null); - mVideoFrameBitmap.recycle(); - mVideoFrameBitmap = null; + private static final String[] DATA_PATH_PROJECTION = new String[] { + "_data" + }; + + private String getDataPath(Uri uri) { + Cursor c = null; + try { + c = mContentResolver.query(uri, DATA_PATH_PROJECTION, null, null, null); + if (c != null && c.moveToFirst()) { + return c.getString(0); + } else { + return null; + } + } finally { + if (c != null) c.close(); } } } |