diff options
Diffstat (limited to 'src/com/android/camera')
-rw-r--r-- | src/com/android/camera/Camera.java | 85 | ||||
-rw-r--r-- | src/com/android/camera/ImageGallery2.java | 27 | ||||
-rwxr-xr-x | src/com/android/camera/ImageManager.java | 24 | ||||
-rw-r--r-- | src/com/android/camera/MenuHelper.java | 11 | ||||
-rw-r--r-- | src/com/android/camera/VideoCamera.java | 206 | ||||
-rw-r--r-- | src/com/android/camera/ViewImage.java | 204 |
6 files changed, 328 insertions, 229 deletions
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java index 1111d0d..8cd1756 100644 --- a/src/com/android/camera/Camera.java +++ b/src/com/android/camera/Camera.java @@ -41,7 +41,12 @@ import android.content.res.AssetFileDescriptor; import android.content.res.Resources; 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.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; @@ -294,7 +299,7 @@ public class Camera extends Activity implements View.OnClickListener, } // We are going to change the size of surface view and show captured - // image. Set it to invisible now and set it back to visible in + // image. Set it to invisible now and set it back to visible in // surfaceChanged() so that users won't see the image is resized on // the screen. mSurfaceView.setVisibility(View.INVISIBLE); @@ -329,7 +334,7 @@ public class Camera extends Activity implements View.OnClickListener, } public void onPictureTaken(byte [] jpegData, android.hardware.Camera camera) { - if (!canHandleCameraEvent()) { + if (mPausing) { return; } if (Config.LOGV) @@ -341,7 +346,9 @@ public class Camera extends Activity implements View.OnClickListener, " RawPictureCallback and JpegPictureCallback."); } - mImageCapture.storeImage(jpegData, camera, mLocation); + if (jpegData != null) { + mImageCapture.storeImage(jpegData, camera, mLocation); + } mStatus = SNAPSHOT_COMPLETED; @@ -379,7 +386,7 @@ public class Camera extends Activity implements View.OnClickListener, } else if (mFocusState == FOCUS_NOT_STARTED) { // User has released the focus key before focus completes. // Do nothing. - } + } updateFocusIndicator(); } }; @@ -587,7 +594,7 @@ public class Camera extends Activity implements View.OnClickListener, } public void onSnap() { - if (!canHandleCameraEvent()) { + if (mPausing) { return; } if (DEBUG_TIME_OPERATIONS) mCaptureStartTime = System.currentTimeMillis(); @@ -618,7 +625,7 @@ public class Camera extends Activity implements View.OnClickListener, mImageCapture.initiate(false); } } - + private void clearLastBitmap() { if (mCaptureOnlyBitmap != null) { mCaptureOnlyBitmap.recycle(); @@ -636,42 +643,56 @@ public class Camera extends Activity implements View.OnClickListener, setLastPictureThumb(lastPictureThumb, uri); } + 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 lastPictureThumb, Uri uri) { - final int PADDING_WIDTH = 2; - final int PADDING_HEIGHT = 2; + 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; - - lastPictureThumb = ImageManager.extractMiniThumb(lastPictureThumb, - miniThumbWidth, miniThumbHeight); + mLastPictureThumb = ImageManager.extractMiniThumb( + lastPictureThumb, miniThumbWidth, miniThumbHeight); + lastPictureThumb = makeRoundedCorner(mLastPictureThumb, 3, 3); Drawable[] vignetteLayers = new Drawable[2]; - vignetteLayers[1] = getResources().getDrawable(R.drawable.frame_thumbnail); + vignetteLayers[0] = getResources().getDrawable(R.drawable.frame_thumbnail); if (mThumbnails == null) { mThumbnails = new Drawable[2]; mThumbnails[1] = new BitmapDrawable(lastPictureThumb); - vignetteLayers[0] = mThumbnails[1]; + vignetteLayers[1] = mThumbnails[1]; } else { mThumbnails[0] = mThumbnails[1]; mThumbnails[1] = new BitmapDrawable(lastPictureThumb); mThumbnailTransition = new TransitionDrawable(mThumbnails); mShouldTransitionThumbnails = true; - vignetteLayers[0] = mThumbnailTransition; + vignetteLayers[1] = mThumbnailTransition; } mVignette = new LayerDrawable(vignetteLayers); - mVignette.setLayerInset(0, PADDING_WIDTH, PADDING_HEIGHT, + mVignette.setLayerInset(1, PADDING_WIDTH, PADDING_HEIGHT, PADDING_WIDTH, PADDING_HEIGHT); mLastPictureButton.setImageDrawable(mVignette); if (mLastPictureButton.getVisibility() != View.VISIBLE) { mShouldShowLastPictureButton = true; } - mLastPictureThumb = lastPictureThumb; mLastPictureUri = uri; } @@ -830,7 +851,7 @@ public class Camera extends Activity implements View.OnClickListener, } private void doAttach() { - if (!canHandleCameraEvent()) { + if (mPausing) { return; } Bitmap bitmap = mImageCapture.getLastBitmap(); @@ -938,14 +959,8 @@ public class Camera extends Activity implements View.OnClickListener, finish(); } - private boolean canHandleCameraEvent() { - // don't handle any shutter event before we have a valid - // imageCapture object. - return mImageCapture != null; - } - public void onShutterButtonFocus(ShutterButton button, boolean pressed) { - if (!canHandleCameraEvent()) { + if (mPausing) { return; } switch (button.getId()) { @@ -956,7 +971,7 @@ public class Camera extends Activity implements View.OnClickListener, } public void onShutterButtonClick(ShutterButton button) { - if (!canHandleCameraEvent()) { + if (mPausing) { return; } switch (button.getId()) { @@ -1143,7 +1158,7 @@ public class Camera extends Activity implements View.OnClickListener, mStorageHint.cancel(); mStorageHint = null; } - + // If we are in an image capture intent and has taken // a picture, we just clear it in onPause. mImageCapture.clearLastBitmap(); @@ -1265,7 +1280,7 @@ public class Camera extends Activity implements View.OnClickListener, private void doSnap() { // If the user has half-pressed the shutter and focus is completed, we // can take the photo right away. - if ((mFocusState == FOCUS_SUCCESS || mFocusState == FOCUS_FAIL) + if ((mFocusState == FOCUS_SUCCESS || mFocusState == FOCUS_FAIL) || !mPreviewing) { // doesn't get set until the idler runs if (mCaptureObject != null) { @@ -1274,8 +1289,8 @@ public class Camera extends Activity implements View.OnClickListener, clearFocusState(); updateFocusIndicator(); } else if (mFocusState == FOCUSING) { - // Half pressing the shutter (i.e. the focus button event) will - // already have requested AF for us, so just request capture on + // Half pressing the shutter (i.e. the focus button event) will + // already have requested AF for us, so just request capture on // focus here. mFocusState = FOCUSING_SNAP_ON_FINISH; } else if (mFocusState == FOCUS_NOT_STARTED) { @@ -1305,7 +1320,7 @@ public class Camera extends Activity implements View.OnClickListener, // if we're creating the surface, start the preview as well. boolean preview = holder.isCreating(); setViewFinder(w, h, preview); - mCaptureObject = mImageCapture; + mCaptureObject = mImageCapture; } public void surfaceCreated(SurfaceHolder holder) { @@ -1331,7 +1346,7 @@ public class Camera extends Activity implements View.OnClickListener, } return mCameraDevice != null; } - + private boolean isLastPictureValid() { boolean isValid = true; if (mLastPictureUri == null) return false; @@ -1344,7 +1359,7 @@ public class Camera extends Activity implements View.OnClickListener, } return isValid; } - + private void updateLastImage() { ImageManager.IImageList list = ImageManager.instance().allImages( this, @@ -1357,7 +1372,7 @@ public class Camera extends Activity implements View.OnClickListener, if (count > 0) { ImageManager.IImage image = list.getImageAt(count-1); mLastPictureUri = image.fullSizeImageUri(); - Log.v(TAG, "updateLastImage: count="+ count + + Log.v(TAG, "updateLastImage: count="+ count + ", lastPictureUri="+mLastPictureUri); setLastPictureThumb(image.miniThumbBitmap(), mLastPictureUri); } else { @@ -1384,7 +1399,7 @@ public class Camera extends Activity implements View.OnClickListener, if (!isImageCaptureIntent() && !isLastPictureValid()) { updateLastImage(); } - + if (mShouldShowLastPictureButton) { mShouldShowLastPictureButton = false; mLastPictureButton.setVisibility(View.VISIBLE); @@ -1530,7 +1545,7 @@ public class Camera extends Activity implements View.OnClickListener, } mPreviewing = false; // If auto focus was in progress, it would have been canceled. - clearFocusState(); + clearFocusState(); } void gotoGallery() { diff --git a/src/com/android/camera/ImageGallery2.java b/src/com/android/camera/ImageGallery2.java index 365be0f..1e02555 100644 --- a/src/com/android/camera/ImageGallery2.java +++ b/src/com/android/camera/ImageGallery2.java @@ -235,8 +235,15 @@ public class ImageGallery2 extends Activity { } }; + private boolean isPaused() { + // Don't process event in pause state. + return mPausing; + } + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { + if (isPaused()) return false; + if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) { mGvs.select(-2, false); // The keyUp doesn't get called when the longpress menu comes up. We only get here when the user @@ -251,13 +258,11 @@ public class ImageGallery2 extends Activity { } return super.onKeyUp(keyCode, event); } - + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - if (mGvs.mCurrentSpec == null) { - // View.onLayout hasn't been called so we can't handle onKeyDown event yet. - return false; - } + if (isPaused()) return false; + boolean handled = true; int sel = mGvs.mCurrentSelection; int columns = mGvs.mCurrentSpec.mColumns; @@ -625,11 +630,12 @@ public class ImageGallery2 extends Activity { @Override public boolean onCreateOptionsMenu(android.view.Menu menu) { MenuItem item; - if (! isPickIntent()) { + if (isPickIntent()) { + MenuHelper.addCapturePictureMenuItems(menu, this); + } else { MenuHelper.addCaptureMenuItems(menu, this); if ((mInclusion & ImageManager.INCLUDE_IMAGES) != 0) { mSlideShowItem = addSlideShowMenu(menu, 5); - } } @@ -851,11 +857,6 @@ public class ImageGallery2 extends Activity { } @Override - public void onShowPress(MotionEvent e) { - super.onShowPress(e); - } - - @Override public boolean onSingleTapUp(MotionEvent e) { select(mCurrentSelection, false); int index = computeSelectedIndex(e); @@ -1746,6 +1747,8 @@ public class ImageGallery2 extends Activity { @Override public boolean onTouchEvent(android.view.MotionEvent ev) { + if (mGallery.isPaused()) return false; + mGestureDetector.onTouchEvent(ev); return true; } diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java index 0b5c850..d7cfc2b 100755 --- a/src/com/android/camera/ImageManager.java +++ b/src/com/android/camera/ImageManager.java @@ -2108,13 +2108,7 @@ public class ImageManager { } if (bitmap != null) { - int degrees = getDegreesRotated(); - if (degrees != 0) { - Matrix m = new Matrix(); - m.setRotate(degrees, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2); - bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), - m, true); - } + bitmap = rotate(bitmap, getDegreesRotated()); } long elapsed = System.currentTimeMillis(); @@ -2328,15 +2322,6 @@ public class ImageManager { if (pfd == null) return null; - try { - InputStream is = mContentResolver.openInputStream(uri); - Log.v(TAG, "available = " + is.available()); - if (is.available() > 5*1024*1024) return null; - is.close(); - } catch (IOException ex) { - return null; - } - if (options == null) options = new BitmapFactory.Options(); @@ -3698,6 +3683,11 @@ public class ImageManager { * @return */ static public Bitmap extractMiniThumb(Bitmap source, int width, int height) { + return extractMiniThumb(source, width, height, true); + } + + static public Bitmap extractMiniThumb(Bitmap source, int width, int height, + boolean recycle) { if (source == null) { return null; } @@ -3713,7 +3703,7 @@ public class ImageManager { Bitmap miniThumbnail = ImageLoader.transform(matrix, source, width, height, false); - if (miniThumbnail != source) { + if (recycle && miniThumbnail != source) { source.recycle(); } return miniThumbnail; diff --git a/src/com/android/camera/MenuHelper.java b/src/com/android/camera/MenuHelper.java index 29bd279..27b057b 100644 --- a/src/com/android/camera/MenuHelper.java +++ b/src/com/android/camera/MenuHelper.java @@ -587,8 +587,7 @@ public class MenuHelper { } } - static void addCaptureMenuItems(Menu menu, final Activity activity) { - + static void addCapturePictureMenuItems(Menu menu, final Activity activity) { menu.add(0, MENU_CAPTURE_PICTURE, 1, R.string.capture_picture) .setOnMenuItemClickListener( new MenuItem.OnMenuItemClickListener() { @@ -604,7 +603,9 @@ public class MenuHelper { } }) .setIcon(android.R.drawable.ic_menu_camera); + } + static void addCaptureVideoMenuItems(Menu menu, final Activity activity) { menu.add(0, MENU_CAPTURE_VIDEO, 2, R.string.capture_video) .setOnMenuItemClickListener( new MenuItem.OnMenuItemClickListener() { @@ -621,6 +622,12 @@ public class MenuHelper { }) .setIcon(R.drawable.ic_menu_camera_video_view); } + + static void addCaptureMenuItems(Menu menu, final Activity activity) { + addCapturePictureMenuItems(menu, activity); + addCaptureVideoMenuItems(menu, activity); + } + static MenuItem addFlipOrientation(Menu menu, final Activity activity, final SharedPreferences prefs) { // position 41 after rotate // D 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, } } } - diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java index 7aacbbb..2e777fd 100644 --- a/src/com/android/camera/ViewImage.java +++ b/src/com/android/camera/ViewImage.java @@ -54,7 +54,9 @@ import com.android.camera.ImageManager.IImage; public class ViewImage extends Activity implements View.OnClickListener { - static final String TAG = "ViewImage"; + private static final String TAG = "ViewImage"; + private static final int TOUCH_AREA_WIDTH = 60; + private ImageGetter mGetter; static final boolean sSlideShowHidesStatusBar = true; @@ -102,7 +104,6 @@ public class ViewImage extends Activity implements View.OnClickListener private Animation mShowNextImageViewAnimation = new AlphaAnimation(0F, 1F); private Animation mShowPrevImageViewAnimation = new AlphaAnimation(0F, 1F); - static final int sPadding = 20; static final int sHysteresis = sPadding * 2; static final int sBaseScrollDuration = 1000; // ms @@ -112,6 +113,8 @@ public class ViewImage extends Activity implements View.OnClickListener private int mSlideShowImageCurrent = 0; private ImageViewTouch [] mSlideShowImageViews = new ImageViewTouch[2]; + private GestureDetector mGestureDetector; + private ZoomButtonsController mZoomButtonsController; // Array of image views. The center view is the one the user is focused // on. The one at the zeroth position and the second position reflect @@ -129,10 +132,6 @@ public class ViewImage extends Activity implements View.OnClickListener private int mCurrentOrientation; - - public ViewImage() { - } - private void updateNextPrevControls() { boolean showPrev = mCurrentPosition > 0; boolean showNext = mCurrentPosition < mAllImages.getCount() - 1; @@ -171,6 +170,8 @@ public class ViewImage extends Activity implements View.OnClickListener private void showOnScreenControls() { updateNextPrevControls(); + updateZoomButtonsEnabled(); + mZoomButtonsController.setVisible(true); scheduleDismissOnScreenControls(); } @@ -193,7 +194,70 @@ public class ViewImage extends Activity implements View.OnClickListener mHandler.postDelayed(mDismissOnScreenControlsRunnable, 1500); } - public void setupDismissOnScreenControlRunnable() { + private void updateZoomButtonsEnabled() { + ImageViewTouch imageView = mImageViews[1]; + float scale = imageView.getScale(); + mZoomButtonsController.setZoomInEnabled(scale < imageView.mMaxZoom); + mZoomButtonsController.setZoomOutEnabled(scale > 1); + } + + private void setupZoomButtonController(View rootView) { + mGestureDetector = new GestureDetector(this, new MyGestureListener()); + mZoomButtonsController = new ZoomButtonsController(rootView); + mZoomButtonsController.setAutoDismissed(false); + mZoomButtonsController.setOnZoomListener( + new ZoomButtonsController.OnZoomListener() { + public void onVisibilityChanged(boolean visible) { + if (visible) { + updateZoomButtonsEnabled(); + } + } + + public void onZoom(boolean zoomIn) { + if (zoomIn) { + mImageViews[1].zoomIn(); + } else { + mImageViews[1].zoomOut(); + } + showOnScreenControls(); + } + + }); + } + + private class MyGestureListener extends + GestureDetector.SimpleOnGestureListener { + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, + float distanceX, float distanceY) { + ImageViewTouch imageView = mImageViews[1]; + if (imageView.getScale() > 1F) { + imageView.postTranslate(-distanceX, -distanceY, sUseBounce); + imageView.center(true, true, false); + } + showOnScreenControls(); + return true; + } + + @Override + public boolean onSingleTapUp(MotionEvent e) { + + int viewWidth = mImageViews[1].getWidth(); + int x = (int) e.getX(); + int y = (int) e.getY(); + if (x < TOUCH_AREA_WIDTH) { + moveNextOrPrevious(-1); + } else if (x > viewWidth - TOUCH_AREA_WIDTH) { + moveNextOrPrevious(1); + } + setMode(MODE_NORMAL); + showOnScreenControls(); + return true; + } + } + + private void setupDismissOnScreenControlRunnable() { mDismissOnScreenControlsRunnable = new Runnable() { public void run() { if (!mShowActionIcons) { @@ -212,6 +276,7 @@ public class ViewImage extends Activity implements View.OnClickListener mPrevImageView.setAnimation(a); mPrevImageView.setVisibility(View.INVISIBLE); } + mZoomButtonsController.setVisible(false); } } }; @@ -225,55 +290,18 @@ public class ViewImage extends Activity implements View.OnClickListener private static final boolean sUseBounce = false; private static final boolean sAnimateTransitions = false; - static public class ImageViewTouch extends ImageViewTouchBase { + public static class ImageViewTouch extends ImageViewTouchBase { private ViewImage mViewImage; private boolean mEnableTrackballScroll; - private GestureDetector mGestureDetector; - - private static int TOUCH_AREA_WIDTH = 60; - - private ZoomButtonsController mZoomButtonsController; public ImageViewTouch(Context context) { super(context); - setup(context); + mViewImage = (ViewImage) context; } public ImageViewTouch(Context context, AttributeSet attrs) { super(context, attrs); - setup(context); - } - - private void setup(Context context) { mViewImage = (ViewImage) context; - mGestureDetector = new GestureDetector(getContext(), new MyGestureListener()); - mZoomButtonsController = new ZoomButtonsController(this); - mZoomButtonsController.setOnZoomListener(new ZoomButtonsController.OnZoomListener() { - public void onCenter(int x, int y) { - } - - public void onVisibilityChanged(boolean visible) { - if (visible) { - updateButtonsEnabled(); - } - } - - public void onZoom(boolean zoomIn) { - if (zoomIn) { - zoomIn(); - } else { - zoomOut(); - } - - updateButtonsEnabled(); - } - - private void updateButtonsEnabled() { - float scale = getScale(); - mZoomButtonsController.setZoomInEnabled(scale < mMaxZoom); - mZoomButtonsController.setZoomOutEnabled(scale > 1); - } - }); } public void setEnableTrackballScroll(boolean enable) { @@ -282,8 +310,9 @@ public class ViewImage extends Activity implements View.OnClickListener protected void postTranslate(float dx, float dy, boolean bounceOK) { super.postTranslate(dx, dy); - if (dx != 0F || dy != 0F) + if (dx != 0F || dy != 0F) { mViewImage.showOnScreenControls(); + } if (!sUseBounce) { center(true, false, false); @@ -295,45 +324,7 @@ public class ViewImage extends Activity implements View.OnClickListener } public boolean handleTouchEvent(MotionEvent m) { - return mGestureDetector.onTouchEvent(m); - } - - private class MyGestureListener extends GestureDetector.SimpleOnGestureListener { - @Override - public boolean onDown(MotionEvent e) { - mZoomButtonsController.setVisible(true); - return true; - } - - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, - float distanceX, float distanceY) { - if (getScale() > 1F) { - postTranslate(-distanceX, -distanceY, sUseBounce); - ImageViewTouch.this.center(true, true, false); - } - mZoomButtonsController.setVisible(true); - return true; - } - - @Override - public boolean onSingleTapUp(MotionEvent e) { - ViewImage viewImage = mViewImage; - - int viewWidth = getWidth(); - int x = (int) e.getX(); - int y = (int) e.getY(); - if (x < TOUCH_AREA_WIDTH) { - viewImage.moveNextOrPrevious(-1); - } else if (x > viewWidth - TOUCH_AREA_WIDTH) { - viewImage.moveNextOrPrevious(1); - } - - viewImage.setMode(MODE_NORMAL); - viewImage.showOnScreenControls(); - - return true; - } + return mViewImage.mGestureDetector.onTouchEvent(m); } @Override @@ -356,7 +347,7 @@ public class ViewImage extends Activity implements View.OnClickListener if (mViewImage.isPickIntent()) { ImageManager.IImage img = mViewImage.mAllImages.getImageAt(mViewImage.mCurrentPosition); mViewImage.setResult(RESULT_OK, - new Intent().setData(img.fullSizeImageUri())); + new Intent().setData(img.fullSizeImageUri())); mViewImage.finish(); } break; @@ -373,7 +364,7 @@ public class ViewImage extends Activity implements View.OnClickListener } case KeyEvent.KEYCODE_DPAD_RIGHT: { panBy(-sPanRate, 0); - int maxOffset = (current == mViewImage.mAllImages.getCount()-1) ? 0 : sHysteresis; + int maxOffset = (current == mViewImage.mAllImages.getCount() - 1) ? 0 : sHysteresis; if (getScale() <= 1F || isShiftedToNextImage(false, maxOffset)) { nextImagePos = current + 1; } else { @@ -392,7 +383,8 @@ public class ViewImage extends Activity implements View.OnClickListener return true; } case KeyEvent.KEYCODE_DEL: - MenuHelper.deletePhoto(mViewImage, mViewImage.mDeletePhotoRunnable); + MenuHelper.displayDeleteDialog(mViewImage, + mViewImage.mDeletePhotoRunnable, true); break; } } finally { @@ -433,12 +425,6 @@ public class ViewImage extends Activity implements View.OnClickListener protected int getScrollOffset() { return scrollHandler().getScrollX(); } - - @Override - protected void onDetachedFromWindow() { - mZoomButtonsController.setVisible(false); - } - } static class ScrollHandler extends LinearLayout { @@ -980,6 +966,7 @@ public class ViewImage extends Activity implements View.OnClickListener public void imageLoaded(int pos, int offset, Bitmap bitmap, boolean isThumb) { ImageViewTouchBase ivt = mImageViews[1 + offset]; + if (offset == 0) updateZoomButtonsEnabled(); ivt.setImageBitmapResetBase(bitmap, isThumb, isThumb); } }; @@ -1095,6 +1082,7 @@ public class ViewImage extends Activity implements View.OnClickListener } } + setupZoomButtonController(findViewById(R.id.rootLayout)); setupDismissOnScreenControlRunnable(); mNextImageView = findViewById(R.id.next_image); @@ -1432,18 +1420,6 @@ public class ViewImage extends Activity implements View.OnClickListener setImage(mCurrentPosition); setOrientation(); - - // Show a tutorial for the new zoom interaction (the method ensure we only show it once) - ZoomButtonsController.showZoomTutorialOnce(this); - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - if (hasFocus) { - ZoomButtonsController.showZoomTutorialOnce(this); - } else { - ZoomButtonsController.finishZoomTutorial(this, false); - } } @Override @@ -1457,6 +1433,9 @@ public class ViewImage extends Activity implements View.OnClickListener setMode(MODE_NORMAL); mAllImages.deactivate(); + mDismissOnScreenControlsRunnable.run(); + if (mDismissOnScreenControlsRunnable != null) + mHandler.removeCallbacks(mDismissOnScreenControlsRunnable); for (ImageViewTouch iv: mImageViews) { iv.recycleBitmaps(); @@ -1467,7 +1446,6 @@ public class ViewImage extends Activity implements View.OnClickListener iv.recycleBitmaps(); iv.setImageBitmap(null, true); } - ZoomButtonsController.finishZoomTutorial(this, false); } @Override @@ -1493,11 +1471,7 @@ public class ViewImage extends Activity implements View.OnClickListener break; case R.id.discard: { - if (mCameraReviewMode) { - mDeletePhotoRunnable.run(); - } else { - MenuHelper.deletePhoto(this, mDeletePhotoRunnable); - } + MenuHelper.displayDeleteDialog(this, mDeletePhotoRunnable, true); } break; @@ -1554,6 +1528,10 @@ public class ViewImage extends Activity implements View.OnClickListener // the Action rather than the Data. Uri dataUri = Uri.parse(data.getAction()); init(dataUri); + // Clear mImageViews so we can reload the correct image in onResume(). + for (ImageViewTouch iv: mImageViews) { + iv.clear(); + } } break; } |