diff options
Diffstat (limited to 'src/com/android/camera/VideoCamera.java')
-rw-r--r-- | src/com/android/camera/VideoCamera.java | 206 |
1 files changed, 156 insertions, 50 deletions
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java index 76e056c..0d6e74d 100644 --- a/src/com/android/camera/VideoCamera.java +++ b/src/com/android/camera/VideoCamera.java @@ -35,8 +35,18 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; 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; @@ -57,6 +67,7 @@ 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; @@ -106,6 +117,11 @@ public class VideoCamera extends Activity implements View.OnClickListener, ImageView mBlackout = null; ImageView mVideoFrame; Bitmap mVideoFrameBitmap; + private TransitionDrawable mThumbnailTransition; + private Drawable[] mThumbnails; + private boolean mShouldTransitionThumbnails; + private ImageView mLastPictureButton; + private Bitmap mLastPictureThumb; private static final int MAX_RECORDING_DURATION_MS = 10 * 60 * 1000; @@ -291,6 +307,8 @@ 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); } private void startShareVideoActivity() { @@ -339,30 +357,38 @@ public class VideoCamera extends Activity implements View.OnClickListener, doPlayCurrentVideo(); break; } + + case R.id.last_picture_button: { + stopPreviewAndShowAlert(); + break; + } } } public void onShutterButtonFocus(ShutterButton button, boolean pressed) { + // Do nothing (everything happens in onShutterButtonClick). + } + + public void onShutterButtonClick(ShutterButton button) { switch (button.getId()) { case R.id.shutter_button: - if (pressed) { - if (mMediaRecorderRecording) { - stopVideoRecordingAndDisplayDialog(); - } else if (mVideoFrame.getVisibility() == View.VISIBLE) { - doStartCaptureMode(); - startVideoRecording(); + if (mMediaRecorderRecording) { + if (isVideoCaptureIntent()) { + stopVideoRecordingAndShowAlert(); } else { - startVideoRecording(); + stopVideoRecordingAndShowThumbnail(); + doStartCaptureMode(); } + } else if (mVideoFrame.getVisibility() == View.VISIBLE) { + doStartCaptureMode(); + startVideoRecording(); + } else { + startVideoRecording(); } break; } } - public void onShutterButtonClick(ShutterButton button) { - // Do nothing (everything happens in onShutterButtonFocus). - } - private void doStartCaptureMode() { if (isVideoCaptureIntent()) { discardCurrentVideoAndStartPreview(); @@ -455,7 +481,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, if (mVideoFrameBitmap == null) { initializeVideo(); } else { - showPostRecordingAlert(); + showVideoFrame(); } } @@ -477,7 +503,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, super.onPause(); stopVideoRecording(); - hidePostPictureAlert(); + hideVideoFrame(); mPausing = true; @@ -498,8 +524,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, switch (keyCode) { case KeyEvent.KEYCODE_BACK: if (mMediaRecorderRecording) { - Log.v(TAG, "onKeyBack"); - stopVideoRecordingAndDisplayDialog(); + mShutterButton.performClick(); return true; } else if(isPostRecordingAlertVisible()) { hideVideoFrameAndStartPreview(); @@ -508,32 +533,19 @@ public class VideoCamera extends Activity implements View.OnClickListener, break; case KeyEvent.KEYCODE_CAMERA: if (event.getRepeatCount() == 0) { - // If we get a dpad center event without any focused view, move the - // focus to the shutter button and press it. - if (mShutterButton.isInTouchMode()) { - mShutterButton.requestFocusFromTouch(); - } else { - mShutterButton.requestFocus(); - } - mShutterButton.setPressed(true); + mShutterButton.performClick(); return true; } - return true; + break; case KeyEvent.KEYCODE_DPAD_CENTER: if (event.getRepeatCount() == 0) { - // If we get a dpad center event without any focused view, move the - // focus to the shutter button and press it. - if (mShutterButton.isInTouchMode()) { - mShutterButton.requestFocusFromTouch(); - } else { - mShutterButton.requestFocus(); - } - mShutterButton.setPressed(true); + mShutterButton.performClick(); + return true; } break; case KeyEvent.KEYCODE_MENU: if (mMediaRecorderRecording) { - stopVideoRecordingAndDisplayDialog(); + mShutterButton.performClick(); return true; } break; @@ -748,6 +760,19 @@ public class VideoCamera extends Activity implements View.OnClickListener, mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); } mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); + + long remaining = getAvailableStorage(); + // remaining >= LOW_STORAGE_THRESHOLD at this point, reserve a quarter + // of that to make it more likely that recording can complete successfully. + try { + mMediaRecorder.setMaxFileSize(remaining - LOW_STORAGE_THRESHOLD / 4); + } catch (RuntimeException exception) { + // We are going to ignore failure of setMaxFileSize here, as + // a) The composer selected may simply not support it, or + // b) The underlying media framework may not handle 64-bit range + // on the size restriction. + } + try { mMediaRecorder.prepare(); } catch (IOException exception) { @@ -783,6 +808,10 @@ public class VideoCamera extends Activity implements View.OnClickListener, // TODO: add more exception handling logic here } } + if (mShouldTransitionThumbnails) { + mShouldTransitionThumbnails = false; + mThumbnailTransition.startTransition(500); + } } private int getIntPreference(String key, int defaultValue) { @@ -843,6 +872,7 @@ public class VideoCamera extends Activity implements View.OnClickListener, mContentResolver.delete(mCurrentVideoUri, null, null); mCurrentVideoUri = null; } + updateAndShowStorageHint(true); } private void deleteVideoFile(String fileName) { @@ -899,7 +929,10 @@ public class VideoCamera extends Activity implements View.OnClickListener, // from MediaRecorder.OnInfoListener public void onInfo(MediaRecorder mr, int what, int extra) { if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) { - stopVideoRecordingAndDisplayDialog(); + mShutterButton.performClick(); + } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) { + mShutterButton.performClick(); + updateAndShowStorageHint(true); } } @@ -948,6 +981,8 @@ public class VideoCamera extends Activity implements View.OnClickListener, mRecordingTimeView.setVisibility(View.VISIBLE); mHandler.sendEmptyMessage(UPDATE_RECORD_TIME); setScreenTimeoutInfinite(); + hideLastPictureButton(); + recycleVideoFrameBitmap(); } } @@ -958,16 +993,31 @@ public class VideoCamera extends Activity implements View.OnClickListener, mShutterButton.setImageDrawable(drawable); } - private void stopVideoRecordingAndDisplayDialog() { - Log.v(TAG, "stopVideoRecordingAndDisplayDialog"); + private void stopVideoRecordingAndShowThumbnail() { + Log.v(TAG, "stopVideoRecordingAndShowThumbnail"); if (mMediaRecorderRecording) { stopVideoRecording(); - acquireAndShowVideoFrame(); - showPostRecordingAlert(); + acquireVideoFrame(); + setLastPictureThumb(mVideoFrameBitmap); + showLastPictureButton(); } } - private void showPostRecordingAlert() { + private void stopVideoRecordingAndShowAlert() { + Log.v(TAG, "stopVideoRecordingAndShowAlert"); + if (mMediaRecorderRecording) { + stopVideoRecording(); + acquireVideoFrame(); + showVideoFrame(); + } + } + + private void stopPreviewAndShowAlert() { + stopVideoRecording(); + showVideoFrame(); + } + + private void showVideoFrame() { int[] pickIds = {R.id.attach, R.id.cancel}; int[] normalIds = {R.id.gallery, R.id.share, R.id.discard}; int[] alwaysOnIds = {R.id.play}; @@ -986,9 +1036,17 @@ public class VideoCamera extends Activity implements View.OnClickListener, mCurrentVideoFileLength > SHARE_FILE_LENGTH_LIMIT); connectAndFadeIn(connectIds); connectAndFadeIn(alwaysOnIds); + hideLastPictureButton(); + mVideoFrame.setVisibility(View.VISIBLE); mPostPictureAlert.setVisibility(View.VISIBLE); } + private void hideVideoFrame() { + mVideoFrame.setVisibility(View.INVISIBLE); + mPostPictureAlert.setVisibility(View.INVISIBLE); + showLastPictureButton(); + } + private void connectAndFadeIn(int[] connectIds) { for(int id : connectIds) { View view = mPostPictureAlert.findViewById(id); @@ -999,10 +1057,6 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } - private void hidePostPictureAlert() { - mPostPictureAlert.setVisibility(View.INVISIBLE); - } - private boolean isPostRecordingAlertVisible() { return mPostPictureAlert.getVisibility() == View.VISIBLE; } @@ -1077,21 +1131,74 @@ public class VideoCamera extends Activity implements View.OnClickListener, } private void hideVideoFrameAndStartPreview() { - hidePostPictureAlert(); hideVideoFrame(); restartPreview(); } - private void acquireAndShowVideoFrame() { + private void acquireVideoFrame() { recycleVideoFrameBitmap(); mVideoFrameBitmap = ImageManager.createVideoThumbnail(mCurrentVideoFilename); mVideoFrame.setImageBitmap(mVideoFrameBitmap); - mVideoFrame.setVisibility(View.VISIBLE); + Log.v(TAG, "acquireVideoFrame:" + mVideoFrameBitmap); } - private void hideVideoFrame() { - recycleVideoFrameBitmap(); - mVideoFrame.setVisibility(View.GONE); + //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 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; + } + + LayerDrawable vignette = new LayerDrawable(vignetteLayers); + vignette.setLayerInset(1, PADDING_WIDTH, PADDING_HEIGHT, + PADDING_WIDTH, PADDING_HEIGHT); + mLastPictureButton.setImageDrawable(vignette); + } + + private void showLastPictureButton() { + mLastPictureButton.setVisibility(View.VISIBLE); + } + + private void hideLastPictureButton() { + mLastPictureButton.setVisibility(View.INVISIBLE); } private void recycleVideoFrameBitmap() { @@ -1102,4 +1209,3 @@ public class VideoCamera extends Activity implements View.OnClickListener, } } } - |