Merge "Gallery2: Fix CANCEL and DONE in ExportDialog disappeared"
diff --git a/gallerycommon/src/com/android/gallery3d/common/OverScroller.java b/gallerycommon/src/com/android/gallery3d/common/OverScroller.java
index a03c451..6becb3a 100644
--- a/gallerycommon/src/com/android/gallery3d/common/OverScroller.java
+++ b/gallerycommon/src/com/android/gallery3d/common/OverScroller.java
@@ -855,7 +855,7 @@
             float distance = mVelocity * mVelocity / (2.0f * Math.abs(mDeceleration));
             final float sign = Math.signum(mVelocity);
 
-            if (distance > mOver) {
+            if (Math.abs(distance) > mOver) {
                 // Default deceleration is not sufficient to slow us down before boundary
                  mDeceleration = - sign * mVelocity * mVelocity / (2.0f * mOver);
                  distance = mOver;
diff --git a/res/layout/filtershow_editor_crop_landscape.xml b/res/layout/filtershow_editor_crop_landscape.xml
new file mode 100644
index 0000000..414a024
--- /dev/null
+++ b/res/layout/filtershow_editor_crop_landscape.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+  Redistribution and use in source and binary forms, with or without
+  modification, are permitted provided that the following conditions are
+  met:
+      * Redistributions of source code must retain the above copyright
+        notice, this list of conditions and the following disclaimer.
+      * Redistributions in binary form must reproduce the above
+        copyright notice, this list of conditions and the following
+        disclaimer in the documentation and/or other materials provided
+        with the distribution.
+      * Neither the name of The Linux Foundation nor the names of its
+        contributors may be used to endorse or promote products derived
+        from this software without specific prior written permission.
+
+  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+  IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/crop_panel_height_lanscape">
+
+    <FrameLayout
+        android:id="@+id/bottom_panel"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/crop_panel_height_lanscape"
+        android:background="@color/edit_actionbar_background"
+        android:layout_gravity="center_vertical">
+
+        <ImageButton
+            android:id="@+id/cancel"
+            android:layout_width="@dimen/category_actionbar_panel_height"
+            android:layout_height="@dimen/category_actionbar_panel_height"
+            android:background="@color/edit_actionbar_background"
+            android:layout_gravity="left|center_vertical"
+            android:src="@drawable/cancel" />
+
+
+        <ImageButton
+            android:id="@+id/done"
+            android:layout_width="@dimen/category_actionbar_panel_height"
+            android:layout_height="@dimen/category_actionbar_panel_height"
+            android:background="@color/edit_actionbar_background"
+            android:layout_gravity="right|center_vertical"
+            android:src="@drawable/done" />
+    </FrameLayout>
+
+    <LinearLayout
+        android:layout_width="360dp"
+        android:layout_height="@dimen/crop_panel_height_lanscape"
+        android:background="@android:color/transparent"
+        android:layout_gravity="center"
+        android:clickable="true"
+        android:orientation="horizontal">
+
+        <LinearLayout
+            android:id="@+id/leftPanel"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_gravity="center_vertical"
+            android:background="@android:color/transparent"
+            android:orientation="vertical" >
+
+            <ImageButton
+                android:id="@+id/leftButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/crop_icon_size_landscape"
+                android:scaleType="centerInside"
+                android:background="@android:color/transparent" />
+
+            <TextView
+                android:id="@+id/leftText"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:clickable="true"
+                android:background="@android:color/transparent"
+                android:layout_marginTop="@dimen/crop_text_margin_padding"
+                android:textColor="#ffffff"
+                android:textSize="12sp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/centerPanel"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:clickable="true"
+            android:layout_gravity="center_vertical"
+            android:background="@android:color/transparent"
+            android:orientation="vertical">
+
+            <ImageButton
+                android:id="@+id/centerButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/crop_icon_size_landscape"
+                android:scaleType="centerInside"
+                android:background="@android:color/transparent" />
+
+            <TextView
+                android:id="@+id/centerText"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:clickable="true"
+                android:background="@android:color/transparent"
+                android:layout_marginTop="@dimen/crop_text_margin_padding"
+                android:textColor="#ffffff"
+                android:textSize="12sp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/rightPanel"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:clickable="true"
+            android:layout_gravity="center_vertical"
+            android:background="@android:color/transparent"
+            android:orientation="vertical">
+
+            <ImageButton
+                android:id="@+id/rightButton"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/crop_icon_size_landscape"
+                android:scaleType="centerInside"
+                android:background="@android:color/transparent" />
+
+            <TextView
+                android:id="@+id/rightText"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:clickable="true"
+                android:background="@android:color/transparent"
+                android:layout_marginTop="@dimen/crop_text_margin_padding"
+                android:textColor="#ffffff"
+                android:textSize="12sp" />
+        </LinearLayout>
+    </LinearLayout>
+
+
+</FrameLayout>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index aa7da66..e021d35 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -188,6 +188,8 @@
     <dimen name="slot_width_album">116dp</dimen>
     <dimen name="slot_height_album">116dp</dimen>
     <dimen name="crop_icon_size">30dp</dimen>
+    <dimen name="crop_icon_size_landscape">24dp</dimen>
+    <dimen name="crop_panel_height_lanscape">60dp</dimen>
     <dimen name="crop_icon_margin_padding">20dp</dimen>
     <dimen name="crop_text_margin_padding">6dp</dimen>
     <dimen name="crop_rect_stroke">2dp</dimen>
diff --git a/src/com/android/gallery3d/app/PhotoDataAdapter.java b/src/com/android/gallery3d/app/PhotoDataAdapter.java
index 05bd376..c6ad14d 100755
--- a/src/com/android/gallery3d/app/PhotoDataAdapter.java
+++ b/src/com/android/gallery3d/app/PhotoDataAdapter.java
@@ -162,6 +162,7 @@
     private int mCameraIndex;
     private boolean mIsPanorama;
     private boolean mIsStaticCamera;
+    private boolean mIsFromTimelineScreen;
     private boolean mIsActive;
     private boolean mNeedFullImage;
     private int mFocusHintDirection = FOCUS_HINT_NEXT;
@@ -187,7 +188,7 @@
     // preview. If cameraIndex < 0, there is no camera preview.
     public PhotoDataAdapter(AbstractGalleryActivity activity, PhotoView view,
             MediaSet mediaSet, Path itemPath, int indexHint, int cameraIndex,
-            boolean isPanorama, boolean isStaticCamera) {
+            boolean isPanorama, boolean isStaticCamera, boolean isFromTimelineScreen) {
         mActivity = activity;
         mSource = Utils.checkNotNull(mediaSet);
         mPhotoView = Utils.checkNotNull(view);
@@ -196,6 +197,7 @@
         mCameraIndex = cameraIndex;
         mIsPanorama = isPanorama;
         mIsStaticCamera = isStaticCamera;
+        mIsFromTimelineScreen = isFromTimelineScreen;
         mThreadPool = activity.getThreadPool();
         mNeedFullImage = true;
 
@@ -1307,6 +1309,9 @@
                 }
                 mDirty = false;
                 version = mSource.reload();
+                if (mIsFromTimelineScreen) {
+                    mSource.setClusterKind(GalleryActivity.CLUSTER_ALBUMSET_NO_TITLE);
+                }
                 //if data is not ready, continue to reload
                 if (version == MediaObject.INVALID_DATA_VERSION) {
                     continue;
diff --git a/src/com/android/gallery3d/app/PhotoPage.java b/src/com/android/gallery3d/app/PhotoPage.java
old mode 100644
new mode 100755
index df3229f..0c82944
--- a/src/com/android/gallery3d/app/PhotoPage.java
+++ b/src/com/android/gallery3d/app/PhotoPage.java
@@ -507,7 +507,8 @@
                     mActivity, mPhotoView, mMediaSet, itemPath, mCurrentIndex,
                     mAppBridge == null ? -1 : 0,
                     mAppBridge == null ? false : mAppBridge.isPanorama(),
-                    mAppBridge == null ? false : mAppBridge.isStaticCamera());
+                    mAppBridge == null ? false : mAppBridge.isStaticCamera(),
+                    mIsFromTimelineScreen);
             mModel = pda;
             mPhotoView.setModel(mModel);
 
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index f0af615..cfce7c5 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -92,7 +92,6 @@
 import com.android.gallery3d.filtershow.category.SwipableView;
 import com.android.gallery3d.filtershow.category.TrueScannerPanel;
 import com.android.gallery3d.filtershow.data.UserPresetsManager;
-import com.android.gallery3d.filtershow.editors.BasicEditor;
 import com.android.gallery3d.filtershow.editors.Editor;
 import com.android.gallery3d.filtershow.editors.EditorCrop;
 import com.android.gallery3d.filtershow.editors.EditorDualCamFusion;
@@ -214,7 +213,9 @@
     private ImageButton imgComparison;
     private String mPopUpText, mCancel;
     RelativeLayout rlImageContainer;
+    private int mEditrCropButtonSelect = 0;
     private boolean isComingFromEditorScreen;
+    private boolean mIsReloadByConfigurationChanged;
     private AlertDialog.Builder mBackAlertDialogBuilder;
 
     private ProgressDialog mLoadingDialog;
@@ -376,19 +377,7 @@
         }
         final int currentId = currentEditor.getID();
         if (currentId == EditorCrop.ID) {
-            new Runnable() {
-                @Override
-                public void run() {
-                    EditorCropPanel panel = new EditorCropPanel();
-                    FragmentTransaction transaction =
-                            getSupportFragmentManager().beginTransaction();
-                    transaction.remove(getSupportFragmentManager().findFragmentByTag(
-                            MainPanel.FRAGMENT_TAG));
-                    transaction.replace(R.id.main_panel_container, panel,
-                            MainPanel.FRAGMENT_TAG);
-                    transaction.commit();
-                }
-            }.run();
+            loadEditorCropPanel();
             return;
         }
         if (useStraightenPanel(currentId)) {
@@ -464,6 +453,22 @@
         return (EditorID == EditorStraighten.ID || EditorID == HazeBusterEditor.ID || EditorID == SeeStraightEditor.ID);
     }
 
+    private void loadEditorCropPanel() {
+        new Runnable() {
+            @Override
+            public void run() {
+                EditorCropPanel panel = new EditorCropPanel();
+                FragmentTransaction transaction =
+                        getSupportFragmentManager().beginTransaction();
+                transaction.remove(getSupportFragmentManager().findFragmentByTag(
+                        MainPanel.FRAGMENT_TAG));
+                transaction.replace(R.id.main_panel_container, panel,
+                        MainPanel.FRAGMENT_TAG);
+                transaction.commit();
+            }
+        }.run();
+    }
+
     public void leaveSeekBarPanel() {
         removeSeekBarPanel();
         showDefaultImageView();
@@ -1151,6 +1156,16 @@
                 Bitmap originalHires = ImageLoader.loadOrientedConstrainedBitmap(master.getUri(),
                         master.getActivity(), highresPreviewSize,
                         master.getOrientation(), bounds);
+
+                // Force the bitmap to even width and height which is required by beautification algo
+                Bitmap tempBmp = MasterImage.convertToEvenNumberWidthImage(originalHires);
+                if(tempBmp != null && originalHires != null) {
+                    if(!originalHires.isRecycled() && originalHires != tempBmp) {
+                        originalHires.recycle();
+                    }
+                    originalHires = tempBmp;
+                }
+
                 master.setOriginalBounds(bounds);
                 master.setOriginalBitmapHighres(originalHires);
                 Log.d(LOGTAG, "FilterShowActivity.LoadHighresBitmapTask.doInBackground(): originalHires.WH is (" + originalHires.getWidth()
@@ -1729,6 +1744,10 @@
         super.onConfigurationChanged(newConfig);
 
         setDefaultValues();
+        if (isShowEditCropPanel()) {
+            mIsReloadByConfigurationChanged = true;
+            loadEditorCropPanel();
+        }
         if (mMasterImage == null) {
             return;
         }
@@ -1769,6 +1788,9 @@
     }
 
     void resetHistory() {
+        if (mMasterImage == null) {
+            return;
+        }
         HistoryManager adapter = mMasterImage.getHistory();
         adapter.reset();
         HistoryItem historyItem = adapter.getItem(0);
@@ -1806,6 +1828,7 @@
         if (currentPanel instanceof MainPanel) {
             return;
         }
+        mIsReloadByConfigurationChanged = false;
         loadMainPanel();
         showDefaultImageView();
         showComparisonButton();
@@ -2018,4 +2041,29 @@
     public void setScaleImage(boolean isScaled) {
         mImageShow.scaleImage(isScaled, getBaseContext());
     }
+
+    public void saveEditorCropState(int select) {
+        mEditrCropButtonSelect = select;
+    }
+
+    public boolean isReloadByConfigurationChanged() {
+        return mIsReloadByConfigurationChanged;
+    }
+
+    public boolean isShowEditCropPanel() {
+        if (mCurrentEditor == null) {
+            return false;
+        }
+        Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(
+                MainPanel.FRAGMENT_TAG);
+        if (currentPanel instanceof MainPanel) {
+            return false;
+        }
+        return mCurrentEditor.getID() == EditorCrop.ID;
+    }
+
+    public int getEditorCropButtonSelect() {
+        return mEditrCropButtonSelect;
+    }
+
 }
diff --git a/src/com/android/gallery3d/filtershow/category/BasicGeometryPanel.java b/src/com/android/gallery3d/filtershow/category/BasicGeometryPanel.java
index 52d16a5..466ecd8 100644
--- a/src/com/android/gallery3d/filtershow/category/BasicGeometryPanel.java
+++ b/src/com/android/gallery3d/filtershow/category/BasicGeometryPanel.java
@@ -30,6 +30,7 @@
 package com.android.gallery3d.filtershow.category;
 
 
+import android.content.res.Configuration;
 import android.os.Bundle;
 import android.support.v4.app.Fragment;
 import android.view.LayoutInflater;
@@ -38,6 +39,7 @@
 import android.widget.ImageButton;
 import android.widget.TextView;
 
+import com.android.gallery3d.filtershow.FilterShowActivity;
 import org.codeaurora.gallery.R;
 
 public class BasicGeometryPanel extends Fragment {
@@ -54,8 +56,15 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
-        mMainView = inflater.inflate(R.layout.filtershow_category_geometry_panel, container, false);
-        mEditorName = (TextView) mMainView.findViewById(R.id.editor_name);
+        FilterShowActivity activity = (FilterShowActivity) getActivity();
+        if (isLandscape() && activity.isShowEditCropPanel()) {
+            mMainView = inflater.inflate(R.layout.filtershow_editor_crop_landscape,
+                    container, false);
+        } else {
+            mMainView = inflater.inflate(R.layout.filtershow_category_geometry_panel,
+                    container, false);
+            mEditorName = (TextView) mMainView.findViewById(R.id.editor_name);
+        }
 
         initButtons();
         initTexts();
@@ -91,4 +100,10 @@
                 mMainView.findViewById(R.id.rightPanel)
         };
     }
+
+    protected boolean isLandscape() {
+        Configuration mConfiguration = this.getResources().getConfiguration();
+        return mConfiguration.orientation == Configuration.ORIENTATION_LANDSCAPE ?
+                true : false;
+    }
 }
diff --git a/src/com/android/gallery3d/filtershow/category/EditorCropPanel.java b/src/com/android/gallery3d/filtershow/category/EditorCropPanel.java
index 3e6124c..db7dfd0 100644
--- a/src/com/android/gallery3d/filtershow/category/EditorCropPanel.java
+++ b/src/com/android/gallery3d/filtershow/category/EditorCropPanel.java
@@ -30,6 +30,7 @@
 package com.android.gallery3d.filtershow.category;
 
 import android.app.Activity;
+import android.content.res.Configuration;
 import android.graphics.Color;
 import android.os.Bundle;
 import android.support.annotation.Nullable;
@@ -76,13 +77,19 @@
     public void onAttach(Activity activity) {
         super.onAttach(activity);
         FilterShowActivity filterShowActivity = (FilterShowActivity) activity;
+        if (filterShowActivity.isReloadByConfigurationChanged()) {
+            mSelectPosition = filterShowActivity.getEditorCropButtonSelect();
+        }
         mEditorCrop = (EditorCrop) filterShowActivity.getEditor(EditorCrop.ID);
     }
 
     @Override
     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
-        mEditorName.setText(R.string.crop);
+        if (!isLandscape()) {
+            mEditorName.setText(R.string.crop);
+            mBottomPanel.setVisibility(View.VISIBLE);
+        }
         mMainView.setBackgroundColor(getContext().getResources().getColor(
                 R.color.edit_actionbar_background));
 
@@ -166,4 +173,11 @@
         }
         super.onDetach();
     }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        FilterShowActivity activity = (FilterShowActivity) getActivity();
+        activity.saveEditorCropState(mSelectPosition);
+    }
 }
diff --git a/src/com/android/gallery3d/filtershow/crop/CropDrawingUtils.java b/src/com/android/gallery3d/filtershow/crop/CropDrawingUtils.java
index b3f1af7..5937c78 100644
--- a/src/com/android/gallery3d/filtershow/crop/CropDrawingUtils.java
+++ b/src/com/android/gallery3d/filtershow/crop/CropDrawingUtils.java
@@ -75,7 +75,8 @@
         float x = 0;
         float y = 0;
         for (int i = 0; i < 2; i++) {
-            y = i * rectHeight + bounds.top + strokeWidth / 2;
+            y = i * rectHeight + bounds.top;
+
             canvas.drawLine(bounds.left - strokeWidth / 2, y, cornerLength + bounds.left, y, p);
             canvas.drawLine(bounds.right - cornerLength, y, bounds.right + strokeWidth / 2, y, p);
         }
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
index 294fbb7..4921c7c 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageCrop.java
@@ -28,13 +28,14 @@
 import android.util.Log;
 import android.view.MotionEvent;
 
-import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
 import com.android.gallery3d.filtershow.crop.CropDrawingUtils;
 import com.android.gallery3d.filtershow.crop.CropMath;
 import com.android.gallery3d.filtershow.crop.CropObject;
 import com.android.gallery3d.filtershow.editors.EditorCrop;
 import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
 import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder;
+import org.codeaurora.gallery.R;
 
 public class ImageCrop extends ImageShow {
     private static final String TAG = ImageCrop.class.getSimpleName();
@@ -232,9 +233,11 @@
     private void forceStateConsistency() {
         MasterImage master = MasterImage.getImage();
         Bitmap image = master.getFiltersOnlyImage();
+        FilterShowActivity filterShowActivity = (FilterShowActivity) getContext();
+        boolean isReload = filterShowActivity.isReloadByConfigurationChanged();
         int width = image.getWidth();
         int height = image.getHeight();
-        if (mCropObj == null || !mUpdateHolder.equals(mGeometry)
+        if (mCropObj == null || (!mUpdateHolder.equals(mGeometry) && !isReload)
                 || mImageBounds.width() != width || mImageBounds.height() != height
                 || !mLocalRep.getCrop().equals(mUpdateHolder.crop)) {
             mImageBounds.set(0, 0, width, height);
@@ -251,7 +254,12 @@
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
         super.onSizeChanged(w, h, oldw, oldh);
-        clearDisplay();
+        FilterShowActivity filterShowActivity = (FilterShowActivity) getContext();
+        if (filterShowActivity.isShowEditCropPanel()) {
+            updateMatrix(w, h);
+        } else {
+            clearDisplay();
+        }
     }
 
     @Override
@@ -270,8 +278,13 @@
         if (mDisplayCropMatrix == null || mDisplayMatrix == null || mDisplayMatrixInverse == null) {
             mCropObj.unsetAspectRatio();
             Resources res = getContext().getResources();
-            int panelHeight = res.getDimensionPixelOffset(R.dimen.category_panel_height) +
-                    res.getDimensionPixelOffset(R.dimen.category_actionbar_panel_height);
+            int panelHeight = 0;
+            if (canvas.getWidth() < canvas.getHeight()) {
+                panelHeight = res.getDimensionPixelOffset(R.dimen.category_panel_height) +
+                        res.getDimensionPixelOffset(R.dimen.category_actionbar_panel_height);
+            } else {
+                panelHeight = res.getDimensionPixelOffset(R.dimen.crop_panel_height_lanscape);
+            }
             mDisplayMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry,
                     bitmap.getWidth(), bitmap.getHeight(), canvas.getWidth(),
                     canvas.getHeight() - panelHeight);
@@ -331,4 +344,32 @@
     public void setEditor(EditorCrop editorCrop) {
         mEditorCrop = editorCrop;
     }
+
+    private void updateMatrix(int w, int h) {
+        Bitmap bitmap = MasterImage.getImage().getFiltersOnlyImage();
+        if (bitmap == null) {
+            MasterImage.getImage().invalidateFiltersOnly();
+        }
+        if (!mValidDraw || bitmap == null) {
+            return;
+        }
+        Resources res = getContext().getResources();
+        int panelHeight = 0;
+        if (w < h) {
+            panelHeight = res.getDimensionPixelOffset(R.dimen.category_panel_height) +
+                    res.getDimensionPixelOffset(R.dimen.category_actionbar_panel_height);
+        } else {
+            panelHeight = res.getDimensionPixelOffset(R.dimen.crop_panel_height_lanscape);
+        }
+        mDisplayMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry,
+                bitmap.getWidth(), bitmap.getHeight(), w, h - panelHeight);
+        mDisplayCropMatrix = GeometryMathUtils.getFullGeometryToScreenMatrix(mGeometry,
+                bitmap.getWidth(), bitmap.getHeight(), w, h - panelHeight);
+        mDisplayMatrixInverse = new Matrix();
+        mDisplayMatrixInverse.reset();
+        if (!mDisplayCropMatrix.invert(mDisplayMatrixInverse)) {
+            Log.w(TAG, "could not invert display matrix");
+            mDisplayMatrixInverse = null;
+        }
+    }
 }
diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index b2aae85..fa82989 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
@@ -272,6 +272,24 @@
         }
     };
 
+    public static Bitmap convertToEvenNumberWidthImage(Bitmap bmp) {
+        Bitmap retBmp = null;
+        if (bmp != null) {
+            int w = bmp.getWidth();
+            int h = bmp.getHeight();
+            boolean bWidthIsEven = (w & 0x01) == 0;
+            boolean bHeightIsEven = (h & 0x01) == 0;
+            Log.v(LOGTAG, "ori bitmap w="+w+" h="+h);
+            if( !bWidthIsEven || !bHeightIsEven){
+                w = w - (w & 0x01);
+                h = h - (h & 0x01);
+                retBmp = Bitmap.createBitmap(bmp, 0, 0, w, h);
+                Log.v(LOGTAG, "new bitmap w="+retBmp.getWidth()+" h="+retBmp.getHeight());
+            }
+        }
+        return retBmp;
+    }
+
     public boolean loadBitmap(Uri uri, int size) {
         setUri(uri);
         mEXIF = ImageLoader.getExif(getActivity(), uri);
@@ -280,6 +298,14 @@
         mOriginalBitmapLarge = ImageLoader.loadOrientedConstrainedBitmap(uri, mActivity,
                 Math.min(MAX_BITMAP_DIM, size),
                 mOrientation, originalBounds);
+        // Force bitmap width and height to even number for beautification algo.
+        Bitmap tempBmp = convertToEvenNumberWidthImage(mOriginalBitmapLarge);
+        if(tempBmp != null && mOriginalBitmapLarge != null) {
+            if(!mOriginalBitmapLarge.isRecycled() && mOriginalBitmapLarge != tempBmp) {
+                mOriginalBitmapLarge.recycle();
+            }
+            mOriginalBitmapLarge = tempBmp;
+        }
         setOriginalBounds(originalBounds);
         if (mOriginalBitmapLarge == null) {
             return false;
diff --git a/src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java b/src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java
index a5c7fb0..99eb33e 100644
--- a/src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java
+++ b/src/com/thundersoft/hz/selfportrait/detect/FaceDetect.java
@@ -24,7 +24,7 @@
 public class FaceDetect {
     private static final String TAG = "FaceDetect";
 
-    private int mHandle = 0;
+    private long mHandle = 0;
 
     static {
         try {
@@ -71,9 +71,9 @@
         return res;
     }
 
-    private static native int native_create();
-    private static native void native_destroy(int handle);
-    private static native int native_detect(int handle, Bitmap bmp);
-    private static native int native_face_info(int handle, int index, Rect face, Rect eye1,
+    private static native long native_create();
+    private static native void native_destroy(long handle);
+    private static native int native_detect(long handle, Bitmap bmp);
+    private static native int native_face_info(long handle, int index, Rect face, Rect eye1,
             Rect eye2, Rect mouth);
 }