summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera')
-rw-r--r--src/com/android/camera/Camera.java85
-rw-r--r--src/com/android/camera/ImageGallery2.java27
-rwxr-xr-xsrc/com/android/camera/ImageManager.java24
-rw-r--r--src/com/android/camera/MenuHelper.java11
-rw-r--r--src/com/android/camera/VideoCamera.java206
-rw-r--r--src/com/android/camera/ViewImage.java204
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;
}