summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/MediaSaver.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/MediaSaver.java')
-rw-r--r--src/com/android/camera/MediaSaver.java149
1 files changed, 149 insertions, 0 deletions
diff --git a/src/com/android/camera/MediaSaver.java b/src/com/android/camera/MediaSaver.java
new file mode 100644
index 000000000..a3d582e1c
--- /dev/null
+++ b/src/com/android/camera/MediaSaver.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2013 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.location.Location;
+import android.net.Uri;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+// We use a queue to store the SaveRequests that have not been completed
+// yet. The main thread puts the request into the queue. The saver thread
+// gets it from the queue, does the work, and removes it from the queue.
+//
+// The main thread needs to wait for the saver thread to finish all the work
+// in the queue, when the activity's onPause() is called, we need to finish
+// all the work, so other programs (like Gallery) can see all the images.
+//
+// If the queue becomes too long, adding a new request will block the main
+// thread until the queue length drops below the threshold (QUEUE_LIMIT).
+// If we don't do this, we may face several problems: (1) We may OOM
+// because we are holding all the jpeg data in memory. (2) We may ANR
+// when we need to wait for saver thread finishing all the work (in
+// onPause() or gotoGallery()) because the time to finishing a long queue
+// of work may be too long.
+class MediaSaver extends Thread {
+ private static final int SAVE_QUEUE_LIMIT = 3;
+ private static final String TAG = "MediaSaver";
+
+ private ArrayList<SaveRequest> mQueue;
+ private boolean mStop;
+ private ContentResolver mContentResolver;
+
+ public interface OnMediaSavedListener {
+ public void onMediaSaved(Uri uri);
+ }
+
+ public MediaSaver(ContentResolver resolver) {
+ mContentResolver = resolver;
+ mQueue = new ArrayList<SaveRequest>();
+ start();
+ }
+
+ // Runs in main thread
+ public synchronized boolean queueFull() {
+ return (mQueue.size() >= SAVE_QUEUE_LIMIT);
+ }
+
+ // Runs in main thread
+ public void addImage(final byte[] data, String title, long date, Location loc,
+ int width, int height, int orientation, OnMediaSavedListener l) {
+ SaveRequest r = new SaveRequest();
+ r.data = data;
+ r.date = date;
+ r.title = title;
+ r.loc = (loc == null) ? null : new Location(loc); // make a copy
+ r.width = width;
+ r.height = height;
+ r.orientation = orientation;
+ r.listener = l;
+ synchronized (this) {
+ while (mQueue.size() >= SAVE_QUEUE_LIMIT) {
+ try {
+ wait();
+ } catch (InterruptedException ex) {
+ // ignore.
+ }
+ }
+ mQueue.add(r);
+ notifyAll(); // Tell saver thread there is new work to do.
+ }
+ }
+
+ // Runs in saver thread
+ @Override
+ public void run() {
+ while (true) {
+ SaveRequest r;
+ synchronized (this) {
+ if (mQueue.isEmpty()) {
+ notifyAll(); // notify main thread in waitDone
+
+ // Note that we can only stop after we saved all images
+ // in the queue.
+ if (mStop) break;
+
+ try {
+ wait();
+ } catch (InterruptedException ex) {
+ // ignore.
+ }
+ continue;
+ }
+ if (mStop) break;
+ r = mQueue.remove(0);
+ notifyAll(); // the main thread may wait in addImage
+ }
+ Uri uri = storeImage(r.data, r.title, r.date, r.loc, r.width, r.height,
+ r.orientation);
+ r.listener.onMediaSaved(uri);
+ }
+ if (!mQueue.isEmpty()) {
+ Log.e(TAG, "Media saver thread stopped with " + mQueue.size() + " images unsaved");
+ mQueue.clear();
+ }
+ }
+
+ // Runs in main thread
+ public void finish() {
+ synchronized (this) {
+ mStop = true;
+ notifyAll();
+ }
+ }
+
+ // Runs in saver thread
+ private Uri storeImage(final byte[] data, String title, long date,
+ Location loc, int width, int height, int orientation) {
+ Uri uri = Storage.addImage(mContentResolver, title, date, loc,
+ orientation, data, width, height);
+ return uri;
+ }
+
+ // Each SaveRequest remembers the data needed to save an image.
+ private static class SaveRequest {
+ byte[] data;
+ String title;
+ long date;
+ Location loc;
+ int width, height;
+ int orientation;
+ OnMediaSavedListener listener;
+ }
+}