summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAngus Kong <shkong@google.com>2013-04-17 15:37:07 -0700
committerAngus Kong <shkong@google.com>2013-04-19 12:46:08 -0700
commit83a99ae51a11af28553dfb77ef0ec91148671c9b (patch)
tree6a954b37ccd589bd1f419acaedbd1c0c25a1b713 /src
parentb0e82433a948ab7625d5c0343a4207ea9a45bbf7 (diff)
downloadandroid_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')
-rw-r--r--src/com/android/camera/MediaSaveService.java81
-rw-r--r--src/com/android/camera/VideoModule.java165
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;