diff options
author | Wu-cheng Li <wuchengli@google.com> | 2011-05-13 15:18:10 +0800 |
---|---|---|
committer | Wu-cheng Li <wuchengli@google.com> | 2011-05-17 15:44:34 +0800 |
commit | 8ab2b624d51b3b8254ece98c46a7e22a6fb5d4aa (patch) | |
tree | 9a62692e59dcfbc8b48e78cfb71e69bfdb7edb4c | |
parent | 9e1fcfe35695fd1e71d6c86f28075ca356e5bad5 (diff) | |
download | packages_apps_LegacyCamera-8ab2b624d51b3b8254ece98c46a7e22a6fb5d4aa.zip packages_apps_LegacyCamera-8ab2b624d51b3b8254ece98c46a7e22a6fb5d4aa.tar.gz packages_apps_LegacyCamera-8ab2b624d51b3b8254ece98c46a7e22a6fb5d4aa.tar.bz2 |
Refactor RotateImageView and thumbnail.
Change-Id: Ic435b7cd97ba775ec8f4b8342a1d4d25e2a5120c
-rw-r--r-- | src/com/android/camera/Camera.java | 95 | ||||
-rw-r--r-- | src/com/android/camera/Storage.java | 130 | ||||
-rw-r--r-- | src/com/android/camera/Thumbnail.java | 201 | ||||
-rw-r--r-- | src/com/android/camera/Util.java | 39 | ||||
-rw-r--r-- | src/com/android/camera/VideoCamera.java | 87 | ||||
-rw-r--r-- | src/com/android/camera/ui/RotateImageView.java (renamed from src/com/android/camera/RotateImageView.java) | 104 |
6 files changed, 315 insertions, 341 deletions
diff --git a/src/com/android/camera/Camera.java b/src/com/android/camera/Camera.java index dc399a4..ae522ef 100644 --- a/src/com/android/camera/Camera.java +++ b/src/com/android/camera/Camera.java @@ -26,7 +26,6 @@ import com.android.camera.ui.ZoomControllerListener; import com.android.camera.ui.ZoomPicker; import android.app.Activity; -import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentProviderClient; import android.content.ContentResolver; @@ -101,8 +100,7 @@ public class Camera extends ActivityBase implements View.OnClickListener, private static final String TAG = "camera"; - private static final String LAST_THUMB_PATH = - Storage.THUMBNAILS + "/image_last_thumb"; + private static final String LAST_THUMB_FILENAME = "image_last_thumb"; private static final int CROP_MSG = 1; private static final int FIRST_TIME_INIT = 2; @@ -172,8 +170,12 @@ public class Camera extends ActivityBase implements View.OnClickListener, private GLRootView mGLRootView; - // The last captured picture. + // A button showing the last captured picture thumbnail. Clicking on it + // goes to gallery. private RotateImageView mThumbnailButton; + // The bitmap of the last captured picture thumbnail and the URI of the + // original picture. + private Thumbnail mThumbnail; // mCropValue and mSaveUri are used only if isImageCaptureIntent() is true. private String mCropValue; @@ -377,7 +379,7 @@ public class Camera extends ActivityBase implements View.OnClickListener, // Initialize last picture button. mContentResolver = getContentResolver(); - if (!mIsImageCaptureIntent) { + if (!mIsImageCaptureIntent) { // no thumbnail in image capture intent findViewById(R.id.camera_switch).setOnClickListener(this); initThumbnailButton(); } @@ -423,30 +425,23 @@ public class Camera extends ActivityBase implements View.OnClickListener, } private void initThumbnailButton() { - mThumbnailButton = - (RotateImageView) findViewById(R.id.review_thumbnail); - if (mThumbnailButton != null) { - mThumbnailButton.setOnClickListener(this); - mThumbnailButton.loadData(LAST_THUMB_PATH); - updateThumbnailButton(); - } + mThumbnailButton.setOnClickListener(this); + // Load the thumbnail from the disk. + mThumbnail = Thumbnail.loadFrom(LAST_THUMB_FILENAME); + updateThumbnailButton(); } private void updateThumbnailButton() { - if (mThumbnailButton == null) return; // Update last image if URI is invalid and the storage is ready. - if (!mThumbnailButton.isUriValid() && mPicturesRemaining >= 0) { - Storage.Thumbnail thumbnail = - Storage.getLastImageThumbnail(mContentResolver); - if (thumbnail != null) { - mThumbnailButton.setData(thumbnail.getOriginalUri(), - thumbnail.getBitmap(mContentResolver)); - } else { - mThumbnailButton.setData(null, null); - } + if ((mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), mContentResolver)) + && mPicturesRemaining >= 0) { + mThumbnail = Thumbnail.getLastImageThumbnail(mContentResolver); + } + if (mThumbnail != null) { + mThumbnailButton.setBitmap(mThumbnail.getBitmap()); + } else { + mThumbnailButton.setBitmap(null); } - mThumbnailButton.setVisibility( - (mThumbnailButton.getUri() != null) ? View.VISIBLE : View.GONE); } // If the activity is paused and resumed, this method will be called in @@ -859,17 +854,15 @@ public class Camera extends ActivityBase implements View.OnClickListener, if (!mIsImageCaptureIntent) { long dateTaken = System.currentTimeMillis(); String title = createName(dateTaken); - - Storage.Thumbnail thumbnail = Storage.addImage( - mContentResolver, title, dateTaken, loc, data); - - if (thumbnail != null && mThumbnailButton != null) { - mThumbnailButton.setData(thumbnail.getOriginalUri(), - thumbnail.getBitmap(mContentResolver)); - mThumbnailButton.setVisibility(View.VISIBLE); - - sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", - thumbnail.getOriginalUri())); + int orientation = Exif.getOrientation(data); + Uri uri = Storage.addImage(mContentResolver, title, dateTaken, + loc, orientation, data); + if (uri != null) { + mThumbnail = Thumbnail.createThumbnail(data, orientation, uri); + if (mThumbnail != null) { + mThumbnailButton.setBitmap(mThumbnail.getBitmap()); + } + sendBroadcast(new Intent("com.android.camera.NEW_PICTURE", uri)); } } else { mJpegImageData = data; @@ -982,6 +975,7 @@ public class Camera extends ActivityBase implements View.OnClickListener, } mSurfaceView = (SurfaceView) findViewById(R.id.camera_preview); mFocusRectangle = (FocusRectangle) findViewById(R.id.focus_rectangle); + mThumbnailButton = (RotateImageView) findViewById(R.id.review_thumbnail); mPreferences = new ComboPreferences(this); CameraSettings.upgradeGlobalPreferences(mPreferences.getGlobal()); @@ -1272,8 +1266,8 @@ public class Camera extends ActivityBase implements View.OnClickListener, restartPreview(); break; case R.id.review_thumbnail: - if (isCameraIdle()) { - viewImage(mThumbnailButton); + if (isCameraIdle() && mThumbnail != null) { + Util.viewUri(mThumbnail.getUri(), this); } break; case R.id.btn_done: @@ -1506,9 +1500,7 @@ public class Camera extends ActivityBase implements View.OnClickListener, if (mFirstTimeInitialized) { mOrientationListener.disable(); if (!mIsImageCaptureIntent) { - if (mThumbnailButton != null) { - mThumbnailButton.storeData(LAST_THUMB_PATH); - } + if (mThumbnail != null) mThumbnail.saveTo(LAST_THUMB_FILENAME); } hidePostCaptureAlert(); } @@ -2146,25 +2138,6 @@ public class Camera extends ActivityBase implements View.OnClickListener, MenuHelper.gotoCameraImageGallery(this); } - private void viewImage(RotateImageView view) { - if(!view.isUriValid()) { - Log.e(TAG, "Uri invalid. uri=" + view.getUri()); - return; - } - - try { - startActivity(new Intent( - Util.REVIEW_ACTION, view.getUri())); - } catch (ActivityNotFoundException ex) { - try { - startActivity(new Intent( - Intent.ACTION_VIEW, view.getUri())); - } catch (ActivityNotFoundException e) { - Log.e(TAG, "review image fail. uri=" + view.getUri(), e); - } - } - } - private void startReceivingLocationUpdates() { if (mLocationManager != null) { try { @@ -2463,10 +2436,10 @@ public class Camera extends ActivityBase implements View.OnClickListener, if (mPausing) return; // Share the last captured picture. - if (mThumbnailButton.getUri() != null) { + if (mThumbnail != null) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("image/jpeg"); - intent.putExtra(Intent.EXTRA_STREAM, mThumbnailButton.getUri()); + intent.putExtra(Intent.EXTRA_STREAM, mThumbnail.getUri()); startActivity(Intent.createChooser(intent, getString(R.string.share_picture_via))); } else { // No last picture if (mNoShareToast == null) { diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java index 23a9282..86fb443 100644 --- a/src/com/android/camera/Storage.java +++ b/src/com/android/camera/Storage.java @@ -17,20 +17,13 @@ package com.android.camera; import android.content.ContentResolver; -import android.content.ContentUris; import android.content.ContentValues; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; import android.location.Location; import android.net.Uri; import android.os.Environment; import android.os.StatFs; import android.provider.MediaStore.Images; import android.provider.MediaStore.Images.ImageColumns; -import android.provider.MediaStore.Video; -import android.provider.MediaStore.Video.VideoColumns; import android.util.Log; import java.io.File; @@ -39,13 +32,11 @@ import java.io.FileOutputStream; class Storage { private static final String TAG = "CameraStorage"; - private static final String DCIM = + public static final String DCIM = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString(); public static final String DIRECTORY = DCIM + "/Camera"; - public static final String THUMBNAILS = DCIM + "/.thumbnails"; - // Match the code in MediaProvider.computeBucketValues(). public static final String BUCKET_ID = String.valueOf(DIRECTORY.toLowerCase().hashCode()); @@ -54,109 +45,10 @@ class Storage { public static final long PREPARING = -2L; public static final long UNKNOWN_SIZE = -3L; - public static class Thumbnail { - private Uri mBaseUri; - private long mId; - private Uri mUri; - private Bitmap mBitmap; - private int mOrientation; - - private Thumbnail(Uri baseUri, long id, int orientation) { - mBaseUri = baseUri; - mId = id; - mOrientation = orientation; - } - - private Thumbnail(Uri uri, Bitmap bitmap, int orientation) { - mUri = uri; - mBitmap = bitmap; - mOrientation = orientation; - } - - public Uri getOriginalUri() { - if (mUri == null && mBaseUri != null) { - mUri = ContentUris.withAppendedId(mBaseUri, mId); - } - return mUri; - } - - public Bitmap getBitmap(ContentResolver resolver) { - if (mBitmap == null) { - if (Images.Media.EXTERNAL_CONTENT_URI.equals(mBaseUri)) { - mBitmap = Images.Thumbnails.getThumbnail(resolver, mId, - Images.Thumbnails.MICRO_KIND, null); - } else if (Video.Media.EXTERNAL_CONTENT_URI.equals(mBaseUri)) { - mBitmap = Video.Thumbnails.getThumbnail(resolver, mId, - Video.Thumbnails.MICRO_KIND, null); - } - } - if (mBitmap != null && mOrientation != 0) { - // We only rotate the thumbnail once even if we get OOM. - Matrix m = new Matrix(); - m.setRotate(mOrientation, mBitmap.getWidth() * 0.5f, - mBitmap.getHeight() * 0.5f); - mOrientation = 0; - - try { - Bitmap rotated = Bitmap.createBitmap(mBitmap, 0, 0, - mBitmap.getWidth(), mBitmap.getHeight(), m, true); - mBitmap.recycle(); - mBitmap = rotated; - } catch (Throwable t) { - Log.w(TAG, "Failed to rotate thumbnail", t); - } - } - return mBitmap; - } - } - - public static Thumbnail getLastImageThumbnail(ContentResolver resolver) { - Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI; - - Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build(); - String[] projection = new String[] {ImageColumns._ID, ImageColumns.ORIENTATION}; - String selection = ImageColumns.MIME_TYPE + "='image/jpeg' AND " + - ImageColumns.BUCKET_ID + '=' + BUCKET_ID; - String order = ImageColumns.DATE_TAKEN + " DESC," + ImageColumns._ID + " DESC"; - - Cursor cursor = null; - try { - cursor = resolver.query(query, projection, selection, null, order); - if (cursor != null && cursor.moveToFirst()) { - return new Thumbnail(baseUri, cursor.getLong(0), cursor.getInt(1)); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - return null; - } - - public static Thumbnail getLastVideoThumbnail(ContentResolver resolver) { - Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI; + private static final int BUFSIZE = 4096; - Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build(); - String[] projection = new String[] {VideoColumns._ID}; - String selection = VideoColumns.BUCKET_ID + '=' + BUCKET_ID; - String order = VideoColumns.DATE_TAKEN + " DESC," + VideoColumns._ID + " DESC"; - - Cursor cursor = null; - try { - cursor = resolver.query(query, projection, selection, null, order); - if (cursor != null && cursor.moveToFirst()) { - return new Thumbnail(baseUri, cursor.getLong(0), 0); - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - return null; - } - - public static Thumbnail addImage(ContentResolver resolver, String title, - long date, Location location, byte[] jpeg) { + public static Uri addImage(ContentResolver resolver, String title, + long date, Location location, int orientation, byte[] jpeg) { // Save the image. String path = DIRECTORY + '/' + title + ".jpg"; FileOutputStream out = null; @@ -173,9 +65,6 @@ class Storage { } } - // Get the orientation. - int orientation = Exif.getOrientation(jpeg); - // Insert into MediaStore. ContentValues values = new ContentValues(9); values.put(ImageColumns.TITLE, title); @@ -196,16 +85,7 @@ class Storage { Log.e(TAG, "Failed to write MediaStore"); return null; } - - // Create the thumbnail. - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inSampleSize = 16; - Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); - if (bitmap == null) { - Log.e(TAG, "Failed to create thumbnail"); - return null; - } - return new Thumbnail(uri, bitmap, orientation); + return uri; } public static long getAvailableSpace() { diff --git a/src/com/android/camera/Thumbnail.java b/src/com/android/camera/Thumbnail.java new file mode 100644 index 0000000..cc9290c --- /dev/null +++ b/src/com/android/camera/Thumbnail.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.camera; + +import android.content.ContentResolver; +import android.content.ContentUris; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Matrix; +import android.net.Uri; +import android.provider.MediaStore.Images; +import android.provider.MediaStore.Images.ImageColumns; +import android.provider.MediaStore.Video; +import android.provider.MediaStore.Video.VideoColumns; +import android.util.Log; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +class Thumbnail { + private static final String TAG = "Thumbnail"; + + private static final String DIRECTORY = Storage.DCIM + "/.thumbnails/"; + private static final int BUFSIZE = 4096; + + private Uri mUri; + private Bitmap mBitmap; + + public Thumbnail(Uri uri, Bitmap bitmap, int orientation) { + mUri = uri; + mBitmap = rotateImage(bitmap, orientation); + } + + public Uri getUri() { + return mUri; + } + + public Bitmap getBitmap() { + return mBitmap; + } + + private static Bitmap rotateImage(Bitmap bitmap, int orientation) { + if (orientation != 0) { + // We only rotate the thumbnail once even if we get OOM. + Matrix m = new Matrix(); + m.setRotate(orientation, bitmap.getWidth() * 0.5f, + bitmap.getHeight() * 0.5f); + + try { + Bitmap rotated = Bitmap.createBitmap(bitmap, 0, 0, + bitmap.getWidth(), bitmap.getHeight(), m, true); + bitmap.recycle(); + return rotated; + } catch (Throwable t) { + Log.w(TAG, "Failed to rotate thumbnail", t); + } + } + return bitmap; + } + + // Stores the bitmap to the specified file. + public void saveTo(String filename) { + String path = DIRECTORY + filename; + FileOutputStream f = null; + BufferedOutputStream b = null; + DataOutputStream d = null; + try { + f = new FileOutputStream(path); + b = new BufferedOutputStream(f, BUFSIZE); + d = new DataOutputStream(b); + d.writeUTF(mUri.toString()); + mBitmap.compress(Bitmap.CompressFormat.PNG, 100, d); + d.close(); + } catch (IOException e) { + Log.e(TAG, "Fail to store bitmap. path=" + path, e); + } finally { + Util.closeSilently(f); + Util.closeSilently(b); + Util.closeSilently(d); + } + } + + + // Loads the data from the specified file. + // Returns null if failure. + public static Thumbnail loadFrom(String filename) { + Uri uri = null; + Bitmap bitmap = null; + FileInputStream f = null; + BufferedInputStream b = null; + DataInputStream d = null; + try { + f = new FileInputStream(DIRECTORY + filename); + b = new BufferedInputStream(f, BUFSIZE); + d = new DataInputStream(b); + uri = Uri.parse(d.readUTF()); + bitmap = BitmapFactory.decodeStream(d); + d.close(); + } catch (IOException e) { + Log.i(TAG, "Fail to load bitmap. " + e); + return null; + } finally { + Util.closeSilently(f); + Util.closeSilently(b); + Util.closeSilently(d); + } + return new Thumbnail(uri, bitmap, 0); + } + + public static Thumbnail getLastImageThumbnail(ContentResolver resolver) { + Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI; + + Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build(); + String[] projection = new String[] {ImageColumns._ID, ImageColumns.ORIENTATION}; + String selection = ImageColumns.MIME_TYPE + "='image/jpeg' AND " + + ImageColumns.BUCKET_ID + '=' + Storage.BUCKET_ID; + String order = ImageColumns.DATE_TAKEN + " DESC," + ImageColumns._ID + " DESC"; + + Cursor cursor = null; + try { + cursor = resolver.query(query, projection, selection, null, order); + if (cursor != null && cursor.moveToFirst()) { + long id = cursor.getLong(0); + int orientation = cursor.getInt(1); + Bitmap bitmap = Images.Thumbnails.getThumbnail(resolver, id, + Images.Thumbnails.MICRO_KIND, null); + Uri uri = ContentUris.withAppendedId(baseUri, id); + // Ensure there's no OOM. Ensure database and storage are in sync. + if (bitmap != null && Util.isUriValid(uri, resolver)) { + return new Thumbnail(uri, bitmap, orientation); + } + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return null; + } + + public static Thumbnail getLastVideoThumbnail(ContentResolver resolver) { + Uri baseUri = Video.Media.EXTERNAL_CONTENT_URI; + + Uri query = baseUri.buildUpon().appendQueryParameter("limit", "1").build(); + String[] projection = new String[] {VideoColumns._ID}; + String selection = VideoColumns.BUCKET_ID + '=' + Storage.BUCKET_ID; + String order = VideoColumns.DATE_TAKEN + " DESC," + VideoColumns._ID + " DESC"; + + Cursor cursor = null; + try { + cursor = resolver.query(query, projection, selection, null, order); + if (cursor != null && cursor.moveToFirst()) { + long id = cursor.getLong(0); + Bitmap bitmap = Video.Thumbnails.getThumbnail(resolver, id, + Video.Thumbnails.MICRO_KIND, null); + Uri uri = ContentUris.withAppendedId(baseUri, id); + // Ensure there's no OOM. Ensure database and storage are in sync. + if (bitmap != null && Util.isUriValid(uri, resolver)) { + return new Thumbnail(uri, bitmap, 0); + } + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + return null; + } + + public static Thumbnail createThumbnail(byte[] jpeg, int orientation, Uri uri) { + // Create the thumbnail. + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inSampleSize = 16; + Bitmap bitmap = BitmapFactory.decodeByteArray(jpeg, 0, jpeg.length, options); + if (bitmap == null) { + Log.e(TAG, "Failed to create thumbnail"); + return null; + } + return new Thumbnail(uri, bitmap, orientation); + } +} diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java index 5d4f9b0..bf33dc9 100644 --- a/src/com/android/camera/Util.java +++ b/src/com/android/camera/Util.java @@ -18,14 +18,19 @@ package com.android.camera; import android.app.Activity; import android.app.AlertDialog; +import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.ContentResolver; import android.content.DialogInterface; +import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Matrix; import android.hardware.Camera; import android.hardware.Camera.Parameters; import android.hardware.Camera.Size; +import android.net.Uri; +import android.os.ParcelFileDescriptor; import android.telephony.TelephonyManager; import android.util.Log; import android.view.Display; @@ -35,6 +40,7 @@ import android.view.animation.Animation; import android.view.animation.TranslateAnimation; import java.io.Closeable; +import java.io.IOException; import java.lang.reflect.Method; import java.util.List; import java.util.StringTokenizer; @@ -399,4 +405,37 @@ public class Util { return x >= mLocation[0] && x < (mLocation[0] + v.getWidth()) && y >= mLocation[1] && y < (mLocation[1] + v.getHeight()); } + + public static boolean isUriValid(Uri uri, ContentResolver resolver) { + if (uri == null) return false; + + try { + ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r"); + if (pfd == null) { + Log.e(TAG, "Fail to open URI. URI=" + uri); + return false; + } + pfd.close(); + } catch (IOException ex) { + return false; + } + return true; + } + + public static void viewUri(Uri uri, Context context) { + if (!isUriValid(uri, context.getContentResolver())) { + Log.e(TAG, "Uri invalid. uri=" + uri); + return; + } + + try { + context.startActivity(new Intent(Util.REVIEW_ACTION, uri)); + } catch (ActivityNotFoundException ex) { + try { + context.startActivity(new Intent(Intent.ACTION_VIEW, uri)); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "review image fail. uri=" + uri, e); + } + } + } } diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java index 27d7aa6..bf8f864 100644 --- a/src/com/android/camera/VideoCamera.java +++ b/src/com/android/camera/VideoCamera.java @@ -89,8 +89,7 @@ public class VideoCamera extends ActivityBase private static final String TAG = "videocamera"; - private static final String LAST_THUMB_PATH = - Storage.THUMBNAILS + "/video_last_thumb"; + private static final String LAST_THUMB_FILENAME = "video_last_thumb"; private static final int CHECK_DISPLAY_ROTATION = 3; private static final int CLEAR_SCREEN_DELAY = 4; @@ -151,8 +150,12 @@ public class VideoCamera extends ActivityBase private View mReviewControl; private Toast mNoShareToast; - // The last recorded video. + // A button showing the last captured video thumbnail. Clicking on it + // goes to gallery. private RotateImageView mThumbnailButton; + // The bitmap of the last captured video thumbnail and the URI of the + // original video. + private Thumbnail mThumbnail; private ShutterButton mShutterButton; private TextView mRecordingTimeView; private SwitcherSet mSwitcher; @@ -597,7 +600,7 @@ public class VideoCamera extends ActivityBase Intent intent = new Intent(Intent.ACTION_VIEW, mCurrentVideoUri); try { startActivity(intent); - } catch (android.content.ActivityNotFoundException ex) { + } catch (ActivityNotFoundException ex) { Log.e(TAG, "Couldn't view video " + mCurrentVideoUri, ex); } } @@ -619,7 +622,9 @@ public class VideoCamera extends ActivityBase doReturnToCaller(false); break; case R.id.review_thumbnail: - if (!mMediaRecorderRecording) viewVideo(mThumbnailButton); + if (!mMediaRecorderRecording && mThumbnail != null) { + Util.viewUri(mThumbnail.getUri(), this); + } break; case R.id.btn_gallery: gotoGallery(); @@ -959,8 +964,8 @@ public class VideoCamera extends ActivityBase } resetScreenOn(); - if (!mIsVideoCaptureIntent && mThumbnailButton != null) { - mThumbnailButton.storeData(LAST_THUMB_PATH); + if (!mIsVideoCaptureIntent && mThumbnail != null) { + mThumbnail.saveTo(LAST_THUMB_FILENAME); } if (mStorageHint != null) { @@ -1462,7 +1467,12 @@ public class VideoCamera extends ActivityBase } private void getThumbnail() { - acquireVideoThumb(); + Bitmap videoFrame = ThumbnailUtils.createVideoThumbnail( + mCurrentVideoFilename, Video.Thumbnails.MINI_KIND); + if (videoFrame != null) { + mThumbnail = new Thumbnail(mCurrentVideoUri, videoFrame, 0); + mThumbnailButton.setBitmap(mThumbnail.getBitmap()); + } } private void showAlert() { @@ -1535,24 +1545,6 @@ public class VideoCamera extends ActivityBase return this.mVideoFrame.getVisibility() == View.VISIBLE; } - private void viewVideo(RotateImageView view) { - if(view.isUriValid()) { - Intent intent = new Intent(Util.REVIEW_ACTION, view.getUri()); - try { - startActivity(intent); - } catch (ActivityNotFoundException ex) { - try { - intent = new Intent(Intent.ACTION_VIEW, view.getUri()); - startActivity(intent); - } catch (ActivityNotFoundException e) { - Log.e(TAG, "review video fail. uri=" + view.getUri(), e); - } - } - } else { - Log.e(TAG, "Uri invalid. uri=" + view.getUri()); - } - } - private void stopVideoRecording() { Log.v(TAG, "stopVideoRecording"); if (mMediaRecorderRecording) { @@ -1598,39 +1590,22 @@ public class VideoCamera extends ActivityBase getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } - private void acquireVideoThumb() { - if (mThumbnailButton != null) { - Bitmap videoFrame = ThumbnailUtils.createVideoThumbnail( - mCurrentVideoFilename, Video.Thumbnails.MINI_KIND); - mThumbnailButton.setData(mCurrentVideoUri, videoFrame); - if (videoFrame != null) { - mThumbnailButton.setVisibility(View.VISIBLE); - } - } - } - private void initThumbnailButton() { - mThumbnailButton = (RotateImageView)findViewById(R.id.review_thumbnail); - if (mThumbnailButton != null) { - mThumbnailButton.setOnClickListener(this); - mThumbnailButton.loadData(LAST_THUMB_PATH); - } + mThumbnailButton = (RotateImageView) findViewById(R.id.review_thumbnail); + mThumbnailButton.setOnClickListener(this); + // Load the thumbnail from the disk. + mThumbnail = Thumbnail.loadFrom(LAST_THUMB_FILENAME); } private void updateThumbnailButton() { - if (mThumbnailButton == null) return; - if (!mThumbnailButton.isUriValid()) { - Storage.Thumbnail thumbnail = - Storage.getLastVideoThumbnail(mContentResolver); - if (thumbnail != null) { - mThumbnailButton.setData(thumbnail.getOriginalUri(), - thumbnail.getBitmap(mContentResolver)); - } else { - mThumbnailButton.setData(null, null); - } + if (mThumbnail == null || !Util.isUriValid(mThumbnail.getUri(), mContentResolver)) { + mThumbnail = Thumbnail.getLastVideoThumbnail(mContentResolver); + } + if (mThumbnail != null) { + mThumbnailButton.setBitmap(mThumbnail.getBitmap()); + } else { + mThumbnailButton.setBitmap(null); } - mThumbnailButton.setVisibility( - (mThumbnailButton.getUri() != null) ? View.VISIBLE : View.GONE); } private static String millisecondToTimeString(long milliSeconds, boolean displayCentiSeconds) { @@ -1918,10 +1893,10 @@ public class VideoCamera extends ActivityBase if (mPausing) return; // Share the last captured video. - if (mThumbnailButton.getUri() != null) { + if (mThumbnail != null) { Intent intent = new Intent(Intent.ACTION_SEND); intent.setType("video/*"); - intent.putExtra(Intent.EXTRA_STREAM, mThumbnailButton.getUri()); + intent.putExtra(Intent.EXTRA_STREAM, mThumbnail.getUri()); startActivity(Intent.createChooser(intent, getString(R.string.share_video_via))); } else { // No last picture if (mNoShareToast == null) { diff --git a/src/com/android/camera/RotateImageView.java b/src/com/android/camera/ui/RotateImageView.java index 531169b..8348bf2 100644 --- a/src/com/android/camera/RotateImageView.java +++ b/src/com/android/camera/ui/RotateImageView.java @@ -25,22 +25,12 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.Rect; import android.media.ThumbnailUtils; -import android.net.Uri; -import android.os.ParcelFileDescriptor; import android.util.AttributeSet; import android.util.Log; import android.view.animation.AnimationUtils; import android.view.ViewGroup.LayoutParams; import android.widget.ImageView; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; - /** * A @{code ImageView} which can rotate it's content. */ @@ -60,8 +50,6 @@ public class RotateImageView extends ImageView { private long mAnimationStartTime = 0; private long mAnimationEndTime = 0; - private Uri mUri; - public RotateImageView(Context context, AttributeSet attrs) { super(context, attrs); } @@ -137,79 +125,14 @@ public class RotateImageView extends ImageView { private Drawable[] mThumbs; private TransitionDrawable mThumbTransition; - public void setData(Uri uri, Bitmap original) { + public void setBitmap(Bitmap bitmap) { // Make sure uri and original are consistently both null or both // non-null. - if (uri == null || original == null) { - uri = null; - original = null; - } - mUri = uri; - updateThumb(original); - } - - public Uri getUri() { - return mUri; - } - - private static final int BUFSIZE = 4096; - - // Stores the data from the specified file. - // Returns true for success. - public boolean storeData(String filePath) { - if (mUri == null) { - return false; - } - - FileOutputStream f = null; - BufferedOutputStream b = null; - DataOutputStream d = null; - try { - f = new FileOutputStream(filePath); - b = new BufferedOutputStream(f, BUFSIZE); - d = new DataOutputStream(b); - d.writeUTF(mUri.toString()); - mThumb.compress(Bitmap.CompressFormat.PNG, 100, d); - d.close(); - } catch (IOException e) { - return false; - } finally { - Util.closeSilently(f); - Util.closeSilently(b); - Util.closeSilently(d); - } - return true; - } - - // Loads the data from the specified file. - // Returns true for success. - public boolean loadData(String filePath) { - FileInputStream f = null; - BufferedInputStream b = null; - DataInputStream d = null; - try { - f = new FileInputStream(filePath); - b = new BufferedInputStream(f, BUFSIZE); - d = new DataInputStream(b); - Uri uri = Uri.parse(d.readUTF()); - Bitmap thumb = BitmapFactory.decodeStream(d); - setData(uri, thumb); - d.close(); - } catch (IOException e) { - return false; - } finally { - Util.closeSilently(f); - Util.closeSilently(b); - Util.closeSilently(d); - } - return true; - } - - private void updateThumb(Bitmap original) { - if (original == null) { + if (bitmap == null) { mThumb = null; mThumbs = null; setImageDrawable(null); + setVisibility(GONE); return; } @@ -219,7 +142,7 @@ public class RotateImageView extends ImageView { final int miniThumbHeight = param.height - getPaddingTop() - getPaddingBottom(); mThumb = ThumbnailUtils.extractThumbnail( - original, miniThumbWidth, miniThumbHeight); + bitmap, miniThumbWidth, miniThumbHeight); Drawable drawable; if (mThumbs == null || !mEnableAnimation) { mThumbs = new Drawable[2]; @@ -232,23 +155,6 @@ public class RotateImageView extends ImageView { setImageDrawable(mThumbTransition); mThumbTransition.startTransition(500); } - } - - public boolean isUriValid() { - if (mUri == null) { - return false; - } - try { - ParcelFileDescriptor pfd = - getContext().getContentResolver().openFileDescriptor(mUri, "r"); - if (pfd == null) { - Log.e(TAG, "Fail to open URI. URI=" + mUri); - return false; - } - pfd.close(); - } catch (IOException ex) { - return false; - } - return true; + setVisibility(VISIBLE); } } |