diff options
6 files changed, 167 insertions, 17 deletions
diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index 90495471d..1a0d33d9d 100644 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -71,6 +71,7 @@ import com.android.camera.remote.RemoteCameraModule; import com.android.camera.session.CaptureSession; import com.android.camera.settings.Keys; import com.android.camera.settings.SettingsManager; +import com.android.camera.stats.CaptureStats; import com.android.camera.stats.UsageStatistics; import com.android.camera.stats.profiler.Profile; import com.android.camera.stats.profiler.Profiler; @@ -555,7 +556,9 @@ public class CaptureModule extends CameraModule implements String title = CameraUtil.instance().createJpegName(sessionTime); CaptureSession session = getServices().getCaptureSessionManager() .createNewSession(title, sessionTime, location); - session.startEmpty(new Size((int) mPreviewArea.width(), (int) mPreviewArea.height())); + + session.startEmpty(new CaptureStats(mHdrPlusEnabled), + new Size((int) mPreviewArea.width(), (int) mPreviewArea.height())); return session; } diff --git a/src/com/android/camera/captureintent/CaptureIntentSession.java b/src/com/android/camera/captureintent/CaptureIntentSession.java index bd78dceb3..6fb22c620 100644 --- a/src/com/android/camera/captureintent/CaptureIntentSession.java +++ b/src/com/android/camera/captureintent/CaptureIntentSession.java @@ -33,6 +33,8 @@ import com.google.common.base.Optional; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; +import javax.annotation.Nonnull; + /** * An implementation of {@link CaptureSession} which is used by * {@link CaptureIntentModule}. @@ -118,22 +120,25 @@ public class CaptureIntentSession implements CaptureSession { } @Override - public synchronized void startEmpty(Size pictureSize) { + public synchronized void startEmpty(ImageLifecycleListener listener, @Nonnull Size pictureSize) { isStarted = true; } @Override - public synchronized void startSession(Bitmap placeholder, int progressMessageId) { + public synchronized void startSession(ImageLifecycleListener listener, @Nonnull Bitmap placeholder, + int progressMessageId) { throw new RuntimeException("Not supported."); } @Override - public synchronized void startSession(byte[] placeholder, int progressMessageId) { + public synchronized void startSession(ImageLifecycleListener listener, @Nonnull byte[] placeholder, + int progressMessageId) { throw new RuntimeException("Not supported."); } @Override - public synchronized void startSession(Uri uri, int progressMessageId) { + public synchronized void startSession(ImageLifecycleListener listener, @Nonnull Uri uri, + @Nonnull int progressMessageId) { throw new RuntimeException("Not supported."); } diff --git a/src/com/android/camera/captureintent/resource/ResourceCaptureToolsImpl.java b/src/com/android/camera/captureintent/resource/ResourceCaptureToolsImpl.java index 35ddc702b..adce211de 100644 --- a/src/com/android/camera/captureintent/resource/ResourceCaptureToolsImpl.java +++ b/src/com/android/camera/captureintent/resource/ResourceCaptureToolsImpl.java @@ -171,7 +171,7 @@ public final class ResourceCaptureToolsImpl implements ResourceCaptureTools { resource.getLocationManager().getCurrentLocation(); final CaptureSession session = mCaptureSessionManager.createNewSession(fileName, timestamp, location); - session.startEmpty(openedCamera.getPictureSize()); + session.startEmpty(null, openedCamera.getPictureSize()); /** Logging */ final SettingsManager settingsManager = resource.getSettingsManager(); diff --git a/src/com/android/camera/session/CaptureSession.java b/src/com/android/camera/session/CaptureSession.java index 7b2808904..0dff1a1b3 100644 --- a/src/com/android/camera/session/CaptureSession.java +++ b/src/com/android/camera/session/CaptureSession.java @@ -23,9 +23,13 @@ import android.net.Uri; import com.android.camera.exif.ExifInterface; import com.android.camera.stats.CaptureSessionStatsCollector; import com.android.camera.util.Size; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Optional; import com.google.common.util.concurrent.ListenableFuture; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * A session is an item that is in progress of being created and saved, such as * a photo sphere or HDR+ photo. @@ -58,6 +62,45 @@ public interface CaptureSession { public void onStatusMessageChanged(int messageId); } + /** + * Classes implementing this interface can listen to progress updates of + * this session. + */ + public static interface ImageLifecycleListener { + /** + * Occurs when, for a particular image type, an image capture has + * started. This method is always executed, and will always be called + * first. + */ + public void onCaptureStarted(); + + /** + * Occurs when the tiny thumbnail bytes are received. + */ + public void onTinyThumb(); + + /** + * Occurs when the medium thumbnail bytes are received. + */ + public void onMediumThumb(); + + /** + * Occurs when rendering/processing/encoding starts for the full size image. + */ + public void onProcessingStarted(); + + /** + * Occurs when the rendering/processing/encoding for the full size image + * is completed. + */ + public void onProcessingComplete(); + + /** + * This occurs after all the bytes are physically on disk. + */ + public void onCapturePersisted(); + } + /** Returns the title/name of this session. */ public String getTitle(); @@ -109,42 +152,50 @@ public interface CaptureSession { /** * Starts an empty session with the given placeholder size. * - * @param mPictureSize the size, in pixels of the empty placeholder. + * @param listener receives events as the session progresses. + * @param pictureSize the size, in pixels of the empty placeholder. */ - public void startEmpty(Size mPictureSize); + public void startEmpty(@Nullable ImageLifecycleListener listener, @Nonnull Size pictureSize); /** * Starts the session by adding a placeholder to the filmstrip and adding * notifications. * + * @param listener receives events as the session progresses. * @param placeholder a valid encoded bitmap to be used as the placeholder. * @param progressMessageId the message to be used to the progress * notification initially. This can later be changed using * {@link #setProgressMessage(int)}. */ - public void startSession(byte[] placeholder, int progressMessageId); + public void startSession(@Nullable ImageLifecycleListener listener, @Nonnull byte[] placeholder, + int progressMessageId); /** * Starts the session by adding a placeholder to the filmstrip and adding * notifications. * + * @param listener receives events as the session progresses. * @param placeholder a valid bitmap to be used as the placeholder. * @param progressMessageId the message to be used to the progress * notification initially. This can later be changed using * {@link #setProgressMessage(int)}. */ - public void startSession(Bitmap placeholder, int progressMessageId); + @VisibleForTesting + public void startSession(@Nullable ImageLifecycleListener listener, @Nonnull Bitmap placeholder, + int progressMessageId); /** * Starts the session by marking the item as in-progress and adding * notifications. * + * @param listener receives events as the session progresses. * @param uri the URI of the item to be re-processed. * @param progressMessageId the message to be used to the progress * notification initially. This can later be changed using * {@link #setProgressMessage(int)}. */ - public void startSession(Uri uri, int progressMessageId); + public void startSession(@Nullable ImageLifecycleListener listener, @Nonnull Uri uri, + int progressMessageId); /** * Cancel the session without a final result. The session will be removed diff --git a/src/com/android/camera/session/CaptureSessionImpl.java b/src/com/android/camera/session/CaptureSessionImpl.java index 0cb5257c9..042c24bed 100644 --- a/src/com/android/camera/session/CaptureSessionImpl.java +++ b/src/com/android/camera/session/CaptureSessionImpl.java @@ -37,6 +37,9 @@ import java.io.File; import java.io.IOException; import java.util.HashSet; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + /** * The default implementation of the CaptureSession interface. This is the * implementation we use for normal Camera use. @@ -80,6 +83,10 @@ public class CaptureSessionImpl implements CaptureSession { /** Object that collects logging information through the capture session lifecycle */ private final CaptureSessionStatsCollector mCaptureSessionStatsCollector = new CaptureSessionStatsCollector(); + @Nullable + private ImageLifecycleListener mImageLifecycleListener; + private boolean mHasPreviouslySetProgress = false; + /** * Creates a new {@link CaptureSession}. * @@ -140,6 +147,10 @@ public class CaptureSessionImpl implements CaptureSession { @Override public synchronized void setProgress(int percent) { + if (!mHasPreviouslySetProgress && percent == 0 && mImageLifecycleListener != null) { + mImageLifecycleListener.onProcessingStarted(); + } + mProgressPercent = percent; mSessionNotifier.notifyTaskProgress(mUri, mProgressPercent); for (ProgressListener listener : mProgressListeners) { @@ -163,21 +174,34 @@ public class CaptureSessionImpl implements CaptureSession { @Override public void updateThumbnail(Bitmap bitmap) { + if (mImageLifecycleListener != null) { + mImageLifecycleListener.onMediumThumb(); + } mPlaceholderManager.replacePlaceholder(mPlaceHolder, bitmap); mSessionNotifier.notifySessionUpdated(mUri); } @Override public void updateCaptureIndicatorThumbnail(Bitmap indicator, int rotationDegrees) { + if (mImageLifecycleListener != null) { + mImageLifecycleListener.onTinyThumb(); + } onCaptureIndicatorUpdate(indicator, rotationDegrees); + } @Override - public synchronized void startEmpty(Size pictureSize) { + public synchronized void startEmpty(@Nullable ImageLifecycleListener listener, + @Nonnull Size pictureSize) { if (mIsFinished) { return; } + if (listener != null) { + mImageLifecycleListener = listener; + mImageLifecycleListener.onCaptureStarted(); + } + mProgressMessageId = -1; mPlaceHolder = mPlaceholderManager.insertEmptyPlaceholder(mTitle, pictureSize, mSessionStartMillis); @@ -187,11 +211,17 @@ public class CaptureSessionImpl implements CaptureSession { } @Override - public synchronized void startSession(Bitmap placeholder, int progressMessageId) { + public synchronized void startSession(@Nullable ImageLifecycleListener listener, + @Nonnull Bitmap placeholder, int progressMessageId) { if (mIsFinished) { return; } + if (listener != null) { + mImageLifecycleListener = listener; + mImageLifecycleListener.onCaptureStarted(); + } + mProgressMessageId = progressMessageId; mPlaceHolder = mPlaceholderManager.insertPlaceholder(mTitle, placeholder, mSessionStartMillis); @@ -202,11 +232,17 @@ public class CaptureSessionImpl implements CaptureSession { } @Override - public synchronized void startSession(byte[] placeholder, int progressMessageId) { + public synchronized void startSession(@Nullable ImageLifecycleListener listener, + @Nonnull byte[] placeholder, int progressMessageId) { if (mIsFinished) { return; } + if (listener != null) { + mImageLifecycleListener = listener; + mImageLifecycleListener.onCaptureStarted(); + } + mProgressMessageId = progressMessageId; mPlaceHolder = mPlaceholderManager.insertPlaceholder(mTitle, placeholder, mSessionStartMillis); @@ -221,7 +257,13 @@ public class CaptureSessionImpl implements CaptureSession { } @Override - public synchronized void startSession(Uri uri, int progressMessageId) { + public synchronized void startSession(@Nullable ImageLifecycleListener listener, + @Nonnull Uri uri, int progressMessageId) { + if (listener != null) { + mImageLifecycleListener = listener; + mImageLifecycleListener.onCaptureStarted(); + } + mUri = uri; mProgressMessageId = progressMessageId; mPlaceHolder = mPlaceholderManager.convertToPlaceholder(uri); @@ -244,18 +286,27 @@ public class CaptureSessionImpl implements CaptureSession { } @Override - public synchronized ListenableFuture<Optional<Uri>> saveAndFinish(byte[] data, int width, int height, - int orientation, ExifInterface exif) { + public synchronized ListenableFuture<Optional<Uri>> saveAndFinish(byte[] data, int width, + int height, int orientation, ExifInterface exif) { final SettableFuture<Optional<Uri>> futureResult = SettableFuture.create(); + if (mImageLifecycleListener != null) { + mImageLifecycleListener.onProcessingComplete(); + } + mIsFinished = true; if (mPlaceHolder == null) { + mMediaSaver.addImage( data, mTitle, mSessionStartMillis, mLocation, width, height, orientation, exif, new MediaSaver.OnMediaSavedListener() { @Override public void onMediaSaved(Uri uri) { futureResult.set(Optional.fromNullable(uri)); + + if (mImageLifecycleListener != null) { + mImageLifecycleListener.onCapturePersisted(); + } } }); } else { @@ -264,6 +315,10 @@ public class CaptureSessionImpl implements CaptureSession { orientation, exif, data, width, height, FilmstripItemData.MIME_TYPE_JPEG); mSessionNotifier.notifyTaskDone(mUri); futureResult.set(Optional.fromNullable(mUri)); + + if (mImageLifecycleListener != null) { + mImageLifecycleListener.onCapturePersisted(); + } } catch (IOException e) { Log.e(TAG, "Could not write file", e); finishWithFailure(-1, true); diff --git a/src_pd/com/android/camera/stats/CaptureStats.java b/src_pd/com/android/camera/stats/CaptureStats.java new file mode 100644 index 000000000..72ff1824d --- /dev/null +++ b/src_pd/com/android/camera/stats/CaptureStats.java @@ -0,0 +1,36 @@ +package com.android.camera.stats; + +import com.android.camera.session.CaptureSession.ImageLifecycleListener; + +/** + * Simple statistics of internal app behavior during capture. + */ +public class CaptureStats implements ImageLifecycleListener { + + public CaptureStats(boolean isHdrPlus) { + } + + @Override + public void onCaptureStarted() { + } + + @Override + public void onTinyThumb() { + } + + @Override + public void onMediumThumb() { + } + + @Override + public void onProcessingStarted() { + } + + @Override + public void onProcessingComplete() { + } + + @Override + public void onCapturePersisted() { + } +} |