diff options
author | Angus Kong <shkong@google.com> | 2013-04-17 15:37:07 -0700 |
---|---|---|
committer | Angus Kong <shkong@google.com> | 2013-04-19 12:46:08 -0700 |
commit | 83a99ae51a11af28553dfb77ef0ec91148671c9b (patch) | |
tree | 6a954b37ccd589bd1f419acaedbd1c0c25a1b713 /src/com/android/camera | |
parent | b0e82433a948ab7625d5c0343a4207ea9a45bbf7 (diff) | |
download | android_packages_apps_Snap-83a99ae51a11af28553dfb77ef0ec91148671c9b.tar.gz android_packages_apps_Snap-83a99ae51a11af28553dfb77ef0ec91148671c9b.tar.bz2 android_packages_apps_Snap-83a99ae51a11af28553dfb77ef0ec91148671c9b.zip |
Save video using MediaSaveService.
bug:8511719
Change-Id: I3fc5054bf7661953181b27e66cc70ba95082d36c
Diffstat (limited to 'src/com/android/camera')
-rw-r--r-- | src/com/android/camera/MediaSaveService.java | 81 | ||||
-rw-r--r-- | src/com/android/camera/VideoModule.java | 165 |
2 files changed, 98 insertions, 148 deletions
diff --git a/src/com/android/camera/MediaSaveService.java b/src/com/android/camera/MediaSaveService.java index b1f47df77..e37b45cf2 100644 --- a/src/com/android/camera/MediaSaveService.java +++ b/src/com/android/camera/MediaSaveService.java @@ -18,16 +18,20 @@ package com.android.camera; import android.app.Service; import android.content.ContentResolver; +import android.content.ContentValues; import android.content.Intent; import android.location.Location; import android.net.Uri; import android.os.AsyncTask; import android.os.Binder; import android.os.IBinder; +import android.provider.MediaStore.Video; import android.util.Log; import com.android.gallery3d.exif.ExifInterface; +import java.io.File; + /* * Service for saving images in the background thread. */ @@ -85,7 +89,8 @@ public class MediaSaveService extends Service { Log.e(TAG, "Cannot add image when the queue is full"); return; } - SaveTask t = new SaveTask(data, title, date, (loc == null) ? null : new Location(loc), + ImageSaveTask t = new ImageSaveTask(data, title, date, + (loc == null) ? null : new Location(loc), width, height, orientation, exif, resolver, l); mTaskNumber++; @@ -95,6 +100,13 @@ public class MediaSaveService extends Service { t.execute(); } + public void addVideo(String path, long duration, ContentValues values, + OnMediaSavedListener l, ContentResolver resolver) { + // We don't set a queue limit for video saving because the file + // is already in the storage. Only updating the database. + new VideoSaveTask(path, duration, values, l, resolver).execute(); + } + public void setListener(Listener l) { mListener = l; if (l == null) return; @@ -109,7 +121,7 @@ public class MediaSaveService extends Service { if (mListener != null) mListener.onQueueStatus(false); } - private class SaveTask extends AsyncTask <Void, Void, Uri> { + private class ImageSaveTask extends AsyncTask <Void, Void, Uri> { private byte[] data; private String title; private long date; @@ -120,9 +132,9 @@ public class MediaSaveService extends Service { private ContentResolver resolver; private OnMediaSavedListener listener; - public SaveTask(byte[] data, String title, long date, Location loc, - int width, int height, int orientation, ExifInterface exif, - ContentResolver resolver, OnMediaSavedListener listener) { + public ImageSaveTask(byte[] data, String title, long date, Location loc, + int width, int height, int orientation, ExifInterface exif, + ContentResolver resolver, OnMediaSavedListener listener) { this.data = data; this.title = title; this.date = date; @@ -148,9 +160,66 @@ public class MediaSaveService extends Service { @Override protected void onPostExecute(Uri uri) { - listener.onMediaSaved(uri); + if (listener != null) listener.onMediaSaved(uri); mTaskNumber--; if (mTaskNumber == SAVE_TASK_LIMIT - 1) onQueueAvailable(); } } + + private class VideoSaveTask extends AsyncTask <Void, Void, Uri> { + private String path; + private long duration; + private ContentValues values; + private OnMediaSavedListener listener; + private ContentResolver resolver; + + public VideoSaveTask(String path, long duration, ContentValues values, + OnMediaSavedListener l, ContentResolver r) { + this.path = path; + this.duration = duration; + this.values = new ContentValues(values); + this.listener = l; + this.resolver = r; + } + + @Override + protected void onPreExecute() { + // do nothing. + } + + @Override + protected Uri doInBackground(Void... v) { + values.put(Video.Media.SIZE, new File(path).length()); + values.put(Video.Media.DURATION, duration); + Uri uri = null; + try { + Uri videoTable = Uri.parse("content://media/external/video/media"); + uri = resolver.insert(videoTable, values); + + // Rename the video file to the final name. This avoids other + // apps reading incomplete data. We need to do it after we are + // certain that the previous insert to MediaProvider is completed. + String finalName = values.getAsString( + Video.Media.DATA); + if (new File(path).renameTo(new File(finalName))) { + path = finalName; + } + + resolver.update(uri, values, null, null); + } catch (Exception e) { + // We failed to insert into the database. This can happen if + // the SD card is unmounted. + Log.e(TAG, "failed to add video to media store", e); + uri = null; + } finally { + Log.v(TAG, "Current video URI: " + uri); + } + return uri; + } + + @Override + protected void onPostExecute(Uri uri) { + if (listener != null) listener.onMediaSaved(uri); + } + } } diff --git a/src/com/android/camera/VideoModule.java b/src/com/android/camera/VideoModule.java index d4be225a0..9549c7394 100644 --- a/src/com/android/camera/VideoModule.java +++ b/src/com/android/camera/VideoModule.java @@ -174,8 +174,6 @@ public class VideoModule implements CameraModule, private LocationManager mLocationManager; - private VideoNamer mVideoNamer; - private int mPendingSwitchCameraId; private final Handler mHandler = new MainHandler(); @@ -188,7 +186,20 @@ public class VideoModule implements CameraModule, private boolean mRestoreFlash; // This is used to check if we need to restore the flash // status when going back from gallery. - private MediaSaveService.OnMediaSavedListener mOnMediaSavedListener = + private final MediaSaveService.OnMediaSavedListener mOnVideoSavedListener = + new MediaSaveService.OnMediaSavedListener() { + @Override + public void onMediaSaved(Uri uri) { + if (uri != null) { + mActivity.addSecureAlbumItemIfNeeded(true, uri); + mActivity.sendBroadcast( + new Intent(Util.ACTION_NEW_VIDEO, uri)); + Util.broadcastNewPicture(mActivity, uri); + } + } + }; + + private final MediaSaveService.OnMediaSavedListener mOnPhotoSavedListener = new MediaSaveService.OnMediaSavedListener() { @Override public void onMediaSaved(Uri uri) { @@ -761,7 +772,6 @@ public class VideoModule implements CameraModule, // Dismiss open menu if exists. PopupManager.getInstance(mActivity).notifyShowPopup(null); - mVideoNamer = new VideoNamer(); UsageStatistics.onContentViewChanged( UsageStatistics.COMPONENT_CAMERA, "VideoModule"); } @@ -950,7 +960,6 @@ public class VideoModule implements CameraModule, // that will close down the effects are well, thus making this if // condition invalid. closeVideoFileDescriptor(); - clearVideoNamer(); } releasePreviewResources(); @@ -1349,69 +1358,25 @@ public class VideoModule implements CameraModule, mCurrentVideoValues.put(Video.Media.LATITUDE, loc.getLatitude()); mCurrentVideoValues.put(Video.Media.LONGITUDE, loc.getLongitude()); } - mVideoNamer.prepareUri(mContentResolver, mCurrentVideoValues); mVideoFilename = tmpPath; Log.v(TAG, "New video filename: " + mVideoFilename); } - private boolean addVideoToMediaStore() { - boolean fail = false; + private void saveVideo() { if (mVideoFileDescriptor == null) { - mCurrentVideoValues.put(Video.Media.SIZE, - new File(mCurrentVideoFilename).length()); long duration = SystemClock.uptimeMillis() - mRecordingStartTime; if (duration > 0) { if (mCaptureTimeLapse) { duration = getTimeLapseVideoLength(duration); } - mCurrentVideoValues.put(Video.Media.DURATION, duration); } else { Log.w(TAG, "Video duration <= 0 : " + duration); } - try { - mCurrentVideoUri = mVideoNamer.getUri(); - mActivity.addSecureAlbumItemIfNeeded(true, mCurrentVideoUri); - - // Rename the video file to the final name. This avoids other - // apps reading incomplete data. We need to do it after the - // above mVideoNamer.getUri() call, so we are certain that the - // previous insert to MediaProvider is completed. - String finalName = mCurrentVideoValues.getAsString( - Video.Media.DATA); - if (new File(mCurrentVideoFilename).renameTo(new File(finalName))) { - mCurrentVideoFilename = finalName; - } - - mContentResolver.update(mCurrentVideoUri, mCurrentVideoValues - , null, null); - mActivity.sendBroadcast(new Intent(Util.ACTION_NEW_VIDEO, - mCurrentVideoUri)); - } catch (Exception e) { - // We failed to insert into the database. This can happen if - // the SD card is unmounted. - Log.e(TAG, "failed to add video to media store", e); - mCurrentVideoUri = null; - mCurrentVideoFilename = null; - fail = true; - } finally { - Log.v(TAG, "Current video URI: " + mCurrentVideoUri); - } + mActivity.getMediaSaveService().addVideo(mCurrentVideoFilename, + duration, mCurrentVideoValues, + mOnVideoSavedListener, mContentResolver); } mCurrentVideoValues = null; - return fail; - } - - private void deleteCurrentVideo() { - // Remove the video and the uri if the uri is not passed in by intent. - if (mCurrentVideoFilename != null) { - deleteVideoFile(mCurrentVideoFilename); - mCurrentVideoFilename = null; - if (mCurrentVideoUri != null) { - mContentResolver.delete(mCurrentVideoUri, null, null); - mCurrentVideoUri = null; - } - } - mActivity.updateStorageSpaceAndHint(); } private void deleteVideoFile(String fileName) { @@ -1599,7 +1564,7 @@ public class VideoModule implements CameraModule, try { if (effectsActive()) { // This is asynchronous, so we can't add to media store now because thumbnail - // may not be ready. In such case addVideoToMediaStore is called later + // may not be ready. In such case saveVideo() is called later // through a callback from the MediaEncoderFilter to EffectsRecorder, // and then to the VideoModule. mEffectsRecorder.stopRecording(); @@ -1647,7 +1612,7 @@ public class VideoModule implements CameraModule, mUI.setOrientationIndicator(0, true); keepScreenOnAwhile(); if (shouldAddToMediaStoreNow) { - if (addVideoToMediaStore()) fail = true; + saveVideo(); } } // always release media recorder if no effects running @@ -1934,7 +1899,8 @@ public class VideoModule implements CameraModule, checkQualityAndStartPreview(); } else if (effectMsg == EffectsRecorder.EFFECT_MSG_RECORDING_DONE) { // This follows the codepath from onStopVideoRecording. - if (mEffectsDisplayResult && !addVideoToMediaStore()) { + if (mEffectsDisplayResult) { + saveVideo(); if (mIsVideoCaptureIntent) { if (mQuickCapture) { doReturnToCaller(true); @@ -1948,7 +1914,6 @@ public class VideoModule implements CameraModule, // had to wait till the effects recording is complete to do this. if (mPaused) { closeVideoFileDescriptor(); - clearVideoNamer(); } } else if (effectMsg == EffectsRecorder.EFFECT_MSG_PREVIEW_RUNNING) { // Enable the shutter button once the preview is complete. @@ -2232,7 +2197,7 @@ public class VideoModule implements CameraModule, Size s = mParameters.getPictureSize(); mActivity.getMediaSaveService().addImage( data, title, dateTaken, loc, s.width, s.height, orientation, - exif, mOnMediaSavedListener, mContentResolver); + exif, mOnPhotoSavedListener, mContentResolver); } private boolean resetEffect() { @@ -2282,90 +2247,6 @@ public class VideoModule implements CameraModule, editor.apply(); } - private void clearVideoNamer() { - if (mVideoNamer != null) { - mVideoNamer.finish(); - mVideoNamer = null; - } - } - - private static class VideoNamer extends Thread { - private boolean mRequestPending; - private ContentResolver mResolver; - private ContentValues mValues; - private boolean mStop; - private Uri mUri; - - // Runs in main thread - public VideoNamer() { - start(); - } - - // Runs in main thread - public synchronized void prepareUri( - ContentResolver resolver, ContentValues values) { - mRequestPending = true; - mResolver = resolver; - mValues = new ContentValues(values); - notifyAll(); - } - - // Runs in main thread - public synchronized Uri getUri() { - // wait until the request is done. - while (mRequestPending) { - try { - wait(); - } catch (InterruptedException ex) { - // ignore. - } - } - Uri uri = mUri; - mUri = null; - return uri; - } - - // Runs in namer thread - @Override - public synchronized void run() { - while (true) { - if (mStop) break; - if (!mRequestPending) { - try { - wait(); - } catch (InterruptedException ex) { - // ignore. - } - continue; - } - cleanOldUri(); - generateUri(); - mRequestPending = false; - notifyAll(); - } - cleanOldUri(); - } - - // Runs in main thread - public synchronized void finish() { - mStop = true; - notifyAll(); - } - - // Runs in namer thread - private void generateUri() { - Uri videoTable = Uri.parse("content://media/external/video/media"); - mUri = mResolver.insert(videoTable, mValues); - } - - // Runs in namer thread - private void cleanOldUri() { - if (mUri == null) return; - mResolver.delete(mUri, null, null); - mUri = null; - } - } - @Override public boolean updateStorageHintOnResume() { return true; |