summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera
diff options
context:
space:
mode:
authorRuben Brunk <rubenbrunk@google.com>2013-10-17 15:41:44 -0700
committerRuben Brunk <rubenbrunk@google.com>2013-10-28 11:13:40 -0700
commit7cfcafdf8f4a439c8fa87b612616fe409979e8a4 (patch)
tree57e306c62dcc4d57c14562fd4c9bc287e4da85d9 /src/com/android/camera
parentd053a5b2aa8cd9cb09bd40962b305ef34e7d404b (diff)
downloadandroid_packages_apps_Snap-7cfcafdf8f4a439c8fa87b612616fe409979e8a4.tar.gz
android_packages_apps_Snap-7cfcafdf8f4a439c8fa87b612616fe409979e8a4.tar.bz2
android_packages_apps_Snap-7cfcafdf8f4a439c8fa87b612616fe409979e8a4.zip
gcam: Add placeholder image.
Bug: 11050749 Change-Id: I374c5919d6da0609fccd21c09775fa91894d5a24
Diffstat (limited to 'src/com/android/camera')
-rw-r--r--src/com/android/camera/CameraActivity.java42
-rw-r--r--src/com/android/camera/Storage.java98
-rw-r--r--src/com/android/camera/WideAnglePanoramaModule.java5
-rw-r--r--src/com/android/camera/app/AppManagerFactory.java8
-rw-r--r--src/com/android/camera/app/PlaceholderManager.java185
-rw-r--r--src/com/android/camera/data/InProgressDataWrapper.java22
6 files changed, 334 insertions, 26 deletions
diff --git a/src/com/android/camera/CameraActivity.java b/src/com/android/camera/CameraActivity.java
index b971b284f..eb2da1d1b 100644
--- a/src/com/android/camera/CameraActivity.java
+++ b/src/com/android/camera/CameraActivity.java
@@ -64,6 +64,7 @@ import android.widget.ProgressBar;
import android.widget.ShareActionProvider;
import com.android.camera.app.AppManagerFactory;
+import com.android.camera.app.PlaceholderManager;
import com.android.camera.app.PanoramaStitchingManager;
import com.android.camera.crop.CropActivity;
import com.android.camera.data.CameraDataAdapter;
@@ -143,6 +144,7 @@ public class CameraActivity extends Activity
private LocalDataAdapter mWrappedDataAdapter;
private PanoramaStitchingManager mPanoramaManager;
+ private PlaceholderManager mPlaceholderManager;
private int mCurrentModuleIndex;
private CameraModule mCurrentModule;
private FrameLayout mAboveFilmstripControlLayout;
@@ -688,6 +690,41 @@ public class CameraActivity extends Activity
item.setVisible(visible);
}
+ private ImageTaskManager.TaskListener mPlaceholderListener =
+ new ImageTaskManager.TaskListener() {
+
+ @Override
+ public void onTaskQueued(String filePath, final Uri imageUri) {
+ mMainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ notifyNewMedia(imageUri);
+ int dataID = mDataAdapter.findDataByContentUri(imageUri);
+ if (dataID != -1) {
+ LocalData d = mDataAdapter.getLocalData(dataID);
+ InProgressDataWrapper newData = new InProgressDataWrapper(d, true);
+ mDataAdapter.updateData(dataID, newData);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void onTaskDone(String filePath, final Uri imageUri) {
+ mMainHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mDataAdapter.refresh(getContentResolver(), imageUri);
+ }
+ });
+ }
+
+ @Override
+ public void onTaskProgress(String filePath, Uri imageUri, int progress) {
+ // Do nothing
+ }
+ };
+
private ImageTaskManager.TaskListener mStitchingListener =
new ImageTaskManager.TaskListener() {
@Override
@@ -761,6 +798,8 @@ public class CameraActivity extends Activity
mDataAdapter.addNewPhoto(cr, uri);
} else if (mimeType.startsWith("application/stitching-preview")) {
mDataAdapter.addNewPhoto(cr, uri);
+ } else if (mimeType.startsWith(PlaceholderManager.PLACEHOLDER_MIME_TYPE)) {
+ mDataAdapter.addNewPhoto(cr, uri);
} else {
android.util.Log.w(TAG, "Unknown new media with MIME type:"
+ mimeType + ", uri:" + uri);
@@ -966,7 +1005,10 @@ public class CameraActivity extends Activity
this.setSystemBarsVisibility(false);
mPanoramaManager = AppManagerFactory.getInstance(this)
.getPanoramaStitchingManager();
+ mPlaceholderManager = AppManagerFactory.getInstance(this)
+ .getGcamProcessingManager();
mPanoramaManager.addTaskListener(mStitchingListener);
+ mPlaceholderManager.addTaskListener(mPlaceholderListener);
LayoutInflater inflater = getLayoutInflater();
View rootLayout = inflater.inflate(R.layout.camera, null, false);
mCameraModuleRootView = rootLayout.findViewById(R.id.camera_app_root);
diff --git a/src/com/android/camera/Storage.java b/src/com/android/camera/Storage.java
index a8ce08b93..499d03029 100644
--- a/src/com/android/camera/Storage.java
+++ b/src/com/android/camera/Storage.java
@@ -43,6 +43,7 @@ public class Storage {
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).toString();
public static final String DIRECTORY = DCIM + "/Camera";
+ public static final String JPEG_POSTFIX = ".jpg";
// Match the code in MediaProvider.computeBucketValues().
public static final String BUCKET_ID =
@@ -62,6 +63,18 @@ public class Storage {
}
}
+ public static void writeFile(String path, byte[] jpeg, ExifInterface exif) {
+ if (exif != null) {
+ try {
+ exif.writeExif(jpeg, path);
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to write data", e);
+ }
+ } else {
+ writeFile(path, jpeg);
+ }
+ }
+
public static void writeFile(String path, byte[] data) {
FileOutputStream out = null;
try {
@@ -73,39 +86,41 @@ public class Storage {
try {
out.close();
} catch (Exception e) {
+ Log.e(TAG, "Failed to close file after write", e);
}
}
}
- // Save the image and add it to media store.
- public static Uri addImage(ContentResolver resolver, String title,
- long date, Location location, int orientation, ExifInterface exif,
- byte[] jpeg, int width, int height) {
- // Save the image.
+ // Save the image and add it to the MediaStore.
+ public static Uri addImage(ContentResolver resolver, String title, long date,
+ Location location, int orientation, ExifInterface exif, byte[] jpeg, int width,
+ int height) {
+
+ return addImage(resolver, title, date, location, orientation, exif, jpeg, width, height,
+ LocalData.MIME_TYPE_JPEG);
+ }
+
+ // Save the image with a given mimeType and add it the MediaStore.
+ public static Uri addImage(ContentResolver resolver, String title, long date,
+ Location location, int orientation, ExifInterface exif, byte[] jpeg, int width,
+ int height, String mimeType) {
+
String path = generateFilepath(title);
- if (exif != null) {
- try {
- exif.writeExif(jpeg, path);
- } catch (Exception e) {
- Log.e(TAG, "Failed to write data", e);
- }
- } else {
- writeFile(path, jpeg);
- }
+ writeFile(path, jpeg, exif);
return addImage(resolver, title, date, location, orientation,
- jpeg.length, path, width, height);
+ jpeg.length, path, width, height, mimeType);
}
- // Add the image to media store.
- public static Uri addImage(ContentResolver resolver, String title,
+ // Get a ContentValues object for the given photo data
+ public static ContentValues getContentValuesForData(String title,
long date, Location location, int orientation, int jpegLength,
- String path, int width, int height) {
- // Insert into MediaStore.
- ContentValues values = new ContentValues(9);
+ String path, int width, int height, String mimeType) {
+
+ ContentValues values = new ContentValues(11);
values.put(ImageColumns.TITLE, title);
- values.put(ImageColumns.DISPLAY_NAME, title + ".jpg");
+ values.put(ImageColumns.DISPLAY_NAME, title + JPEG_POSTFIX);
values.put(ImageColumns.DATE_TAKEN, date);
- values.put(ImageColumns.MIME_TYPE, LocalData.MIME_TYPE_JPEG);
+ values.put(ImageColumns.MIME_TYPE, mimeType);
// Clockwise rotation in degrees. 0, 90, 180, or 270.
values.put(ImageColumns.ORIENTATION, orientation);
values.put(ImageColumns.DATA, path);
@@ -117,6 +132,17 @@ public class Storage {
values.put(ImageColumns.LATITUDE, location.getLatitude());
values.put(ImageColumns.LONGITUDE, location.getLongitude());
}
+ return values;
+ }
+
+ // Add the image to media store.
+ public static Uri addImage(ContentResolver resolver, String title,
+ long date, Location location, int orientation, int jpegLength,
+ String path, int width, int height, String mimeType) {
+ // Insert into MediaStore.
+ ContentValues values =
+ getContentValuesForData(title, date, location, orientation, jpegLength, path,
+ width, height, mimeType);
Uri uri = null;
try {
@@ -132,6 +158,34 @@ public class Storage {
return uri;
}
+ // Overwrites the file and updates the MediaStore
+ public static void updateImage(Uri imageUri, ContentResolver resolver, String title, long date,
+ Location location, int orientation, ExifInterface exif, byte[] jpeg, int width,
+ int height, String mimeType) {
+ String path = generateFilepath(title);
+ writeFile(path, jpeg, exif);
+ updateImage(imageUri, resolver, title, date, location, orientation, jpeg.length, path,
+ width, height, mimeType);
+ }
+
+ // Updates the image values in MediaStore
+ public static void updateImage(Uri imageUri, ContentResolver resolver, String title,
+ long date, Location location, int orientation, int jpegLength,
+ String path, int width, int height, String mimeType) {
+
+ ContentValues values =
+ getContentValuesForData(title, date, location, orientation, jpegLength, path,
+ width, height, mimeType);
+
+ // Update the MediaStore
+ int rowsModified = resolver.update(imageUri, values, null, null);
+ if (rowsModified != 1) {
+ // This should never happen
+ throw new IllegalStateException("Bad number of rows (" + rowsModified
+ + ") updated for uri: " + imageUri);
+ }
+ }
+
public static void deleteImage(ContentResolver resolver, Uri uri) {
try {
resolver.delete(uri, null, null);
diff --git a/src/com/android/camera/WideAnglePanoramaModule.java b/src/com/android/camera/WideAnglePanoramaModule.java
index 20e8885d1..8d00c70c8 100644
--- a/src/com/android/camera/WideAnglePanoramaModule.java
+++ b/src/com/android/camera/WideAnglePanoramaModule.java
@@ -46,6 +46,7 @@ import android.view.WindowManager;
import com.android.camera.CameraManager.CameraProxy;
import com.android.camera.app.OrientationManager;
+import com.android.camera.data.LocalData;
import com.android.camera.exif.ExifInterface;
import com.android.camera.util.CameraUtil;
import com.android.camera.util.UsageStatistics;
@@ -759,8 +760,8 @@ public class WideAnglePanoramaModule
Storage.writeFile(filepath, jpegData);
}
int jpegLength = (int) (new File(filepath).length());
- return Storage.addImage(mContentResolver, filename, mTimeTaken,
- loc, orientation, jpegLength, filepath, width, height);
+ return Storage.addImage(mContentResolver, filename, mTimeTaken, loc, orientation,
+ jpegLength, filepath, width, height, LocalData.MIME_TYPE_JPEG);
}
return null;
}
diff --git a/src/com/android/camera/app/AppManagerFactory.java b/src/com/android/camera/app/AppManagerFactory.java
index 9c047aa55..43d2a00cd 100644
--- a/src/com/android/camera/app/AppManagerFactory.java
+++ b/src/com/android/camera/app/AppManagerFactory.java
@@ -16,9 +16,9 @@
package com.android.camera.app;
-import android.app.Application;
import android.content.Context;
+
/**
* A singleton class which provides application level utility
* classes.
@@ -35,13 +35,19 @@ public class AppManagerFactory {
}
private PanoramaStitchingManager mPanoramaStitchingManager;
+ private PlaceholderManager mGcamProcessingManager;
/** No public constructor. */
private AppManagerFactory(Context ctx) {
mPanoramaStitchingManager = new PanoramaStitchingManager(ctx);
+ mGcamProcessingManager = new PlaceholderManager(ctx);
}
public PanoramaStitchingManager getPanoramaStitchingManager() {
return mPanoramaStitchingManager;
}
+
+ public PlaceholderManager getGcamProcessingManager() {
+ return mGcamProcessingManager;
+ }
}
diff --git a/src/com/android/camera/app/PlaceholderManager.java b/src/com/android/camera/app/PlaceholderManager.java
new file mode 100644
index 000000000..326f0be80
--- /dev/null
+++ b/src/com/android/camera/app/PlaceholderManager.java
@@ -0,0 +1,185 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.graphics.BitmapFactory;
+import android.location.Location;
+import android.net.Uri;
+
+import com.android.camera.ImageTaskManager;
+import com.android.camera.Storage;
+import com.android.camera.exif.ExifInterface;
+import com.android.camera.util.CameraUtil;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+public class PlaceholderManager implements ImageTaskManager {
+ private static final String TAG = "PlaceholderManager";
+
+ public static final String PLACEHOLDER_MIME_TYPE = "application/placeholder-image";
+ private final Context mContext;
+
+ final private ArrayList<WeakReference<TaskListener>> mListenerRefs;
+
+ public static class Session {
+ String outputTitle;
+ Uri outputUri;
+ long time;
+
+ Session(String title, Uri uri, long timestamp) {
+ outputTitle = title;
+ outputUri = uri;
+ time = timestamp;
+ }
+ }
+
+ public PlaceholderManager(Context context) {
+ mContext = context;
+ mListenerRefs = new ArrayList<WeakReference<TaskListener>>();
+ }
+
+ @Override
+ public void addTaskListener(TaskListener l) {
+ synchronized (mListenerRefs) {
+ if (findTaskListener(l) == -1) {
+ mListenerRefs.add(new WeakReference<TaskListener>(l));
+ }
+ }
+ }
+
+ @Override
+ public void removeTaskListener(TaskListener l) {
+ synchronized (mListenerRefs) {
+ int i = findTaskListener(l);
+ if (i != -1) {
+ mListenerRefs.remove(i);
+ }
+ }
+ }
+
+ @Override
+ public int getTaskProgress(Uri uri) {
+ return 0;
+ }
+
+ private int findTaskListener(TaskListener listener) {
+ int index = -1;
+ for (int i = 0; i < mListenerRefs.size(); i++) {
+ TaskListener l = mListenerRefs.get(i).get();
+ if (l != null && l == listener) {
+ index = i;
+ break;
+ }
+ }
+ return index;
+ }
+
+ private Iterable<TaskListener> getListeners() {
+ return new Iterable<TaskListener>() {
+ @Override
+ public Iterator<TaskListener> iterator() {
+ return new ListenerIterator();
+ }
+ };
+ }
+
+ private class ListenerIterator implements Iterator<TaskListener> {
+ private int mIndex = 0;
+ private TaskListener mNext = null;
+
+ @Override
+ public boolean hasNext() {
+ while (mNext == null && mIndex < mListenerRefs.size()) {
+ mNext = mListenerRefs.get(mIndex).get();
+ if (mNext == null) {
+ mListenerRefs.remove(mIndex);
+ }
+ }
+ return mNext != null;
+ }
+
+ @Override
+ public TaskListener next() {
+ hasNext(); // Populates mNext
+ mIndex++;
+ TaskListener next = mNext;
+ mNext = null;
+ return next;
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public Session insertPlaceholder(String title, byte[] placeholder, long timestamp) {
+ if (title == null || placeholder == null) {
+ throw new IllegalArgumentException("Null argument passed to insertPlaceholder");
+ }
+
+ // Decode bounds
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeByteArray(placeholder, 0, placeholder.length, options);
+ int width = options.outWidth;
+ int height = options.outHeight;
+
+ if (width <= 0 || height <= 0) {
+ throw new IllegalArgumentException("Image had bad height/width");
+ }
+
+ Uri uri =
+ Storage.addImage(mContext.getContentResolver(), title, timestamp, null, 0, null,
+ placeholder, width, height, PLACEHOLDER_MIME_TYPE);
+
+ if (uri == null) {
+ return null;
+ }
+
+ String filePath = uri.getPath();
+ synchronized (mListenerRefs) {
+ for (TaskListener l : getListeners()) {
+ l.onTaskQueued(filePath, uri);
+ }
+ }
+
+ return new Session(title, uri, timestamp);
+ }
+
+ public void replacePlaceholder(Session session, Location location, int orientation,
+ ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) {
+
+ Storage.updateImage(session.outputUri, mContext.getContentResolver(), session.outputTitle,
+ session.time, location, orientation, exif, jpeg, width, height, mimeType);
+
+ synchronized (mListenerRefs) {
+ for (TaskListener l : getListeners()) {
+ l.onTaskDone(session.outputUri.getPath(), session.outputUri);
+ }
+ }
+ CameraUtil.broadcastNewPicture(mContext, session.outputUri);
+ }
+
+ public void removePlaceholder(Session session) {
+ Storage.deleteImage(mContext.getContentResolver(), session.outputUri);
+ }
+
+}
diff --git a/src/com/android/camera/data/InProgressDataWrapper.java b/src/com/android/camera/data/InProgressDataWrapper.java
index 7de617bae..61e87b722 100644
--- a/src/com/android/camera/data/InProgressDataWrapper.java
+++ b/src/com/android/camera/data/InProgressDataWrapper.java
@@ -22,8 +22,10 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.view.View;
+import android.widget.FrameLayout;
import com.android.camera.util.PhotoSphereHelper;
+import com.android.camera2.R;
/**
* A wrapper class for in-progress data. Data that's still being processed
@@ -34,16 +36,34 @@ import com.android.camera.util.PhotoSphereHelper;
public class InProgressDataWrapper implements LocalData {
final LocalData mLocalData;
+ private boolean mHasProgressBar;
public InProgressDataWrapper(LocalData wrappedData) {
mLocalData = wrappedData;
}
+ public InProgressDataWrapper(LocalData wrappedData, boolean hasProgressBar) {
+ this(wrappedData);
+ mHasProgressBar = hasProgressBar;
+ }
+
@Override
public View getView(
Activity a, int width, int height,
Drawable placeHolder, LocalDataAdapter adapter) {
- return mLocalData.getView(a, width, height, placeHolder, adapter);
+ View v = mLocalData.getView(a, width, height, placeHolder, adapter);
+
+ if (mHasProgressBar) {
+ // Return a framelayout with the progressbar and imageview.
+ FrameLayout frame = new FrameLayout(a);
+ frame.setLayoutParams(new FrameLayout.LayoutParams(width, height));
+ frame.addView(v);
+ a.getLayoutInflater()
+ .inflate(R.layout.placeholder_progressbar, frame);
+ return frame;
+ }
+
+ return v;
}
@Override