diff options
Diffstat (limited to 'src/com/android/camera/MediaSaver.java')
-rw-r--r-- | src/com/android/camera/MediaSaver.java | 149 |
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; + } +} |