resolved conflicts for merge of f3d505af to master

Change-Id: Ic7e9fdcb874b9c41e332c7e2c1bf896fd52b0b11
diff --git a/res/raw/backdropper.graph b/res/raw/backdropper.graph
index 6a3f641..3a48fc4 100644
--- a/res/raw/backdropper.graph
+++ b/res/raw/backdropper.graph
@@ -29,6 +29,7 @@
 @external recordingWidth;
 @external recordingHeight;
 @external recordingProfile;
+@external recordingDoneListener;
 @external audioSource;
 
 @external previewSurface;
@@ -74,6 +75,7 @@
 @filter MediaEncoderFilter recorder {
   audioSource = $audioSource;
   recordingProfile = $recordingProfile;
+  recordingDoneListener = $recordingDoneListener;
   recording = false;
   // outputFile, orientationHint, inputRegion, listeners
   // will be set when recording starts
diff --git a/res/raw/goofy_face.graph b/res/raw/goofy_face.graph
index fe2c5d9..7145033 100644
--- a/res/raw/goofy_face.graph
+++ b/res/raw/goofy_face.graph
@@ -31,6 +31,7 @@
 @external recordingWidth;
 @external recordingHeight;
 @external recordingProfile;
+@external recordingDoneListener;
 @external audioSource;
 
 @external previewSurface;
@@ -98,6 +99,7 @@
 @filter MediaEncoderFilter recorder {
   audioSource = $audioSource;
   recordingProfile = $recordingProfile;
+  recordingDoneListener = $recordingDoneListener;
   recording = false;
   // outputFile, orientationHint, inputRegion, listeners
   // will be set when recording starts
diff --git a/src/com/android/camera/EffectsRecorder.java b/src/com/android/camera/EffectsRecorder.java
index 3059281..5e8bfc1 100644
--- a/src/com/android/camera/EffectsRecorder.java
+++ b/src/com/android/camera/EffectsRecorder.java
@@ -25,9 +25,10 @@
 import android.filterfw.core.GraphRunner.OnRunnerDoneListener;
 import android.filterfw.geometry.Point;
 import android.filterfw.geometry.Quad;
-import android.filterpacks.videosrc.SurfaceTextureSource.SurfaceTextureSourceListener;
 import android.filterpacks.videoproc.BackDropperFilter;
 import android.filterpacks.videoproc.BackDropperFilter.LearningDoneListener;
+import android.filterpacks.videosink.MediaEncoderFilter.OnRecordingDoneListener;
+import android.filterpacks.videosrc.SurfaceTextureSource.SurfaceTextureSourceListener;
 
 import android.graphics.SurfaceTexture;
 import android.hardware.Camera;
@@ -71,6 +72,7 @@
     public static final int  EFFECT_MSG_DONE_LEARNING    = 1;
     public static final int  EFFECT_MSG_SWITCHING_EFFECT = 2;
     public static final int  EFFECT_MSG_EFFECTS_STOPPED  = 3;
+    public static final int  EFFECT_MSG_RECORDING_DONE   = 4;
 
     private Context mContext;
     private Handler mHandler;
@@ -370,7 +372,8 @@
                 "recordingHeight", mProfile.videoFrameHeight,
                 "recordingProfile", mProfile,
                 "audioSource", MediaRecorder.AudioSource.CAMCORDER,
-                "learningDoneListener", mLearningDoneListener);
+                "learningDoneListener", mLearningDoneListener,
+                "recordingDoneListener", mRecordingDoneListener);
 
         mRunner = null;
         mGraphId = -1;
@@ -542,6 +545,16 @@
         }
     };
 
+    // A callback to finalize the media after the recording is done.
+    private OnRecordingDoneListener mRecordingDoneListener =
+            new OnRecordingDoneListener() {
+        // Forward the callback to the VideoCamera object (as an asynchronous event).
+        public void onRecordingDone() {
+            if (mLogVerbose) Log.v(TAG, "Recording done callback triggered");
+            sendMessage(EFFECT_NONE, EFFECT_MSG_RECORDING_DONE);
+        }
+    };
+
     public synchronized void startRecording() {
         if (mLogVerbose) Log.v(TAG, "Starting recording (" + this + ")");
 
@@ -755,4 +768,5 @@
             });
         }
     }
+
 }
diff --git a/src/com/android/camera/VideoCamera.java b/src/com/android/camera/VideoCamera.java
index b02d83c..1249ce9 100755
--- a/src/com/android/camera/VideoCamera.java
+++ b/src/com/android/camera/VideoCamera.java
@@ -1633,20 +1633,24 @@
     private void stopVideoRecording() {
         Log.v(TAG, "stopVideoRecording");
         if (mMediaRecorderRecording) {
-            boolean shouldAddToMediaStore = false;
+            boolean shouldAddToMediaStoreNow = false;
 
             try {
                 if (effectsActive()) {
+                    // This is asynchronous, so we cant add to media store now because thumbnail
+                    // may not be ready. In such case addVideoToMediaStore is called later
+                    // through a callback from the MediaEncoderFilter to EffectsRecorder,
+                    // and then to the VideoCamera.
                     mEffectsRecorder.stopRecording();
                 } else {
                     mMediaRecorder.setOnErrorListener(null);
                     mMediaRecorder.setOnInfoListener(null);
                     mMediaRecorder.stop();
+                    shouldAddToMediaStoreNow = true;
                 }
                 mCurrentVideoFilename = mVideoFilename;
                 Log.v(TAG, "Setting current video filename: "
                         + mCurrentVideoFilename);
-                shouldAddToMediaStore = true;
             } catch (RuntimeException e) {
                 Log.e(TAG, "stop fail",  e);
                 if (mVideoFilename != null) deleteVideoFile(mVideoFilename);
@@ -1658,7 +1662,7 @@
                 enableCameraControls(true);
             }
             keepScreenOnAwhile();
-            if (shouldAddToMediaStore) {
+            if (shouldAddToMediaStoreNow) {
                 addVideoToMediaStore();
             }
         }
@@ -1923,6 +1927,9 @@
             // and restart regular preview.
             mBgLearningMessageFrame.setVisibility(View.GONE);
             checkQualityAndStartPreview();
+        } else if (effectMsg == EffectsRecorder.EFFECT_MSG_RECORDING_DONE) {
+            addVideoToMediaStore();
+            getThumbnail();
         } else if (effectId == EffectsRecorder.EFFECT_BACKDROPPER) {
             switch (effectMsg) {
                 case EffectsRecorder.EFFECT_MSG_STARTED_LEARNING: