import com.android.camera.app.OrientationManagerImpl;
import com.android.camera.data.CameraDataAdapter;
import com.android.camera.data.FixedLastDataAdapter;
-import com.android.camera.data.InProgressDataWrapper;
import com.android.camera.data.LocalData;
import com.android.camera.data.LocalDataAdapter;
import com.android.camera.data.LocalDataUtil;
@Override
public void onSessionQueued(final Uri uri) {
notifyNewMedia(uri);
- int dataId = mDataAdapter.findDataByContentUri(uri);
- if (dataId != -1) {
- // Don't allow special UI actions (swipe to
- // delete, for example) on in-progress data.
- LocalData d = mDataAdapter.getLocalData(dataId);
- InProgressDataWrapper newData = new InProgressDataWrapper(d);
- mDataAdapter.updateData(dataId, newData);
- }
}
@Override
public void onSessionDone(final Uri uri) {
Log.v(TAG, "onSessionDone:" + uri);
- int doneId = mDataAdapter.findDataByContentUri(uri);
- int currentDataId = mFilmstripController.getCurrentId();
-
- if (currentDataId == doneId) {
- hideSessionProgress();
- updateSessionProgress(0);
- }
- mDataAdapter.refresh(uri, /* isInProgress */false);
+ mDataAdapter.finishSession(uri);
}
@Override
@Override
public void onSessionUpdated(Uri uri) {
- mDataAdapter.refresh(uri, /* isInProgress */true);
+ mDataAdapter.refresh(uri);
}
@Override
updateSessionProgress(0);
showProcessError(reason);
}
- mDataAdapter.refresh(uri, /* isInProgress */false);
+ // HERE
+ mDataAdapter.refresh(uri);
}
};
@Override
public void notifyNewMedia(Uri uri) {
- ContentResolver cr = getContentResolver();
- String mimeType = cr.getType(uri);
- if (LocalDataUtil.isMimeTypeVideo(mimeType)) {
- sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri));
- mDataAdapter.addNewVideo(uri);
- } else if (LocalDataUtil.isMimeTypeImage(mimeType)) {
- CameraUtil.broadcastNewPicture(mAppContext, uri);
- mDataAdapter.addNewPhoto(uri);
- } else if (LocalDataUtil.isMimeTypePlaceHolder(mimeType)) {
- mDataAdapter.addNewPhoto(uri);
+ if (Storage.isSessionUri(uri)) {
+ mDataAdapter.addNewSession(uri);
} else {
- android.util.Log.w(TAG, "Unknown new media with MIME type:"
- + mimeType + ", uri:" + uri);
+
+ ContentResolver cr = getContentResolver();
+ String mimeType = cr.getType(uri);
+ if (LocalDataUtil.isMimeTypeVideo(mimeType)) {
+ sendBroadcast(new Intent(CameraUtil.ACTION_NEW_VIDEO, uri));
+ mDataAdapter.addNewVideo(uri);
+ } else if (LocalDataUtil.isMimeTypeImage(mimeType)) {
+ CameraUtil.broadcastNewPicture(mAppContext, uri);
+ mDataAdapter.addNewPhoto(uri);
+ } else {
+ android.util.Log.w(TAG, "Unknown new media with MIME type:"
+ + mimeType + ", uri:" + uri);
+ }
}
}
} else {
LocalData data = mDataAdapter.getLocalData(mFilmstripController.getCurrentId());
if (data != null) {
- mDataAdapter.refresh(data.getContentUri(), false);
+ mDataAdapter.refresh(data.getContentUri());
}
}
// The share button might be disabled to avoid double tapping.
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentValues;
+import android.graphics.Point;
import android.location.Location;
import android.net.Uri;
import android.os.Build;
import java.io.File;
import java.io.FileOutputStream;
+import java.util.HashMap;
+import java.util.UUID;
public class Storage {
- private static final String TAG = "CameraStorage";
-
public static final String DCIM =
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 =
String.valueOf(DIRECTORY.toLowerCase().hashCode());
-
public static final long UNAVAILABLE = -1L;
public static final long PREPARING = -2L;
public static final long UNKNOWN_SIZE = -3L;
public static final long LOW_STORAGE_THRESHOLD_BYTES = 50000000;
+ public static final String CAMERA_SESSION_SCHEME = "camera_session";
+ private static final String TAG = "Storage";
+ private static final String GOOGLE_COM = "google.com";
+ private static HashMap<Uri, Uri> sSessionsToContentUris = new HashMap<Uri, Uri>();
+ private static HashMap<Uri, byte[]> sSessionsToPlaceholderBytes = new HashMap<Uri, byte[]>();
+ private static HashMap<Uri, Point> sSessionsToSizes= new HashMap<Uri, Point>();
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private static void setImageSize(ContentValues values, int width, int height) {
return values;
}
+ /**
+ * Add a placeholder for a new image that does not exist yet.
+ * @param jpeg the bytes of the placeholder image
+ * @param width the image's width
+ * @param height the image's height
+ * @return A new URI used to reference this placeholder
+ */
+ public static Uri addPlaceholder(byte[] jpeg, int width, int height) {
+ Uri uri;
+ Uri.Builder builder = new Uri.Builder();
+ String uuid = UUID.randomUUID().toString();
+ builder.scheme(CAMERA_SESSION_SCHEME).authority(GOOGLE_COM).appendPath(uuid);
+ uri = builder.build();
+
+ replacePlaceholder(uri, jpeg, width, height);
+ return uri;
+ }
+
+ /**
+ * Add or replace placeholder for a new image that does not exist yet.
+ * @param uri the uri of the placeholder to replace, or null if this is a new one
+ * @param jpeg the bytes of the placeholder image
+ * @param width the image's width
+ * @param height the image's height
+ * @return A URI used to reference this placeholder
+ */
+ public static void replacePlaceholder(Uri uri, byte[] jpeg, int width, int height) {
+ Point size = new Point(width, height);
+ sSessionsToSizes.put(uri, size);
+ sSessionsToPlaceholderBytes.put(uri, jpeg);
+ }
+
// Add the image to media store.
public static Uri addImage(ContentResolver resolver, String title,
long date, Location location, int orientation, int jpegLength,
}
// 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) {
+
+ /**
+ * Take jpeg bytes and add them to the media store, either replacing an existing item
+ * or a placeholder uri to replace
+ * @param imageUri The content uri or session uri of the image being updated
+ * @param resolver The content resolver to use
+ * @param title of the image
+ * @param date of the image
+ * @param location of the image
+ * @param orientation of the image
+ * @param exif of the image
+ * @param jpeg bytes of the image
+ * @param width of the image
+ * @param height of the image
+ * @param mimeType of the image
+ * @return The content uri of the newly inserted or replaced item.
+ */
+ public static Uri 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,
+ return 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,
+ private static Uri updateImage(Uri imageUri, ContentResolver resolver, String title,
long date, Location location, int orientation, int jpegLength,
String path, int width, int height, String mimeType) {
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);
+
+ Uri resultUri = imageUri;
+ if (Storage.isSessionUri(imageUri)) {
+ // If this is a session uri, then we need to add the image
+ resultUri = addImage(resolver, title, date, location, orientation, jpegLength, path,
+ width, height, mimeType);
+ sSessionsToContentUris.put(imageUri, resultUri);
+ } else {
+ // 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);
+ }
}
+ return resultUri;
}
/**
* switching an image to an in-progress type for re-processing.
*
* @param uri the URI of the item to change
- * @param mimeeType the new mime type of the item
+ * @param mimeType the new mime type of the item
*/
public static void updateItemMimeType(Uri uri, String mimeType, ContentResolver resolver) {
ContentValues values = new ContentValues(1);
return DIRECTORY + '/' + title + ".jpg";
}
+ /**
+ * Returns the jpeg bytes for a placeholder session
+ *
+ * @param uri the session uri to look up
+ * @return The jpeg bytes or null
+ */
+ public static byte[] getJpegForSession(Uri uri) {
+ return sSessionsToPlaceholderBytes.get(uri);
+ }
+
+ /**
+ * Returns the dimensions of the placeholder image
+ *
+ * @param uri the session uri to look up
+ * @return The size
+ */
+ public static Point getSizeForSession(Uri uri) {
+ return sSessionsToSizes.get(uri);
+ }
+
+ /**
+ * Takes a session URI and returns the finished image's content URI
+ *
+ * @param uri the uri of the session that was replaced
+ * @return The uri of the new media item, if it exists, or null.
+ */
+ public static Uri getContentUriForSessionUri(Uri uri) {
+ return sSessionsToContentUris.get(uri);
+ }
+
+ /**
+ * Determines if a URI points to a camera session
+ *
+ * @param uri the uri to check
+ * @return true if it is a session uri.
+ */
+ public static boolean isSessionUri(Uri uri) {
+ return uri.getScheme().equals(CAMERA_SESSION_SCHEME);
+ }
+
public static long getAvailableSpace() {
String state = Environment.getExternalStorageState();
Log.d(TAG, "External storage state=" + state);
Log.e(TAG, "Failed to create " + nnnAAAAA.getPath());
}
}
+
}
}
@Override
+ public void addNewSession(Uri uri) {
+ mAdapter.addNewSession(uri);
+ }
+
+ @Override
public void insertData(LocalData data) {
mAdapter.insertData(data);
}
}
@Override
- public void refresh(Uri uri, boolean isInProgressSession) {
- mAdapter.refresh(uri, isInProgressSession);
+ public void finishSession(Uri uri) {
+ mAdapter.finishSession(uri);
+ }
+ @Override
+ public void refresh(Uri uri) {
+ mAdapter.refresh(uri);
}
@Override
}
}
- // TODO: put the database query on background thread
- @Override
- public void addNewPhoto(Uri uri) {
+ private LocalData localDataFromUri(Uri uri) {
Cursor cursor = mContext.getContentResolver().query(uri,
LocalMediaData.PhotoData.QUERY_PROJECTION,
MediaStore.Images.Media.DATA + " like ? ", CAMERA_PATH,
try {
if (cursor == null || !cursor.moveToFirst()) {
- return;
+ return null;
}
newData = LocalMediaData.PhotoData.buildFromCursor(mContext, cursor);
} finally {
cursor.close();
}
}
+ return newData;
+ }
+
+ // TODO: put the database query on background thread
+ @Override
+ public void addNewPhoto(Uri uri) {
+ LocalData newData = localDataFromUri(uri);
+ addData(uri, newData);
+ }
+
+ @Override
+ public void addNewSession(Uri uri) {
+ LocalSessionData newData = new LocalSessionData(uri);
+ addData(uri, newData);
+ }
+
+ private void addData(Uri uri, LocalData newData) {
int pos = findDataByContentUri(uri);
if (pos != -1) {
// a duplicate one, just do a substitute.
}
@Override
- public void refresh(Uri contentUri, boolean isInProgressSession) {
- final int pos = findDataByContentUri(contentUri);
+ public void finishSession(Uri sessionUri) {
+ Uri contentUri = Storage.getContentUriForSessionUri(sessionUri);
+ if (contentUri == null) {
+ refresh(sessionUri);
+ return;
+ }
+ final int pos = findDataByContentUri(sessionUri);
+ if (pos == -1) {
+ throw new IllegalAccessError("Finishing invalid uri");
+ }
+ LocalData newData = localDataFromUri(contentUri);
+ updateData(pos, newData);
+ }
+
+ @Override
+ public void refresh(Uri uri) {
+ final int pos = findDataByContentUri(uri);
if (pos == -1) {
return;
}
mListener.onDataRemoved(pos, data);
return;
}
-
- // Wrap the data item if this represents a session that is in progress.
- if (isInProgressSession) {
- refreshedData = new InProgressDataWrapper(refreshedData);
- }
-
updateData(pos, refreshedData);
}
while (true) {
LocalData data = LocalMediaData.PhotoData.buildFromCursor(mContext, c);
if (data != null) {
- if (data.getMimeType().equals(PlaceholderManager.PLACEHOLDER_MIME_TYPE)) {
- l.add(new InProgressDataWrapper(data));
- } else {
- l.add(data);
- }
+ l.add(data);
} else {
Log.e(TAG, "Error loading data:"
+ c.getString(LocalMediaData.PhotoData.COL_DATA));
public void addNewPhoto(Uri uri);
/**
+ * Adds new placeholder uri.
+ *
+ * @param uri the uri of the session to find the placeholder images
+ */
+ public void addNewSession(Uri uri);
+
+ /**
+ * Called when a session is done processing
+ *
+ * @param uri {@link Uri} of the session.
+ */
+ public void finishSession(Uri uri);
+
+ /**
* Refresh the data by {@link Uri}.
*
* @param uri The {@link Uri} of the data to refresh.
- * @param isInProgressSession Whether this data item has a session in
- * progress associated with it.
*/
- public void refresh(Uri uri, boolean isInProgressSession);
+ public void refresh(Uri uri);
/**
* Finds the {@link LocalData} of the specified content Uri.
}
/**
- * @param mimeType The MIME type to check.
- * @return Whether the MIME is a placeholder type.
- * @see {@link com.android.camera.session.PlaceholderManager}.
- */
- public static boolean isMimeTypePlaceHolder(String mimeType) {
- return mimeType.startsWith(PlaceholderManager.PLACEHOLDER_MIME_TYPE);
- }
-
- /**
* Decodes the dimension of a bitmap.
*
* @param path The path to the bitmap.
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
if (mNeedsRefresh && mAdapter != null) {
- mAdapter.refresh(getContentUri(), mIsInProgressSession);
+ mAdapter.refresh(getContentUri());
}
}
}
/*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2014 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.
package com.android.camera.data;
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
-import android.view.LayoutInflater;
import android.view.View;
-import android.widget.FrameLayout;
+import android.widget.ImageView;
-import com.android.camera2.R;
+import com.android.camera.Storage;
+
+import java.util.Date;
/**
- * A wrapper class for in-progress data. Data that's still being processed
- * should not supporting any actions. Only methods related to actions like
- * {@link #isDataActionSupported(int)} and
- * {@link #isUIActionSupported(int)} are implemented by this class.
+ * This is used to represent a local data item that is in progress and not
+ * yet in the media store.
*/
-public class InProgressDataWrapper implements LocalData {
+public class LocalSessionData implements LocalData {
- final LocalData mLocalData;
+ private Uri mUri;
+ private long mDateTaken;
+ protected final Bundle mMetaData;
+ private int mWidth;
+ private int mHeight;
- public InProgressDataWrapper(LocalData wrappedData) {
- mLocalData = wrappedData;
+ public LocalSessionData(Uri uri) {
+ mUri = uri;
+ mMetaData = new Bundle();
+ mDateTaken = new Date().getTime();
+ Point size = Storage.getSizeForSession(uri);
+ mWidth = size.x;
+ mHeight = size.y;
}
@Override
- public View getView(
- Context context, int width, int height,
- Drawable placeHolder, LocalDataAdapter adapter, boolean isInProgress) {
-
- return mLocalData.getView(context, width, height, placeHolder, adapter, true);
+ public View getView(Context context, int width, int height, Drawable placeHolder,
+ LocalDataAdapter adapter, boolean isInProgress) {
+ //TODO do this on a background thread
+ byte[] jpegData = Storage.getJpegForSession(mUri);
+ Bitmap bmp = BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length);
+ ImageView imageView = new ImageView(context);
+ imageView.setImageBitmap(bmp);
+ return imageView;
}
@Override
- public void resizeView(Context context, int w, int h, View v, LocalDataAdapter adapter) {
- // do nothing.
+ public void resizeView(Context context, int width, int height, View view,
+ LocalDataAdapter adapter) {
+
}
@Override
public long getDateTaken() {
- return mLocalData.getDateTaken();
+ return mDateTaken;
}
@Override
public long getDateModified() {
- return mLocalData.getDateModified();
+ return mDateTaken;
}
@Override
public String getTitle() {
- return mLocalData.getTitle();
+ return mUri.toString();
}
+
@Override
public boolean isDataActionSupported(int actions) {
return false;
@Override
public boolean delete(Context c) {
- // No actions are allowed to modify the wrapped data.
return false;
}
@Override
- public boolean rotate90Degrees(
- Context context, LocalDataAdapter adapter,
- int currentDataId, boolean clockwise) {
- // No actions are allowed to modify the wrapped data.
+ public boolean rotate90Degrees(Context context, LocalDataAdapter adapter, int currentDataId, boolean clockwise) {
return false;
}
@Override
public void onFullScreen(boolean fullScreen) {
- mLocalData.onFullScreen(fullScreen);
+
}
@Override
public boolean canSwipeInFullScreen() {
- return mLocalData.canSwipeInFullScreen();
+ return true;
}
@Override
public String getPath() {
- return mLocalData.getPath();
+ return "";
}
@Override
public String getMimeType() {
- return mLocalData.getMimeType();
+ return null;
}
@Override
public MediaDetails getMediaDetails(Context context) {
- return mLocalData.getMediaDetails(context);
+ return null;
}
@Override
public int getLocalDataType() {
- // Force the data type to be in-progress data.
return LOCAL_IN_PROGRESS_DATA;
}
@Override
public long getSizeInBytes() {
- return mLocalData.getSizeInBytes();
+ return 0;
}
@Override
public LocalData refresh(Context context) {
- return mLocalData.refresh(context);
+ return this;
}
@Override
public long getContentId() {
- return mLocalData.getContentId();
+ return 0;
}
@Override
public Bundle getMetadata() {
- return mLocalData.getMetadata();
+ return mMetaData;
}
@Override
public boolean isMetadataUpdated() {
- return mLocalData.isMetadataUpdated();
+ return true;
}
@Override
- public int getWidth() {
- return mLocalData.getWidth();
+ public int getRotation() {
+ return 0;
}
@Override
- public int getHeight() {
- return mLocalData.getHeight();
+ public int getWidth() {
+ return mWidth;
}
@Override
- public int getRotation() {
- return mLocalData.getRotation();
+ public int getHeight() {
+ return mHeight;
}
@Override
public int getViewType() {
- return mLocalData.getViewType();
+ return VIEW_TYPE_REMOVABLE;
}
@Override
public double[] getLatLong() {
- return mLocalData.getLatLong();
+ return null;
}
@Override
@Override
public void prepare() {
- mLocalData.prepare();
+
}
@Override
public void recycle() {
- mLocalData.recycle();
+
}
@Override
public Uri getContentUri() {
- return mLocalData.getContentUri();
+ return mUri;
}
}
package com.android.camera.session;
import android.content.ContentResolver;
+import android.graphics.BitmapFactory;
import android.location.Location;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
+import android.util.Log;
+import com.android.camera.Exif;
import com.android.camera.app.MediaSaver;
import com.android.camera.app.MediaSaver.OnMediaSavedListener;
-import com.android.camera.crop.ImageLoader;
import com.android.camera.data.LocalData;
import com.android.camera.exif.ExifInterface;
+import com.android.camera.exif.ExifTag;
+import com.android.camera.exif.Rational;
+import com.android.camera.util.FileUtil;
+import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
*/
public class CaptureSessionManagerImpl implements CaptureSessionManager {
+ private static final String TAG = "CaptureSessionManagerImpl";
+ public static final String TEMP_SESSIONS = "TEMP_SESSIONS";
+
private class CaptureSessionImpl implements CaptureSession {
/** A URI of the item being processed. */
private Uri mUri;
}
// TODO: This needs to happen outside the UI thread.
- mPlaceholderManager.replacePlaceholder(mPlaceHolderSession, mLocation, orientation,
- exif, data, width, height, LocalData.MIME_TYPE_JPEG);
+ mPlaceholderManager.finishPlaceholder(mPlaceHolderSession, mLocation, orientation, exif,
+ data, width, height, LocalData.MIME_TYPE_JPEG);
mNotificationManager.notifyCompletion(mNotificationId);
removeSession(mUri.toString());
"Cannot call finish without calling startSession first.");
}
- // Set final values in media store, such as mime type and size.
- mPlaceholderManager.replacePlaceHolder(mPlaceHolderSession, mLocation,
- LocalData.MIME_TYPE_JPEG, /* finalImage */ true);
- mNotificationManager.notifyCompletion(mNotificationId);
- removeSession(mUri.toString());
- notifyTaskDone(mPlaceHolderSession.outputUri);
+ final String path = this.getPath();
+
+ AsyncTask.SERIAL_EXECUTOR.execute(new Runnable() {
+ @Override
+ public void run() {
+ byte[] jpegDataTemp;
+ try {
+ jpegDataTemp = FileUtil.readFileToByteArray(new File(path));
+ } catch (IOException e) {
+ return;
+ }
+ final byte[] jpegData = jpegDataTemp;
+
+ final CaptureSession session = CaptureSessionImpl.this;
+
+ if (session == null) {
+ throw new IllegalStateException("No session for captured photo");
+ }
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length, options);
+ int width = options.outWidth;
+ int height = options.outHeight;
+ int rotation = 0;
+ ExifInterface exif = null;
+ try {
+ exif = new ExifInterface();
+ exif.readExif(jpegData);
+ } catch (IOException e) {
+ Log.w(TAG, "Could not read exif", e);
+ exif = null;
+ }
+
+ session.saveAndFinish(jpegData, width, height, rotation, exif, null);
+ }
+ });
+
}
@Override
if (mUri == null) {
throw new IllegalStateException("Cannot retrieve URI of not started session.");
}
- return ImageLoader.getLocalPathFromUri(mContentResolver, mUri);
+
+ File tempDirectory = null;
+ try {
+ tempDirectory = new File(
+ getSessionDirectory(TEMP_SESSIONS), mTitle);
+ } catch (IOException e) {
+ Log.e(TAG, "Could not get temp session directory", e);
+ throw new RuntimeException("Could not get temp session directory", e);
+ }
+ tempDirectory.mkdirs();
+ File tempFile = new File(tempDirectory, mTitle + ".jpg");
+ try {
+ if (!tempFile.exists()) {
+ tempFile.createNewFile();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Could not create temp session file", e);
+ throw new RuntimeException("Could not create temp session file", e);
+ }
+ return tempFile.getPath();
}
@Override
@Override
public void onPreviewChanged() {
- mPlaceholderManager.replacePlaceHolder(mPlaceHolderSession, mLocation,
- PlaceholderManager.PLACEHOLDER_MIME_TYPE, /* finalImage */ false);
- notifySessionUpdate(mPlaceHolderSession.outputUri);
+
+ final Location loc = null; // mLocationManager.getCurrentLocation();
+ final int heading = 0; // mHeading;
+ final String path = this.getPath();
+
+ AsyncTask.SERIAL_EXECUTOR.execute(new Runnable() {
+ @Override
+ public void run() {
+ byte[] jpegDataTemp;
+ try {
+ jpegDataTemp = FileUtil.readFileToByteArray(new File(path));
+ } catch (IOException e) {
+ return;
+ }
+ final byte[] jpegData = jpegDataTemp;
+
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inJustDecodeBounds = true;
+ BitmapFactory.decodeByteArray(jpegData, 0, jpegData.length, options);
+ int width = options.outWidth;
+ int height = options.outHeight;
+
+ mPlaceholderManager.replacePlaceholder(mPlaceHolderSession, jpegData, width, height);
+ notifySessionUpdate(mPlaceHolderSession.outputUri);
+ }
+ });
}
@Override
}
mProgressMessage = reason;
- // Change mime type of session so it's not marked as in progress anymore.
- mPlaceholderManager.replacePlaceHolder(mPlaceHolderSession, mLocation,
- LocalData.MIME_TYPE_JPEG, /* finalImage */false);
mNotificationManager.notifyCompletion(mNotificationId);
removeSession(mUri.toString());
mFailedSessionMessages.put(mPlaceHolderSession.outputUri, reason);
public class PlaceholderManager {
private static final String TAG = "PlaceholderManager";
- public static final String PLACEHOLDER_MIME_TYPE = "application/placeholder-image";
private final Context mContext;
public static class Session {
}
Uri uri =
- Storage.addImage(mContext.getContentResolver(), title, timestamp, null, 0, null,
- placeholder, width, height, PLACEHOLDER_MIME_TYPE);
-
+ Storage.addPlaceholder(placeholder, width, height);
if (uri == null) {
return null;
}
* session.
*/
public Session convertToPlaceholder(Uri uri) {
- Storage.updateItemMimeType(uri, PLACEHOLDER_MIME_TYPE, mContext.getContentResolver());
return createSessionFromUri(uri);
}
- public void replacePlaceholder(Session session, Location location, int orientation,
- ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) {
+ /**
+ * This converts the placeholder in to a real media item
+ *
+ * @param session the session that is being finished.
+ * @param location the location of the image
+ * @param orientation the orientation of the image
+ * @param exif the exif of the image
+ * @param jpeg the bytes of the image
+ * @param width the width of the image
+ * @param height the height of the image
+ * @param mimeType the mime type of the image
+ */
+ public void finishPlaceholder(Session session, Location location, int orientation,
+ ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) {
- Storage.updateImage(session.outputUri, mContext.getContentResolver(), session.outputTitle,
+ Uri resultUri = Storage.updateImage(session.outputUri, mContext.getContentResolver(), session.outputTitle,
session.time, location, orientation, exif, jpeg, width, height, mimeType);
- CameraUtil.broadcastNewPicture(mContext, session.outputUri);
+ CameraUtil.broadcastNewPicture(mContext, resultUri);
}
/**
- * Replace the placeholder with an updated image.
+ * This changes the temporary placeholder jpeg without writing it to the media store
*
- * @param session the session to update.
- * @param loc the location of the new item.
- * @param mimeType the mime-type of the new image.
- * @param finalImage whether this is the final image. If set, this will
- * broadcast that a new picture has been added.
+ * @param session the session to update
+ * @param jpeg the new placeholder bytes
+ * @param width the width of the image
+ * @param height the height of the image
*/
- public void replacePlaceHolder(Session session, Location loc, String mimeType,
- boolean finalImage) {
- Storage.updateImageFromChangedFile(session.outputUri, loc, mContext.getContentResolver(),
- mimeType);
- if (finalImage) {
- CameraUtil.broadcastNewPicture(mContext, session.outputUri);
- }
- }
+ public void replacePlaceholder(Session session,
+ byte[] jpeg, int width, int height) {
- /**
- * Removes the placeholder for the given session.
- */
- public void removePlaceholder(Session session) {
- Storage.deleteImage(mContext.getContentResolver(), session.outputUri);
+ Storage.replacePlaceholder(session.outputUri,
+ jpeg, width, height);
+ CameraUtil.broadcastNewPicture(mContext, session.outputUri);
}
/**
package com.android.camera.util;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
/**
* Common file operations.
}
return directory.delete();
}
+
+ /**
+ * Reads the content of a {@code File} as a byte array.
+ *
+ * @param file The file to read
+ * @return The content of the file
+ * @throws java.io.IOException if the content of the {@code File} could not be read
+ */
+ public static byte[] readFileToByteArray(File file) throws IOException {
+ int length = (int) file.length();
+ byte[] data = new byte[length];
+ FileInputStream stream = new FileInputStream(file);
+ try {
+ int offset = 0;
+ while (offset < length) {
+ offset += stream.read(data, offset, length - offset);
+ }
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ stream.close();
+ }
+ return data;
+ }
+
}
if (currItem == null) {
return false;
}
- if (!mDataAdapter.canSwipeInFullScreen(currItem.getId())) {
+ if (inFullScreen() && !mDataAdapter.canSwipeInFullScreen(currItem.getId())) {
return false;
}
hideZoomView();