merge in jb-mr2-release history after reset to master
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 6bfe75e..a052e46 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -42,7 +42,7 @@
</plurals>
<!-- no translation found for pref_camera_timer_sound_default (7066624532144402253) -->
<skip />
- <string name="pref_camera_timer_sound_title" msgid="2469008631966169105">"Emet un so durant el compte enrere"</string>
+ <string name="pref_camera_timer_sound_title" msgid="2469008631966169105">"Sona en compte enr."</string>
<string name="setting_off" msgid="4480039384202951946">"Desactivat"</string>
<string name="setting_on" msgid="8602246224465348901">"Activat"</string>
<string name="pref_video_quality_title" msgid="8245379279801096922">"Qualitat de vídeo"</string>
diff --git a/src/com/android/camera/MediaSaver.java b/src/com/android/camera/MediaSaver.java
new file mode 100644
index 0000000..a3d582e
--- /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;
+ }
+}
diff --git a/src/com/android/camera/PhotoModule.java b/src/com/android/camera/PhotoModule.java
index 640f840..a283e59 100644
--- a/src/com/android/camera/PhotoModule.java
+++ b/src/com/android/camera/PhotoModule.java
@@ -200,9 +200,9 @@
// A view group that contains all the small indicators.
private View mOnScreenIndicators;
- // We use a thread in ImageSaver to do the work of saving images. This
+ // We use a thread in MediaSaver to do the work of saving images. This
// reduces the shot-to-shot time.
- private ImageSaver mImageSaver;
+ private MediaSaver mMediaSaver;
// Similarly, we use a thread to generate the name of the picture and insert
// it into MediaStore while picture taking is still in progress.
private NamedImages mNamedImages;
@@ -304,6 +304,17 @@
private PreviewGestures mGestures;
+ private MediaSaver.OnMediaSavedListener mOnMediaSavedListener = new MediaSaver.OnMediaSavedListener() {
+ @Override
+
+ public void onMediaSaved(Uri uri) {
+ if (uri != null) {
+ mHandler.obtainMessage(UPDATE_SECURE_ALBUM_ITEM, uri).sendToTarget();
+ Util.broadcastNewPicture(mActivity, uri);
+ }
+ }
+ };
+
// The purpose is not to block the main thread in onCreate and onResume.
private class CameraStartUpThread extends Thread {
private volatile boolean mCancelled;
@@ -639,7 +650,7 @@
mShutterButton.setOnShutterButtonListener(this);
mShutterButton.setVisibility(View.VISIBLE);
- mImageSaver = new ImageSaver();
+ mMediaSaver = new MediaSaver(mContentResolver);
mNamedImages = new NamedImages();
mFirstTimeInitialized = true;
@@ -677,7 +688,7 @@
mPreferences, mContentResolver);
mLocationManager.recordLocation(recordLocation);
- mImageSaver = new ImageSaver();
+ mMediaSaver = new MediaSaver(mContentResolver);
mNamedImages = new NamedImages();
initializeZoom();
keepMediaProviderInstance();
@@ -983,8 +994,8 @@
Log.e(TAG, "Unbalanced name/data pair");
} else {
if (date == -1) date = mCaptureStartTime;
- mImageSaver.addImage(jpegData, title, date, mLocation, width, height,
- orientation);
+ mMediaSaver.addImage(jpegData, title, date, mLocation, width, height,
+ orientation, mOnMediaSavedListener);
}
} else {
mJpegImageData = jpegData;
@@ -1033,142 +1044,6 @@
}
}
- // 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;
- }
-
- // 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.
- private class ImageSaver extends Thread {
- private static final int QUEUE_LIMIT = 3;
-
- private ArrayList<SaveRequest> mQueue;
- private boolean mStop;
-
- // Runs in main thread
- public ImageSaver() {
- mQueue = new ArrayList<SaveRequest>();
- start();
- }
-
- // Runs in main thread
- public synchronized boolean queueFull() {
- return (mQueue.size() >= QUEUE_LIMIT);
- }
-
- // Runs in main thread
- public void addImage(final byte[] data, String title, long date, Location loc,
- int width, int height, int orientation) {
- 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;
- synchronized (this) {
- while (mQueue.size() >= 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;
- }
- r = mQueue.get(0);
- }
- storeImage(r.data, r.title, r.date, r.loc, r.width, r.height,
- r.orientation);
- synchronized (this) {
- mQueue.remove(0);
- notifyAll(); // the main thread may wait in addImage
- }
- }
- }
-
- // Runs in main thread
- public void waitDone() {
- synchronized (this) {
- while (!mQueue.isEmpty()) {
- try {
- wait();
- } catch (InterruptedException ex) {
- // ignore.
- }
- }
- }
- }
-
- // Runs in main thread
- public void finish() {
- waitDone();
- synchronized (this) {
- mStop = true;
- notifyAll();
- }
- try {
- join();
- } catch (InterruptedException ex) {
- // ignore.
- }
- }
-
- // Runs in saver thread
- private void 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);
- if (uri != null) {
- mHandler.sendMessage(mHandler.obtainMessage(UPDATE_SECURE_ALBUM_ITEM, uri));
- Util.broadcastNewPicture(mActivity, uri);
- }
- }
- }
-
private static class NamedImages {
private ArrayList<NamedEntity> mQueue;
private boolean mStop;
@@ -1242,7 +1117,7 @@
// If we are already in the middle of taking a snapshot or the image save request
// is full then ignore.
if (mCameraDevice == null || mCameraState == SNAPSHOT_IN_PROGRESS
- || mCameraState == SWITCHING_CAMERA || mImageSaver.queueFull()) {
+ || mCameraState == SWITCHING_CAMERA || mMediaSaver.queueFull()) {
return false;
}
mCaptureStartTime = System.currentTimeMillis();
@@ -1707,9 +1582,9 @@
if (mFaceView != null) mFaceView.clear();
if (mFirstTimeInitialized) {
- if (mImageSaver != null) {
- mImageSaver.finish();
- mImageSaver = null;
+ if (mMediaSaver != null) {
+ mMediaSaver.finish();
+ mMediaSaver = null;
mNamedImages = null;
}
}