Merge "Overlay java files Issue 3370836" into honeycomb
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
old mode 100755
new mode 100644
index f10f5e8..1244b8e
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -24,15 +24,16 @@
 import java.util.Iterator;
 import java.util.List;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
 import android.media.videoeditor.VideoEditor.ExportProgressListener;
 import android.media.videoeditor.VideoEditor.PreviewProgressListener;
 import android.media.videoeditor.VideoEditor.MediaProcessingProgressListener;
 import android.util.Log;
 import android.util.Pair;
 import android.view.Surface;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
 
 /**
  *This class provide Native methods to be used by MediaArtist {@hide}
@@ -70,11 +71,17 @@
     private boolean mExportDone = false;
 
     private int mProgressToApp;
+
     /**
      *  The resize paint
      */
     private static final Paint sResizePaint = new Paint(Paint.FILTER_BITMAP_FLAG);
 
+    private String mRenderPreviewOverlayFile;
+    private int   mRenderPreviewRenderingMode;
+
+    private boolean mIsFirstProgress;
+
     public static final int TASK_LOADING_SETTINGS = 1;
 
     public static final int TASK_ENCODING = 2;
@@ -1899,12 +1906,35 @@
     }
 
     @SuppressWarnings("unused")
-    private void onPreviewProgressUpdate(int progress, boolean isFinished) {
+    private void onPreviewProgressUpdate(int progress, boolean isFinished,
+                  boolean updateOverlay, String filename, int renderingMode) {
         if (mPreviewProgressListener != null) {
-            mPreviewProgressListener.onProgress(mVideoEditor, progress, isFinished);
+            if (mIsFirstProgress) {
+                mPreviewProgressListener.onStart(mVideoEditor);
+                mIsFirstProgress = false;
+            }
+
+            final VideoEditor.OverlayData overlayData;
+            if (updateOverlay) {
+                overlayData = new VideoEditor.OverlayData();
+                if (filename != null) {
+                    overlayData.set(BitmapFactory.decodeFile(filename), renderingMode);
+                } else {
+                    overlayData.setClear();
+                }
+            } else {
+                overlayData = null;
+            }
+
+            mPreviewProgressListener.onProgress(mVideoEditor, progress, overlayData);
+
             if (progress != 0) {
                 mPreviewProgress = progress;
             }
+
+            if (isFinished) {
+                mPreviewProgressListener.onStop(mVideoEditor);
+            }
         }
     }
 
@@ -2894,6 +2924,7 @@
                     maxHeight = populateMediaItemProperties(lMediaItem,
                                                             previewIndex,
                                                             maxHeight);
+                    /* Get the clip properties of the media item. */
                     if (lMediaItem instanceof MediaImageItem)
                     {
                         int tmpCnt = 0;
@@ -3014,11 +3045,11 @@
      * @param callbackAfterFrameCount INdicated after how many frames
      * the callback is needed
      * @param listener The PreviewProgressListener
-     *
      */
     public void doPreview(Surface surface, long fromMs, long toMs, boolean loop,
             int callbackAfterFrameCount, PreviewProgressListener listener) {
         mPreviewProgress = fromMs;
+        mIsFirstProgress = true;
         mPreviewProgressListener = listener;
 
         if (!mInvalidatePreviewArray) {
@@ -3042,9 +3073,6 @@
                 Log.e("MediaArtistNativeHelper", "Runtime exception in nativeStartPreview");
                 throw ex;
             }
-
-        } else {
-            return;
         }
     }
 
@@ -3064,22 +3092,37 @@
      * @param time The time in ms at which the frame has to be rendered
      * @param surfaceWidth The surface width
      * @param surfaceHeight The surface height
+     * @param overlayData The overlay data
      *
      * @return The actual time from the story board at which the  frame was extracted
      * and rendered
      */
     public long renderPreviewFrame(Surface surface, long time, int surfaceWidth,
-                                   int surfaceHeight) {
+            int surfaceHeight, VideoEditor.OverlayData overlayData) {
         long timeMs = 0;
         if (!mInvalidatePreviewArray) {
             try {
-                for (int clipCnt = 0; clipCnt < mPreviewEditSettings.clipSettingsArray.length; clipCnt++) {
+                for (int clipCnt = 0;
+                      clipCnt < mPreviewEditSettings.clipSettingsArray.length;
+                      clipCnt++) {
+
                     if (mPreviewEditSettings.clipSettingsArray[clipCnt].fileType == FileType.JPG) {
-                        mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath = mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath;
+                        mPreviewEditSettings.clipSettingsArray[clipCnt].clipPath =
+                            mPreviewEditSettings.clipSettingsArray[clipCnt].clipDecodedPath;
                     }
                 }
+
+                // Reset the render preview frame params that shall be set by native.
+                mRenderPreviewOverlayFile = null;
+                mRenderPreviewRenderingMode = MediaRendering.RESIZING;
                 nativePopulateSettings(mPreviewEditSettings, mClipProperties, mAudioSettings);
                 timeMs = (long)nativeRenderPreviewFrame(surface, time, surfaceWidth, surfaceHeight);
+
+                if (mRenderPreviewOverlayFile != null) {
+                    overlayData.set(BitmapFactory.decodeFile(mRenderPreviewOverlayFile), mRenderPreviewRenderingMode);
+                } else {
+                    overlayData.setClear();
+                }
             } catch (IllegalArgumentException ex) {
                 Log.e("MediaArtistNativeHelper",
                 "Illegal Argument exception in nativeRenderPreviewFrame");
@@ -3094,11 +3137,16 @@
             }
             return timeMs;
         } else {
-
             throw new RuntimeException("Call generate preview first");
         }
     }
 
+    private void previewFrameEditInfo(String filename, int renderingMode) {
+        mRenderPreviewOverlayFile = filename;
+        mRenderPreviewRenderingMode = renderingMode;
+    }
+
+
     /**
      * This function is responsible for rendering a single frame
      * from a single media item on the surface
@@ -3551,7 +3599,6 @@
         int outBitrate = 0;
         mExportFilename = filePath;
         previewStoryBoard(mediaItemsList, mediaTransitionList, mediaBGMList,null);
-
         mExportProgressListener = listener;
 
         mProgressToApp = 0;
@@ -3678,7 +3725,6 @@
         int outBitrate = 0;
         mExportFilename = filePath;
         previewStoryBoard(mediaItemsList, mediaTransitionList, mediaBGMList,null);
-
         mExportProgressListener = listener;
 
         mProgressToApp = 0;
@@ -4003,6 +4049,7 @@
     public void clearPreviewSurface(Surface surface) {
        nativeClearSurface(surface);
     }
+
     /**     Native Methods        */
     native Properties getMediaProperties(String file) throws IllegalArgumentException,
     IllegalStateException, RuntimeException, Exception;
diff --git a/media/java/android/media/videoeditor/Transition.java b/media/java/android/media/videoeditor/Transition.java
index feec284..4d1bafb 100755
--- a/media/java/android/media/videoeditor/Transition.java
+++ b/media/java/android/media/videoeditor/Transition.java
@@ -332,8 +332,6 @@
         List<EffectSettings> effectSettings_clip2;
 
         String output = null;
-        String effectClip1 = null;
-        String effectClip2 = null;
 
         if (mNativeHelper == null) {
             if (m1 != null)
diff --git a/media/java/android/media/videoeditor/VideoEditor.java b/media/java/android/media/videoeditor/VideoEditor.java
index f1ad921..9006613 100755
--- a/media/java/android/media/videoeditor/VideoEditor.java
+++ b/media/java/android/media/videoeditor/VideoEditor.java
@@ -20,7 +20,10 @@
 import java.io.IOException;
 import java.util.List;
 import java.util.concurrent.CancellationException;
-
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Canvas;
+import android.graphics.Rect;
 import android.view.SurfaceHolder;
 
 /**
@@ -78,9 +81,26 @@
          * @param videoEditor The VideoEditor instance
          * @param timeMs The current preview position (expressed in milliseconds
          *        since the beginning of the storyboard timeline).
-         * @param end true if the end of the timeline was reached
+         * @param overlayData The overlay data (null if the overlay data
+         *      is unchanged)
          */
-        public void onProgress(VideoEditor videoEditor, long timeMs, boolean end);
+        public void onProgress(VideoEditor videoEditor, long timeMs,
+                               OverlayData overlayData);
+        /**
+         * This method notifies the listener when the preview is started
+         * previewing a project.
+         *
+         * @param videoEditor The VideoEditor instance
+         */
+        public void onStart(VideoEditor videoEditor);
+
+        /**
+         * This method notifies the listener when the preview is stopped
+         * previewing a project.
+         *
+         * @param videoEditor The VideoEditor instance
+         */
+        public void onStop(VideoEditor videoEditor);
     }
 
     /**
@@ -126,6 +146,158 @@
     }
 
     /**
+     * The overlay data
+     */
+    public static final class OverlayData {
+        // Instance variables
+        private Bitmap mOverlayBitmap;
+        private int mRenderingMode;
+        private boolean mClear;
+
+        /**
+         * Default constructor
+         */
+        public OverlayData() {
+            mOverlayBitmap = null;
+            mRenderingMode = MediaArtistNativeHelper.MediaRendering.BLACK_BORDERS;
+            mClear = false;
+        }
+
+        /**
+         * Releases the bitmap
+         */
+        public void release() {
+            if (mOverlayBitmap != null) {
+                mOverlayBitmap.recycle();
+                mOverlayBitmap = null;
+            }
+        }
+
+        /**
+         * Check if the overlay needs to be rendered
+         *
+         * @return true if rendering is needed
+         */
+        public boolean needsRendering() {
+            return (mClear || mOverlayBitmap != null);
+        }
+
+        /**
+         * Store the overlay data
+         *
+         * @param overlayBitmap The overlay bitmap
+         * @param renderingMode The rendering mode
+         */
+        void set(Bitmap overlayBitmap, int renderingMode) {
+            mOverlayBitmap = overlayBitmap;
+            mRenderingMode = renderingMode;
+            mClear = false;
+        }
+
+        /**
+         * Clear the overlay
+         */
+        void setClear() {
+            mClear = true;
+        }
+
+        /**
+        * Render the overlay by either clearing it or by
+        * rendering the overlay bitmap with the specified
+        * rendering mode
+        *
+        * @param destBitmap The destination bitmap
+        */
+        public void renderOverlay(Bitmap destBitmap) {
+            if (mClear) {
+                destBitmap.eraseColor(Color.TRANSPARENT);
+            } else if (mOverlayBitmap != null) {
+                final Canvas overlayCanvas = new Canvas(destBitmap);
+                final Rect destRect;
+                final Rect srcRect;
+                switch (mRenderingMode) {
+                    case MediaArtistNativeHelper.MediaRendering.RESIZING: {
+                        destRect = new Rect(0, 0, overlayCanvas.getWidth(),
+                                                 overlayCanvas.getHeight());
+                        srcRect = new Rect(0, 0, mOverlayBitmap.getWidth(),
+                                                 mOverlayBitmap.getHeight());
+                        break;
+                    }
+
+                    case MediaArtistNativeHelper.MediaRendering.BLACK_BORDERS: {
+                        int left, right, top, bottom;
+                        float aROverlayImage, aRCanvas;
+                        aROverlayImage = (float)(mOverlayBitmap.getWidth()) /
+                                         (float)(mOverlayBitmap.getHeight());
+
+                        aRCanvas = (float)(overlayCanvas.getWidth()) /
+                                         (float)(overlayCanvas.getHeight());
+
+                        if (aROverlayImage > aRCanvas) {
+                            int newHeight = ((overlayCanvas.getWidth() * mOverlayBitmap.getHeight())
+                                             / mOverlayBitmap.getWidth());
+                            left = 0;
+                            top  = (overlayCanvas.getHeight() - newHeight) / 2;
+                            right = overlayCanvas.getWidth();
+                            bottom = top + newHeight;
+                        } else {
+                            int newWidth = ((overlayCanvas.getHeight() * mOverlayBitmap.getWidth())
+                                                / mOverlayBitmap.getHeight());
+                            left = (overlayCanvas.getWidth() - newWidth) / 2;
+                            top  = 0;
+                            right = left + newWidth;
+                            bottom = overlayCanvas.getHeight();
+                        }
+
+                        destRect = new Rect(left, top, right, bottom);
+                        srcRect = new Rect(0, 0, mOverlayBitmap.getWidth(), mOverlayBitmap.getHeight());
+                        break;
+                    }
+
+                    case MediaArtistNativeHelper.MediaRendering.CROPPING: {
+                        // Calculate the source rect
+                        int left, right, top, bottom;
+                        float aROverlayImage, aRCanvas;
+                        aROverlayImage = (float)(mOverlayBitmap.getWidth()) /
+                                         (float)(mOverlayBitmap.getHeight());
+                        aRCanvas = (float)(overlayCanvas.getWidth()) /
+                                        (float)(overlayCanvas.getHeight());
+                        if (aROverlayImage < aRCanvas) {
+                            int newHeight = ((mOverlayBitmap.getWidth() * overlayCanvas.getHeight())
+                                       / overlayCanvas.getWidth());
+
+                            left = 0;
+                            top  = (mOverlayBitmap.getHeight() - newHeight) / 2;
+                            right = mOverlayBitmap.getWidth();
+                            bottom = top + newHeight;
+                        } else {
+                            int newWidth = ((mOverlayBitmap.getHeight() * overlayCanvas.getWidth())
+                                        / overlayCanvas.getHeight());
+                            left = (mOverlayBitmap.getWidth() - newWidth) / 2;
+                            top  = 0;
+                            right = left + newWidth;
+                            bottom = mOverlayBitmap.getHeight();
+                        }
+
+                        srcRect = new Rect(left, top, right, bottom);
+                        destRect = new Rect(0, 0, overlayCanvas.getWidth(), overlayCanvas.getHeight());
+                        break;
+                    }
+
+                    default: {
+                        throw new IllegalStateException("Rendering mode: " + mRenderingMode);
+                    }
+                }
+
+                destBitmap.eraseColor(Color.TRANSPARENT);
+                overlayCanvas.drawBitmap(mOverlayBitmap, srcRect, destRect, null);
+
+                mOverlayBitmap.recycle();
+            }
+        }
+    }
+
+    /**
      * @return The path where the VideoEditor stores all files related to the
      *         project
      */
@@ -518,6 +690,7 @@
      *
      * @param surfaceHolder SurfaceHolder used by the application
      * @param timeMs time corresponding to the frame to display
+     * @param overlayData The overlay data
      *
      * @return The accurate time stamp of the frame that is rendered.
      *
@@ -526,7 +699,8 @@
      * @throws IllegalArgumentException if time is negative or beyond the
      *        preview duration
      */
-    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs);
+    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs,
+            OverlayData overlayData);
 
     /**
      * This method must be called after any changes made to the storyboard
@@ -535,7 +709,6 @@
      */
     public void generatePreview(MediaProcessingProgressListener listener);
 
-
     /**
      * Start the preview of all the storyboard items applied on all MediaItems
      * This method does not block (does not wait for the preview to complete).
@@ -580,5 +753,4 @@
      * and needs to be cleared.
      */
     public void clearSurface(SurfaceHolder surfaceHolder);
-
 }
diff --git a/media/java/android/media/videoeditor/VideoEditorImpl.java b/media/java/android/media/videoeditor/VideoEditorImpl.java
index 672ce19..d2dfe82bf 100755
--- a/media/java/android/media/videoeditor/VideoEditorImpl.java
+++ b/media/java/android/media/videoeditor/VideoEditorImpl.java
@@ -899,7 +899,8 @@
     /*
      * {@inheritDoc}
      */
-    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs) {
+    public long renderPreviewFrame(SurfaceHolder surfaceHolder, long timeMs,
+                                    OverlayData overlayData) {
         long result = 0;
         int surfaceWidth = 0;
         int surfaceHeight = 0;
@@ -939,7 +940,7 @@
             if (!mMANativeHelper.mInvalidatePreviewArray) {
                 if (mMediaItems.size() > 0) {
                     result = mMANativeHelper.renderPreviewFrame(surface,
-                                             timeMs,surfaceWidth,surfaceHeight);
+                                             timeMs,surfaceWidth,surfaceHeight, overlayData);
                 }
                 else {
                     result = 0;
@@ -1643,7 +1644,7 @@
                     mMANativeHelper.previewStoryBoard(mMediaItems, mTransitions,
                                                       mAudioTracks, null);
                     mMANativeHelper.doPreview(mSurface, fromMs, toMs, loop,
-                                             callbackAfterFrameCount, listener);
+                                     callbackAfterFrameCount, listener);
                     mPreviewInProgress = true;
                 } catch (IllegalArgumentException ex) {
                     mPreviewSemaphore.release();
@@ -1683,7 +1684,7 @@
         }
     }
 
-    /**
+    /*
      * Remove transitions associated with the specified media item
      *
      * @param mediaItem The media item